Sending images to Qwen 3.8 27B
Image input on qwen3.8-27b works the way the OpenAI SDK already expects: a content array with a text part and an image_url part. Two details decide whether your first attempt works — the image must be inlined as a base64 data URI, and the token budget must leave room for the model to think before it answers.
The rules that actually matter
- Format
- content array: {"type":"text"} + {"type":"image_url"}
- Image source
- base64 data URI only — remote http(s) links are not fetched
- If the model has no vision
- The request is refused up front with vision_not_available, and you are not billed
- Token budget
- Keep max_completion_tokens generous (400+) — reasoning is spent from the same budget
- Request size
- Up to 10 MB per request body, base64 included
- Billing
- Image tokens are input tokens, at the normal input rate
Pricing (40% off list)
- Input
$0.45$0.27- Output
$3.20$1.92
@cf/qwen/qwen3.8-27b
Images bill as input tokens at the normal rate — there is no separate image fee. Live pricing on the models page.
What we verified
Our probe, 2026-08-18: two different solid-colour images, asked for the dominant colour, both answered correctly. We report what we tested, not what the model page claims.
2 / 2
probe images identified correctly
3 of 7
models in our catalog that actually read images
base64 only
accepted image transport
not measured
small print, scanned documents, dense charts
Working example
Read the file, base64 it, put it in the content array. This is the whole integration.
import base64
from openai import OpenAI
client = OpenAI(
base_url="https://api.clfaigateway.dev/v1",
api_key="sk-gw-...", # app.clfaigateway.dev
)
with open("screenshot.png", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
resp = client.chat.completions.create(
model="qwen3.8-27b",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "What does this screen show?"},
# Must be a data: URI. Remote http(s) links are not fetched.
{"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{b64}"}},
],
}],
# Leave room: the model thinks before it answers, and a tiny budget
# can be spent entirely on reasoning, returning empty content.
max_completion_tokens=400,
)
print(resp.choices[0].message.content)Image input — common questions
Almost always the token budget. This model reasons before it answers, and reasoning is spent from max_completion_tokens — set it too low and the entire budget goes into thinking, leaving the content field empty. It looks exactly like a model that cannot see. Raise max_completion_tokens to 400 or more and the answer appears. This cost us an hour, so it is the first thing to check.
No — a remote http(s) link is not fetched, and we refuse it up front with a clear error instead of letting it fail deeper in the stack. Download the bytes yourself and inline them as a base64 data URI. That also keeps your images out of a third-party fetch path.
Error reference →You get a 400 with vision_not_available naming the model, before the request goes upstream, and it costs you nothing. We check this deliberately: some models accept image payloads without complaining and then answer from the text alone, which bills you for a confident guess. We would rather refuse.
Which models read images →No. Images are part of the request content, and we log request metadata only — tokens, latency, cost — never prompt or response content. Inference runs on Cloudflare infrastructure; nothing is retained on our side for training or review.
Data policy →