Multimodal Token Cost: The Image Patch Formula & the PDF document Block
CoreWork with the Messages API's core request/response mechanics · Difficulty 2/5
Explanation
The Image Token Formula
Claude does not see an image as one indivisible unit -- it views images in 28x28-pixel patches, and each patch is one visual token. That gives a concrete, computable cost:
visual_tokens = ceil(width / 28) * ceil(height / 28)Worked example: a 1,000 x 1,000 pixel image is ceil(1000/28) x ceil(1000/28) = 36 x 36 = 1,296 visual tokens. Run the same formula on a few sizes to build intuition for how fast this scales:
| Image size | Patches (ceil(w/28) x ceil(h/28)) | Visual tokens |
|---|---|---|
| 400 x 300 px (small screenshot) | 15 x 11 | ~165 |
| 1,000 x 1,000 px | 36 x 36 | ~1,296 |
| 1,920 x 1,080 px (full HD screenshot) | 69 x 39 | ~2,691 |
| 3,000 x 2,000 px (high-res photo) | 108 x 72 | ~7,776 |
At that rate, a handful of full-resolution screenshots in one request can consume as much context as a substantial system prompt -- ten of them can outweigh it. This is a budget line item to compute at design time, not something to discover once a pipeline is already in production against real-size inputs.
The Resolution Ceiling and Downscaling
Each model tier has its own maximum native image resolution, expressed as both a long-edge pixel limit and a visual-token ceiling, and these limits differ across model generations -- newer tiers generally accept larger images before hitting the ceiling. An image that exceeds either limit is downscaled before processing, and the token-cost formula then runs on the *scaled* dimensions, not the original ones. Practically: if you send an oversized image expecting the formula to apply to its native size, the actual token cost will be lower than a naive calculation predicts, because the image was shrunk first -- but you also lose whatever detail the downscale discarded. Confirm current per-tier limits against the vision documentation at build time, since they have changed between model generations before and will again.
PDFs Use a Different Block Type: document, Not image
A PDF is not sent as an image Content Block -- it uses a dedicated document block type. The source structure inside it follows the same pattern images use (it can be base64, a url, or a Files API file_id), but the surrounding block is document:
{
"type": "document",
"source": {
"type": "base64",
"media_type": "application/pdf",
"data": "<base64-encoded-pdf-bytes>"
},
"title": "contract_review.pdf"
}A few structural details about this block are easy to get wrong from memory:
- There is no required
namefield on adocumentblock -- do not assume PDFs need a filename field the way some other systems require one. title(a readable document name) andcontext(additional metadata) are both optional -- neither is required to send a valid PDF request.- Once loaded, a PDF's pages are subject to the same visual-token accounting as any other image content Claude reads from it -- the formula above and the per-tier resolution limits both still apply.
Base64 vs. Files API: The Reuse Question
Inline base64 encoding puts the full encoded payload directly in the message content -- simple, no upload step, but that means the entire payload travels on every single request. For a genuinely one-off image or document, that overhead is fine; the complexity of an upload flow wouldn't pay for itself. But for an asset that gets sent to Claude repeatedly across many requests -- a reference product diagram, a template document, a standing policy PDF -- base64 means paying the full transfer and (if the content counts toward tokens on each occurrence) the full token cost every single time. That is exactly the case the Files API and prompt caching exist to solve: upload or cache the asset once, reference it by file_id (or a cached prefix) on every subsequent call, and avoid re-transferring and re-tokenizing the same bytes over and over.
| Scenario | Right approach | Why |
|---|---|---|
| A support engineer submits a one-off screenshot of a bug | Inline base64 | No reuse, so an upload step adds complexity with no later payoff |
| A reference diagram sent with every request in a pipeline | Files API (file_id) | The same asset is reused across many calls -- upload once, reference cheaply thereafter |
| A long, stable system-prompt document read on every turn of a session | Prompt caching (cache_control) | Not a separate asset per request -- a stable prefix reused turn over turn |
Common exam traps
- Applying the image-token formula to an oversized image's *original* dimensions instead of its downscaled dimensions -- the API downscales first, then tokenizes.
- Assuming a PDF needs a
namefield on its Content Block, or thattitle/contextare required -- none of the three is mandatory. - Sending a PDF as an
image-type block instead of adocument-type block. - Reaching for inline base64 by default for an asset that's actually reused across many requests, paying the full transfer and token cost repeatedly instead of uploading once via the Files API.
Key Takeaways
- Claude views images in 28x28-pixel patches; visual token cost = ceil(width/28) x ceil(height/28), so a 1,000x1,000px image costs ~1,296 visual tokens
- Each model tier has its own maximum native image resolution (a long-edge limit and a visual-token limit); oversized images are downscaled before processing, and the formula applies to the scaled dimensions
- PDFs use a document content block, not an image block; source can be base64, a URL, or a Files API file_id, with no required name field and optional title/context fields
- Inline base64 sends the full payload on every request -- fine for a one-off asset, costly for one reused across many calls, where the Files API or prompt caching is the correct fix
Glossary Terms
Related Concepts