Send an Image to the Claude API (base64, URL, Files)
The image content block in Python and curl, the format and size limits from the docs, and a screenshot-to-CSV extraction that doesn't invent numbers.
On this page4 sections
Images ride in the same messages array as text — an image content block with one of three source types: base64, url, or a file_id from the Files API.
1. Python: a local file as base64
import base64, anthropic
client = anthropic.Anthropic()
with open("invoice.png", "rb") as f:
data = base64.standard_b64encode(f.read()).decode()
msg = client.messages.create(
model="claude-opus-5",
max_tokens=2048,
messages=[{"role": "user", "content": [
{"type": "image", "source": {
"type": "base64", "media_type": "image/png", "data": data}},
{"type": "text", "text": "Describe this image."},
]}],
)
print(next(b.text for b in msg.content if b.type == "text"))
media_type has to match the actual bytes — image/jpeg, image/png, image/gif, or image/webp. Note the ordering: the docs recommend putting the image before the text.
2. curl: an image by URL
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": [
{"type": "image", "source": {"type": "url",
"url": "https://example.com/chart.png"}},
{"type": "text", "text": "What is the trend in this chart?"}
]}]
}'
Anthropic’s servers fetch the URL, so nothing gets base64-encoded into your request. For an image you’ll reuse across turns, upload it once via the Files API and send {"type": "file", "file_id": "..."} instead — base64 re-sends the whole image on every turn of a conversation.
3. Limits worth knowing
- Formats: JPEG, PNG, GIF, WebP. Animations aren’t supported — only the first frame is read.
- Per image: 10 MB base64 on the Claude API (5 MB on Bedrock and Google Cloud), max 8000×8000 px.
- Per request: 32 MB total. Up to 600 images per API request, or 100 for models with a 200k-token context window.
- Above 20 image blocks in one request, a stricter per-image dimension limit kicks in for every image in it. Keep each under 2000 px on both sides, or keep the request to 20 blocks.
- Token cost is
⌈width / 28⌉ × ⌈height / 28⌉visual tokens. Oversized images are downscaled first — to a 2576 px long edge (max 4784 visual tokens) on Claude 4.7 and later, 1568 px (max 1568 tokens) on earlier models.
4. Use case: table out of a screenshot
{"type": "text", "text":
"Return this table as CSV, header row first. Copy values exactly. "
"Leave a cell empty if you cannot read it — never guess a number."}
The “leave it empty” clause is the important half: without it a blurry digit becomes a confident wrong digit. Re-add the extracted totals yourself and compare them to the totals in the image — that one check catches most OCR-style errors. Claude also won’t identify people in images, and reads no EXIF or other metadata.
Next: send a PDF to the Claude API · your first Claude API request.