Claude API Image Input: Vision Support Explained
Does the Claude API support image input?
Yes. Claude's vision-capable models accept images alongside text in the same message, and you can send them as base64-encoded data or as a URL reference depending on which models and which gateway you're using. This lets you build apps that read screenshots, analyze charts, extract text from scanned documents, describe photos, or compare multiple images in a single request — all through the same /messages-style endpoint you already use for text.
Vision support in Claude is not a separate API. You add an image content block to the same content array you'd use for text, and the model treats the image as part of the conversation context. There's no separate "vision endpoint," no special billing tier beyond normal token usage, and no fine-tuning step required. This article covers the practical details: supported formats, size limits, how to structure multi-image requests, and common gotchas.
Supported image formats and limits
Claude's vision models currently support:
- JPEG (
image/jpeg) - PNG (
image/png) - GIF (
image/gif, non-animated frame only) - WebP (
image/webp)
Practical limits to keep in mind:
- Each image is capped at roughly 5MB after base64 encoding in most implementations — resize large screenshots or photos before sending them.
- You can include multiple images in a single message (commonly up to 20 in one request, though this varies by provider configuration).
- Very high-resolution images get downscaled internally before the model processes them, so sending a 4K screenshot doesn't improve accuracy over a reasonably sized one — it just costs more tokens.
- Images consume tokens based on their pixel dimensions, roughly proportional to width × height, so cropping to the relevant region before sending is a real cost optimization, not just a nicety.
Sending an image with curl (base64)
The most common pattern is base64-encoding the image and embedding it directly in the request body:
IMAGE_B64=$(base64 -w 0 chart.png)
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"claude-sonnet-4\",
\"max_tokens\": 500,
\"messages\": [
{
\"role\": \"user\",
\"content\": [
{
\"type\": \"image\",
\"source\": {
\"type\": \"base64\",
\"media_type\": \"image/png\",
\"data\": \"$IMAGE_B64\"
}
},
{
\"type\": \"text\",
\"text\": \"What trend does this chart show, and what's the peak value?\"
}
]
}
]
}"
Note the order: image blocks typically go before the text block that references them, though Claude handles either order reasonably well. The key structural point is that content is an array mixing block types, not a single string.
Sending an image in JavaScript
const fs = require("fs");
const imageBase64 = fs.readFileSync("screenshot.jpg", { encoding: "base64" });
const response = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "claude-sonnet-4",
max_tokens: 400,
messages: [
{
role: "user",
content: [
{
type: "image",
source: {
type: "base64",
media_type: "image/jpeg",
data: imageBase64,
},
},
{ type: "text", text: "Extract all visible text from this screenshot as plain text." },
],
},
],
}),
});
const data = await response.json();
console.log(data.content[0].text);
This same pattern works for OCR, UI bug triage from screenshots, receipt parsing, or diagram explanation — the prompt text is what changes, not the request shape.
Comparing multiple images in one request
Vision gets more interesting when you send several images and ask Claude to reason across them:
content: [
{ type: "image", source: { type: "base64", media_type: "image/png", data: beforeImg } },
{ type: "image", source: { type: "base64", media_type: "image/png", data: afterImg } },
{ type: "text", text: "Compare these two UI screenshots and list every visual difference." }
]
This works well for before/after design reviews, diffing two versions of a dashboard, or checking whether a generated chart matches a spec. Keep image count reasonable — stacking a dozen large images into one message inflates both latency and token cost fast.
Combining vision with tool use
Image input composes naturally with Claude's tool use. A common pattern: Claude reads a photo of a whiteboard or invoice, extracts structured data, then calls a function to save it. If you're building that kind of pipeline, pair this with Claude's tool calling support so the model can both interpret the image and act on what it extracts — for example emitting a JSON object matching a schema, then triggering a webhook or database write in your app logic.
Why gate image input behind an API gateway
If you're shipping vision features to end users rather than just prototyping locally, routing image requests through a gateway like SubToAPI gives you a few practical advantages over calling the model directly:
- Per-key usage tracking — see exactly which application or team member is burning tokens on large image uploads, since images can be token-expensive.
- Consistent streaming — if you stream the model's description of an image back to a frontend, the streaming API behaves the same way whether the input was text or image, so your client code doesn't branch.
- Simple key rotation — if an
sub_live_...key leaks (easy to do when embedding keys in client-heavy image upload flows), you can rotate it from the dashboard without touching your provider credentials.
Check the quickstart for the minimal setup, and the Messages API reference for the full content block schema. Plans start with a free trial at signup; see pricing for Solo, Team, and Scale tiers if you're moving past prototyping into production image workloads.
Common mistakes to avoid
- Sending unresized originals. A 12MB phone photo wastes tokens and may exceed size limits — resize to under ~1568px on the longest edge before encoding.
- Wrong
media_type. This must match the actual file format, not just the extension — a renamed.pngthat's actually a JPEG will fail or produce garbage output. - Forgetting the text prompt. An image block with no accompanying instruction leaves Claude guessing what you want it to do with the image.
- Animated GIFs. Only the first frame is processed; convert animations to a static frame or video-adjacent workflow if motion matters.
Questions
Can Claude read text inside an image, like a screenshot or scanned document? Yes — this is one of the most common vision use cases. Claude performs reasonably accurate OCR-style text extraction directly from image input, no separate OCR service needed.
Does sending an image cost more than a text-only request? Images consume tokens based on resolution, so a large or high-res image can cost noticeably more than a short text prompt. Resizing images before upload is the main lever for controlling this.
Can I send an image by URL instead of base64? Support for URL-based image sources varies by provider and gateway configuration — base64 encoding is the most universally supported method and is recommended if you want predictable, portable requests.