◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/API & SDK
⬡ API & SDK/2026-03-10Intermediate

Multimodal Input Guide — Working with Images and PDFs in the Claude API

How to send images and PDFs to the Claude API, when to reach for the Files API, and the cost and speed lessons you only learn by running it in production — with real measurements.

multimodal3vision8pdf4files-api3image

✦ Premium Article

What is Multimodal Input?

Claude can understand more than just text. It can analyze images, read PDFs, interpret charts, and extract information from visual content. This is called "multimodal input" — the ability to process multiple types of media in a single API request.

ℹ️
With multimodal input, you can: - Analyze and describe image contents - Extract text and visual elements from PDFs - Read charts, graphs, and tables - Compare and contrast multiple images - Extract structured data from documents

Sending Images to Claude

Claude supports four image formats: JPEG, PNG, GIF, and WebP. There are three ways to include images in your API requests.

Method 1: Base64 Encoding

The most fundamental approach — read a local image file, encode it as Base64, and send it in the request body.

import anthropic
import base64
 
# Read and encode a local image
with open("photo.jpg", "rb") as f:
    image_data = base64.standard_b64encode(f.read()).decode("utf-8")
 
client = anthropic.Anthropic()
message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/jpeg",
                        "data": image_data,
                    },
                },
                {"type": "text", "text": "What's in this image?"},
            ],
        }
    ],
)
print(message.content[0].text)

Here's the TypeScript equivalent:

import Anthropic from "@anthropic-ai/sdk";
import fs from "fs";
 
const client = new Anthropic();
 
const imageData = fs.readFileSync("photo.jpg").toString("base64");
 
const message = await client.messages.create({
  model: "claude-sonnet-4-6",
  max_tokens: 1024,
  messages: [
    {
      role: "user",
      content: [
        {
          type: "image",
          source: {
            type: "base64",
            media_type: "image/jpeg",
            data: imageData,
          },
        },
        { type: "text", text: "What's in this image?" },
      ],
    },
  ],
});

Method 2: URL Reference

For images hosted online, you can reference them directly by URL. This is the simplest approach since no encoding is needed.

import anthropic
 
client = anthropic.Anthropic()
message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "url",
                        "url": "https://example.com/chart.png",
                    },
                },
                {"type": "text", "text": "Analyze the trend shown in this chart."},
            ],
        }
    ],
)

Method 3: Files API

For images you'll reuse across multiple requests, the Files API lets you upload once and reference by file_id. This is especially valuable in multi-turn conversations where each request resends the full history — using file_id keeps payloads small.

import anthropic
 
client = anthropic.Anthropic()
 
# Upload the image once
with open("photo.jpg", "rb") as f:
    file = client.beta.files.upload(
        file=("photo.jpg", f, "image/jpeg")
    )
 
# Reference by file_id in messages
message = client.beta.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    betas=["files-api-2025-04-14"],
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {"type": "file", "file_id": file.id},
                },
                {"type": "text", "text": "Describe this image."},
            ],
        }
    ],
)
💡
The Files API is currently in beta. Include the header `anthropic-beta: files-api-2025-04-14` in your requests.
✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Why resizing helps perceived speed, not accuracy — with measured first-response time dropping from 2.3s to 0.9s
✦How a scanned PDF costs roughly 2x the tokens of a text-based one, and how to budget for it
✦Avoiding silent 400s from a wrong media_type, and when the Files API actually pays off
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ API & SDK2026-09-22
Character counts won't predict PDF input tokens — bracket the cost per page before you send
How to estimate the input tokens of a PDF before sending it to the Claude API, by bracketing from page count rather than character count. Includes a measured 6.6x gap on a nine-page A4 document, the two separate increases that come with current models, and the count_tokens limitation that bites when you use file_id.
⬡ API & SDK2026-06-13
Claude Vision API in Production — Implementation Patterns for Image Analysis, PDF Processing, and OCR
Implementation patterns for taking Claude's vision capabilities to production: choosing between Base64, URL, and the Files API, native PDF processing, schema-enforced extraction with Tool Use, batch cost reduction, and error recovery — all with working code.
⬡ API & SDK2026-06-12
Handing Monthly Revenue CSVs to the Claude API Code Execution Tool — Files API Wiring, Container Reuse, and Billing Traps
How I moved monthly revenue-CSV reconciliation into the Claude API Code Execution tool — a pre-upload sanity check, Files API integration, container reuse, the 5-minute billing minimum, and the file recovery that pause_turn quietly drops.