Claude OCR API: Extract Text from Images with Anthropic Messages
← All posts
TutorialSep 14, 2026· 9 min read

Claude OCR API: Extract Text from Images with Anthropic Messages

If you searched for a Claude OCR API, you are shopping for a programmatic image-to-text path: send a screenshot or scan, get text (or fields) back in code. Anthropic does not sell a separate OCR product. You use the Messages API with vision: attach an image content block, prompt for extraction, and parse the model reply. That works well for low volume and tasks that need judgment. For bulk Markdown or typed JSON, a dedicated OCR endpoint such as OCRskill is usually simpler to operate.

For the capability FAQ (does Claude have OCR at all?), see Does Claude have OCR?. This post is the API how-to: request shape, runnable examples, limits, and a hybrid pattern with OCRskill.

What “Claude OCR API” means in practice

There is no POST /ocr on api.anthropic.com. Image-to-text is multimodal chat:

  1. POST https://api.anthropic.com/v1/messages
  2. Include an image block (base64, url, or Files API file_id)
  3. Add a text instruction such as “extract all visible text as Markdown”
  4. Read the assistant content text (or structured output if you constrain it with tools or a strict prompt)

Supported image media types are JPEG, PNG, GIF, and WebP. Prefer image-then-text in the content array when you can; Anthropic’s vision guide notes that layout tends to work best that way.

So “can Claude extract text from an image?” Yes, through vision on the Messages API. “Is there an Anthropic OCR API SKU?” No. You pay normal multimodal token rates for whatever vision-capable Claude model you choose.

Minimal curl: image to text

Encode a local PNG, then ask for Markdown only. Replace the model id with a current vision-capable Claude model from Anthropic’s models overview (examples below use claude-sonnet-5).

export ANTHROPIC_API_KEY="your-key"
IMAGE_B64=$(base64 -w0 screenshot.png)

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-sonnet-5\",
    \"max_tokens\": 2048,
    \"messages\": [{
      \"role\": \"user\",
      \"content\": [
        {
          \"type\": \"image\",
          \"source\": {
            \"type\": \"base64\",
            \"media_type\": \"image/png\",
            \"data\": \"$IMAGE_B64\"
          }
        },
        {
          \"type\": \"text\",
          \"text\": \"Extract all visible text as Markdown. Preserve headings, lists, and tables when present. Do not invent text that is not in the image.\"
        }
      ]
    }]
  }"

URL-hosted images skip base64. Use "source": { "type": "url", "url": "https://example.com/page.png" } in the same image block. For repeated references in multi-turn agents, upload once via the Files API and pass "type": "file", "file_id": "...".

Python: same call with the official SDK

import base64
import anthropic

with open("screenshot.png", "rb") as f:
    data = base64.standard_b64encode(f.read()).decode("utf-8")

client = anthropic.Anthropic()  # uses ANTHROPIC_API_KEY

message = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=2048,
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "image",
                "source": {
                    "type": "base64",
                    "media_type": "image/png",
                    "data": data,
                },
            },
            {
                "type": "text",
                "text": (
                    "Extract all visible text as Markdown. "
                    "Do not invent text that is not in the image."
                ),
            },
        ],
    }],
)

print(message.content[0].text)

What you get back is a normal Messages response: text blocks (and optional tool calls if you enabled tools). There is no guaranteed schema unless you enforce one. Soft prompts like “reply with JSON only” help, but production pipelines still need validation and retries when the model wraps JSON in prose or drifts keys.

Cost, latency, and accuracy tradeoffs

Anthropic bills images as visual tokens. Per the vision docs, each patch is a 28×28 pixel block, so an image costs roughly ceil(width / 28) × ceil(height / 28) visual tokens before any text prompt or completion tokens. Oversized images are downscaled to the model’s long-edge / visual-token limits. Dense full-page scans at high resolution burn more input tokens than a cropped UI dump.

Practical consequences for an image-to-text Claude workflow:

  • Cost scales with pixels and output length, not with “one page.” A sharp 4K scan on a high-resolution-tier model can cost several times a downsampled copy of the same document. Check current per-model rates on Anthropic’s pricing page; Sonnet-class models are usually the middle ground for extraction demos.
  • Latency includes vision encoding plus generation. Fine for interactive tools; painful if you fan out thousands of pages through chat completions.
  • Accuracy is strong on clear print and screenshots. Anthropic documents weaker spots: very small crops (under about 200 px), rotated or blurry text, and dense numeric tables where digit-level precision matters. Treat IDs, totals, and account numbers as values to verify.

A dedicated OCR API flips the product shape. You send bytes, get Markdown or named fields, and you do not assemble a multimodal messages array for every page. OCRskill prices extraction in tokens aimed at that job (see Why token pricing wins for OCR for the site’s published rates and examples). You still validate high-stakes digits, but you avoid paying generalist vision tokens for routine transcription.

Job Claude Messages + vision Dedicated OCR (e.g. OCRskill)
One screenshot, ask a question Strong fit Overkill
Hundreds of similar images → Markdown Possible; you own batching, prompts, parsing Built for upload → text
Stable named fields every time Prompt/tools; output can drift POST /ocr.json?fields=...
Explain what the layout means Strength Pair OCR text with Claude afterward
Unit cost on dense bulk scans Vision tokens add up Extraction-oriented token pricing

Contrast: OCRskill for bulk and structured extraction

Markdown from a PNG without a Messages payload (simplified /ocr upload):

curl https://api.ocrskill.com/ocr \
  -H "Authorization: Bearer $OCRSKILL_API_KEY" \
  -H "Content-Type: image/png" \
  --data-binary "@screenshot.png"

Typed fields when your app needs columns, not a chat reply (structured OCR JSON, full field list on the OCR JSON API page):

curl "https://api.ocrskill.com/ocr.json?fields=company_name,invoice_date,total_amount" \
  -H "Authorization: Bearer $OCRSKILL_API_KEY" \
  -F "file=@invoice.png"

Get a free test key with curl https://api.ocrskill.com/get-key.json. Auth is always Authorization: Bearer. Inputs mirror what teams already use for plain OCR (multipart, raw binary, data URIs), with a 20 MB max size on /ocr.json per the reference docs.

Hybrid pattern: OCR for pixels, Claude for reasoning

Most production stacks that “use Claude for OCR” should not route every page through vision forever. A durable split:

  1. Extract with OCRskill (/ocr for Markdown, /ocr.json for fields).
  2. Reason with Claude on the resulting text: classify, summarize, decide next actions, draft replies, map fields into domain schemas.
  3. Escalate only the awkward slice (shadows, weird angles, mixed handwriting, layout that needs explanation) to a Claude vision pass after a cheap OCR attempt.

That keeps bulk cost and latency predictable while you still use Claude where judgment matters. If you work inside Claude Code rather than a backend service, package the OCR step as a skill so the agent shells to the API instead of pasting huge scans into context; see Claude Code OCR skill.

Example hybrid in Python (OCR first, then Claude on text only):

import os
import requests
import anthropic

api_key = os.environ["OCRSKILL_API_KEY"]
with open("invoice.png", "rb") as f:
    ocr = requests.post(
        "https://api.ocrskill.com/ocr",
        headers={
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "image/png",
        },
        data=f,
        timeout=60,
    )
ocr.raise_for_status()
markdown = ocr.text

client = anthropic.Anthropic()
decision = client.messages.create(
    model="claude-sonnet-5",
    max_tokens=512,
    messages=[{
        "role": "user",
        "content": (
            "Given this invoice text, say whether payment looks overdue "
            "and list any missing fields. Reply in short bullets.\n\n"
            f"{markdown}"
        ),
    }],
)
print(decision.content[0].text)

You pay OCR tokens for the image once, then cheaper text tokens for the decision. You also avoid stuffing the same PNG into every follow-up turn.

Limits and pitfalls when treating Claude as an OCR API

  • No dedicated OCR endpoint. Retries, schema enforcement, and batch orchestration are yours.
  • Image limits. Anthropic documents per-image size caps (about 10 MB base64 on the Claude API), max dimensions, and per-request image counts. Requests with many images hit stricter dimension rules and overall payload limits (32 MB on standard endpoints). Prefer Files API file_id when the same image appears across turns.
  • Downscaling can hurt fine text. If a dense table shrinks below legibility, pre-crop or downsample thoughtfully before upload, or switch that page to a dedicated OCR path.
  • Soft JSON. Prompt-only “return JSON” is not the same as required typed fields with 400 on missing keys. Use tools or a post-validator if you stay on Claude for structure; use /ocr.json when the schema is the product.
  • High-stakes digits. Neither Claude vision nor OCR APIs are a substitute for verification on money, IDs, and legal identifiers.
  • Wrong surface. Claude.ai chat Skills and Claude Code skills are different products from a backend Messages integration. Match the surface to the workflow.

When to choose which path

Use Claude Messages + vision when you need an answer about one or a few images, layout or charts matter as much as characters, volume is low, or the next step is reasoning rather than a database row.

Use a dedicated OCR API when you already know the job is extraction, you want stable Markdown or named JSON, you process many similar files, or you want extraction logged and priced separately from chat.

Combine them when OCR feeds Claude clean text, and vision is reserved for exceptions.

If your search was really “Anthropic OCR API” or “image to text Claude” for a production service, start by wiring a dedicated extraction endpoint for the bulk path, keep Claude for judgment, and only use Messages vision as the primary OCR when the product is conversation, not transcription. Grab an OCRskill key for the upload → Markdown or fields step, and keep Anthropic’s vision guide open for the image-block details on the reasoning side.