Claude Vision Token Cost Unexpected — Image Billing Fix (2026) | AI Error Hub
Anthropic Claude Vision · Billing Severity: Medium Not an error

Claude Vision — Unexpected Token Consumption

Your bill is higher than expected because images cost 1000-5000+ tokens each depending on dimensions. Not a bug — vision is expensive. Approximate formula: tokens ≈ (width × height) / 750. Downscale before sending to slash cost 3-10x with minimal accuracy loss.

Error surface: Billing math Category: Vision · Billing Type: Cost surprise Last tested: Nov 15, 2026
Quick Fix (TL;DR)

Resize images to 1092×1092 max before uploading. This drops cost from ~5000 tokens (large image) to ~1600 tokens with negligible accuracy loss for most tasks. For OCR of dense text, 1568px longest edge is sweet spot. Use prompt caching when sending the same image across multiple queries.

The "Symptom" You're Seeing

Common surprises
My bill for 10,000 vision requests is $150 higher than expected
  → Each image consumed ~2000 tokens more than my estimate

Anthropic console shows 8,500 input tokens for a simple prompt
  → Prompt was 50 tokens; image was 8,450 tokens (large photo)

PDF processing cost 10x more than plain text
  → PDF pages tokenize like images: 1500-3000 tokens per page

I sent identical images 100 times, was billed 100x
  → Prompt caching not enabled; each was full-price

Vision seems way more expensive than text
  → Yes — vision tokens are billed at input rate, but images generate many tokens

Image Token Math (Claude Sonnet 4.5)

Approximate formula: image_tokens ≈ ceil((width × height) / 750)

Image SizeTokensInput CostNotes
200 × 200 (icon)~55$0.00016Minimal
512 × 512 (thumbnail)~350$0.00105Recognizes UI, simple scenes
768 × 768 (small)~790$0.00237Good for most tasks
1092 × 1092 (SWEET SPOT)~1590$0.00477Best cost/accuracy ratio
1568 × 1568 (OCR-friendly)~3280$0.00984Best for text-heavy content
2000 × 2000~5335$0.01601Diminishing returns above this
4000 × 4000 (huge)~21335$0.06400Waste for most use cases
8000 × 8000 (max)~85335$0.25600Rarely needed

Cost figures assume $3/million input tokens (Sonnet 4.5). Opus 4.6 is 5× more expensive; Haiku 4.5 is 3.75× cheaper.

Where Cost Surprises Come From

42%
Sending original high-resolution images4K screenshots, DSLR photos at native size = 15-40K tokens per image. Downscale.
28%
Multiple images per request5 images × 3000 tokens = 15,000 tokens just for images. Batch fewer.
15%
PDF pages billed like imagesEach page ~2000 tokens. 100-page PDF = 200K tokens minimum.
10%
Not caching repeated imagesSame image sent 100 times = 100× cost. Cache_control drops it to 10%.
5%
Retries after failuresEvery retry re-sends the image and re-bills. Cache before retrying.

Fixes That Work (Tested Nov 2026)

1Estimate Cost Before Every Call

Python · pre-flight cost estimator
from PIL import Image import base64, io PRICES = { "claude-sonnet-4-5": {"input": 3.0, "output": 15.0}, "claude-opus-4-6": {"input": 15.0, "output": 75.0}, "claude-haiku-4-5": {"input": 0.80, "output": 4.0}, } def estimate_image_tokens(width, height): """Approximate token cost for an image at given dimensions.""" return int((width * height) / 750) def estimate_call_cost(image_paths, prompt_tokens, model="claude-sonnet-4-5", expected_output_tokens=500): total_image_tokens = 0 for path in image_paths: img = Image.open(path) total_image_tokens += estimate_image_tokens(*img.size) total_input = total_image_tokens + prompt_tokens prices = PRICES[model] input_cost = total_input * prices["input"] / 1_000_000 output_cost = expected_output_tokens * prices["output"] / 1_000_000 return { "image_tokens": total_image_tokens, "total_input_tokens": total_input, "estimated_cost": input_cost + output_cost, "per_image_avg": total_image_tokens / len(image_paths) if image_paths else 0 } # Use before every batch est = estimate_call_cost(["a.jpg", "b.jpg"], prompt_tokens=150) print(f"Est cost: ${est['estimated_cost']:.4f}") if est["per_image_avg"] > 3000: logger.warning("High image tokens; consider downscaling")

2Downscale Aggressively for Cost

Python · task-appropriate resize
def resize_by_task(path, task): """Resize based on task type — different needs, different sizes.""" max_edge = { "describe_scene": 768, # low detail needed "identify_object": 1092, # standard "read_ui_screenshot": 1092, # UI is bold, readable "ocr_document": 1568, # dense text needs detail "read_chart_data": 1568, # small labels "detailed_analysis": 2048, # premium quality }[task] img = Image.open(path) if max(img.size) > max_edge: ratio = max_edge / max(img.size) img = img.resize( (int(img.size[0] * ratio), int(img.size[1] * ratio)), Image.LANCZOS ) buf = io.BytesIO() img.save(buf, format="JPEG", quality=85) return base64.b64encode(buf.getvalue()).decode() # Same image, different tasks — different cost b64_cheap = resize_by_task("photo.jpg", "describe_scene") # ~800 tokens b64_pro = resize_by_task("photo.jpg", "detailed_analysis") # ~5500 tokens

3Cache Images That Repeat

Python · prompt caching for reused images
# If the SAME image is analyzed with many different questions # (e.g., document + N queries), cache the image content block response = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, messages=[{ "role": "user", "content": [ { "type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": b64}, "cache_control": {"type": "ephemeral"} # ← cache this }, {"type": "text", "text": question} ] }], extra_headers={"anthropic-beta": "prompt-caching-2024-07-31"} ) # Second query on same image = 90% cost reduction # cache_read_input_tokens billed at $0.30/M vs $3.00/M for regular input
When caching pays off

Cache write costs 25% extra ($3.75/M vs $3.00/M input). Cache read costs 90% less ($0.30/M vs $3.00/M). Break-even: after 2 uses, you save. 10 uses of the same image = 87% total savings vs re-sending each time.

Preventing This Error Going Forward

  • Estimate cost before every batch. Log estimate vs actual for calibration.
  • Set per-image token budget alerts. If avg per image > 3000, investigate.
  • Downscale by default. Ship with 1092px max, override for OCR tasks only.
  • Cache repeated images. Especially for interactive analysis (chat over document).
  • Prefer Haiku for volume vision tasks. Same tokens, 3.75× cheaper.
  • Audit monthly. Break down image tokens vs text tokens vs cached in dashboards.
SK
Tested by Sana K.
Researcher · AI Error Hub
Last verified: Nov 15, 2026 · Prices as of: Nov 2026

Frequently Asked Questions

It's an approximation. Actual tokens depend on tile boundaries and Claude's internal image encoding. Real numbers can vary ±15% from the formula. Use it for budgeting, verify with real usage data.

Input rate. Image tokens are counted as input tokens. They appear in usage.input_tokens alongside prompt tokens. There's no separate "vision fee" — just token count × input price.

Same token count for the same image, but Haiku's input rate is $0.80/M vs Sonnet's $3.00/M. So Haiku is 3.75× cheaper for vision. Great for high-volume, less complex vision tasks.

Use the Token Counting API (client.messages.count_tokens) — it returns exact input tokens including image content. Free to call. Perfect for pre-flight cost validation.

Yes. All input tokens (prompt + image + tools + cache) count against the 200K context window. A single 8000×8000 image can eat 40% of your context. Downscaling saves both cost and context.