§15.13

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.

published 06 Sept 2026 checked against docs 06 Sept 2026 4 min in Building with the API Markdown

On this page4 sections
  1. 1. Python: a local file as base64
  2. 2. curl: an image by URL
  3. 3. Limits worth knowing
  4. 4. Use case: table out of a screenshot

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.

← All Building with the API plates · Search all guides

↑↓ move↵ openalt+↵ copy first command

Keyboard

⌘/ctrl+K or /
Search all guides
alt+↵
In search: copy the guide's first command
j / k
Move through a list of guides
c
On a guide: copy its first command
t
Toggle light / dark
?
This list