Skip to content
Image input · verified

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)

qwen3.8-27b40% off
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 →