Chapter 2 of 7 · 19 min read
Image token cost
On this page
Every mainstream provider prices an image on its dimensions rather than its bytes, using a formula stated in the reference documentation, applied after a server-side resize that caps how large an image is allowed to be before anything is counted. File size is a fact about compression; token cost is a fact about pixels. The two are so loosely related that ranking images by upload size ranks them wrongly by cost.
This chapter is about doing that arithmetic before you send anything: the order of the steps, the three billing shapes in common use, the floors and ceilings that defeat the obvious optimisations, and how to check an estimate against what the API actually reports. Getting it wrong is expensive in a particular way, because image tokens are input tokens — the tokens a model is charged for reading, as opposed to the ones it generates — so they are paid on every request that carries the image, including each retry and each turn of a multi-turn conversation.
Resize first, then count
Two images went through the same endpoint on the same afternoon. The first was a 3000×2000 photograph of a whiteboard, saved as JPEG at quality 85, weighing 1.8 MB. The second was a 4000×3000 screenshot of a mostly-white admin dashboard, saved as PNG, weighing 210 KB — less than an eighth of the bytes. The screenshot cost more: 2,459 input tokens against 2,185. Anyone forecasting spend from average upload size would have got the ranking backwards and the total wrong.
Bytes and cost come apart like that because of how an image becomes something a model can read, and having that mechanism is what makes every formula below predictable rather than memorised. A model consumes one sequence of positions and nothing else, so an image has to be turned into positions before any of it can be read. The provider does that by cutting the picture into fixed-size patches and turning each patch into one entry in that sequence. The number of entries an image produces is therefore the number of patches it makes, and the number of patches is the image's area divided by the area one patch covers. A picture twice as wide and twice as tall makes four times as many patches whatever it weighs on disk, which is why a token count is arithmetic on width and height. A divisor in a published formula is that patch area written as a single number, and dividing by it is the right operation rather than a convention somebody settled on.
Compression sits entirely outside that chain. A JPEG quality setting decides how many bytes are needed to describe a given grid of pixels, and it changes no pixel counts at all, which is exactly why the two images above rank the way they do. The screenshot is mostly flat white, which compresses to almost nothing and still occupies every patch its dimensions demand. The same chain also forces a cap to exist somewhere: patch count grows with area, area has no upper bound, and without a limit one upload could take an arbitrary share of both the bill and the context window. Some limit has to exist, and it has to bite where the pixels arrive rather than where they were chosen, because the dimensions arriving are whatever the client decided to send.
The order of operations is what produces that result, and it matters more than the formula. Providers cap resolution, and the cap is applied server-side before anything is counted.
Take a provider that bills roughly (width × height) / 750 tokens and states
that images with a long edge above 1568 pixels are resized down before encoding.
Send that whiteboard photo and the calculation runs in four steps, each of which
is worth doing rather than assuming.
The first step decides whether the cap fires at all, which means comparing the longer of the two dimensions against it. The long edge of 3000 exceeds 1568, so the image is resized, and the factor to resize by is the cap divided by that long edge: 1568/3000 = 0.5227. The second step applies that factor to both dimensions, which is what keeps the picture the shape it was — multiplying one edge and not the other would stretch it — so the long edge lands on the cap by construction and the short edge of 2000 becomes about 1045. The photograph the provider is about to count is 1568×1045, and nothing in the request said so.
The third step is the formula, applied to the dimensions that survived rather than the ones that were uploaded: 1568 × 1045 = 1,638,560 pixels, a little over 1.6 million, divided by 750 for 2,184.7. That fraction has to become a whole number because a fraction of a position in a sequence does not exist, so the count is completed upward to about 2,185 tokens. The fourth step converts tokens to money at the published input rate, which means dividing by a million and multiplying by three: 2,185 tokens at $3 per million tokens is $0.0066 for the image.
The number people expect, if they apply the formula to the upload, is 3000 × 2000 / 750 = 8,000 tokens — nearly four times too high. The error runs the other way too. Downscaling that photo yourself from 3000×2000 to 1600×1067 before upload feels like a saving and is worth almost nothing, because 1600 still exceeds the cap and the server resizes to 1568×1045 regardless. You did the work; the provider was going to do it anyway. The 4000×3000 screenshot runs through the same steps: capped to 1568×1176, which is 1,843,968 pixels, divided by 750 for 2,459 tokens. Its aspect ratio is squarer, so more pixels survive the cap on the long edge, and it costs 13% more than the photograph that was eight times larger on disk.
Two beliefs are doing the damage there, and both are reasonable enough that stating them plainly is the only way to dislodge them. The first is that a smaller file is a cheaper request, which is what every other pipe in an engineering system has taught: bytes are what a network moves, what a bucket charges for and what a gateway limits, so bytes are the quantity an engineer reaches for. Here they are a fact about compression and the price is a fact about patch count, and the two are related only loosely enough to rank a set of images wrongly. The second is that shrinking an image before upload buys something, which is true right up to the cap and worth nothing beyond it, because every pixel between the cap and your upload was going to be discarded for free.
Squarer images hit the area cap first
A single long-edge cap is the simplest case, and plenty of references state a second limit alongside it — a ceiling on total area, commonly around 1.15 megapixels, or a maximum number of tokens per image. Both constraints apply together, so compute a scale factor for each and use the smaller. Taking the smaller is the whole of the rule and it earns a line of justification: a factor that satisfies one constraint leaves the image still illegal under the other, and only the more aggressive of the two brings the picture inside both at once.
The area factor is the step that gets done wrongly, because an area does not scale the way an edge does. Multiplying both edges by the same factor multiplies the area by that factor twice over, once for each edge, so halving both edges leaves a quarter of the pixels rather than half of them. Running that backwards is what the square root is for: to bring an area down to some fraction of what it was, the edges have to be multiplied by the number which, multiplied by itself, gives that fraction. The slip worth naming is dividing the cap by the area and using the answer directly on the edges, which shrinks the picture far harder than the cap ever asked for, and which looks right because it is the arithmetic every other kind of budget uses.
Take the same 3000×2000 photograph against a provider stating both a 1568-pixel long edge and a 1.15-megapixel area cap. The long-edge factor is 1568/3000 = 0.5227, exactly as before. For the area factor, the upload holds 6,000,000 pixels against a cap of 1,150,000, so the fraction to reach is 1,150,000/6,000,000 — a little under a fifth — and the number giving that fraction when multiplied by itself is 0.4378. That is the smaller of the two, so it governs. Multiplying both edges by it gives 1313×875, and dividing 1,148,875 pixels by 750 gives about 1,532 tokens rather than 2,185. The check worth doing is the last one: 1,148,875 sits just inside the 1,150,000 the cap allows, which is how you know the right factor was applied rather than a plausible one.
Which constraint binds depends on the aspect ratio. A square-ish upload spends its pixels in both directions, so it hits the area cap while its long edge is still legal — 3000×3000 scaled to a 1568-pixel long edge is 2.46 megapixels, more than double a 1.15-megapixel limit. A 5000×1000 panorama behaves the opposite way, arriving at 1568×314 and well under half a megapixel, so the long-edge cap is the only one that ever fires on it. Reading only the long-edge cap therefore overestimates square images by about a third, which is the harmless direction for a budget and the wrong direction if you are sizing a request against a context limit.
Both of those shapes are one multiplication each. The square upload has no short edge to speak of, so bringing its long edge to the cap brings the other edge to the cap as well, and the surviving area is 1568 multiplied by itself, which is the 2.46 megapixels above and more than double the limit it was supposed to satisfy. The panorama takes the same treatment and comes out the other way: the factor that brings 5000 down to 1568 is a little over three tenths, applying it to a height of 1000 leaves 314, and 1568×314 is the well-under-half-a-megapixel figure that no area cap will ever object to. The gap the square opens is the third mentioned above — the 3000×2000 photograph quoted at 2,185 tokens where the two caps together give 1,532 — and it is a third of the number you would have quoted rather than of the number you would have paid.
The formulas differ, and so do their floors
There is no shared standard here. Three broad billing shapes are in use, and each has its own rounding behaviour and its own floor.
| Provider style | Resolution handling | Token count | Where it surprises you |
|---|---|---|---|
| Continuous, area-based | Long edge capped, aspect preserved | Approximately w × h / 750, with an effective ceiling near 1,600 tokens | Cost scales smoothly, so small resizes give small savings — and the cap means large uploads all converge on the same price |
| Fixed tiles | Scaled to fit a bounding box, then divided into 512-pixel tiles | A base charge plus a fixed cost per tile | Tiles round up, so cost is a step function; two different sizes routinely cost exactly the same |
| Flat plus tiles | Images below a threshold are one flat charge; larger ones are cut into fixed crops | A constant per image below the threshold, a constant per crop above it | The floor means shrinking a small image below the threshold saves nothing at all |
The floors deserve attention because they defeat the most intuitive optimisation. A provider that charges a flat 258 tokens for any image whose dimensions both fall under 384 pixels is charging the same for a 384×384 thumbnail as for a 96×96 favicon. Compressing that favicon further, or stripping its colour, changes nothing on the bill and can only cost you information. The same logic applies at the top: under a 1568-pixel cap, a 6000×4000 upload and a 2000×1333 upload are billed identically, so the only thing the larger upload bought you was bandwidth and latency.
Rounding is the other place where intuition fails. Where a formula divides pixels
by a constant, the result is close to continuous and 5% fewer pixels is roughly
5% fewer tokens. Where the provider counts tiles, ceil is applied to each axis
independently, and a resize that does not cross a boundary changes nothing. That
behaviour is consequential enough that chapter 4 is devoted to it.
Establishing which family you are on takes ten minutes in the reference, provided you know what to hunt for: the long-edge cap, any area cap, the formula or tile size, the rounding rule, the floor, the per-image ceiling, and the model versions the page covers. A reference that omits one is telling you indirectly to measure it.
Do the arithmetic in code, then check it against the bill
An estimator you can call before sending is worth writing, because it lets you reject or downscale an upload at the edge of your system rather than discovering the cost in a monthly invoice. Two of the three billing styles fit in a dozen lines:
import math
def area_based_tokens(width: int, height: int,
long_edge_cap: int = 1568,
divisor: int = 750) -> int:
"""Continuous, area-based pricing: cap the long edge, then divide."""
long_edge = max(width, height)
if long_edge > long_edge_cap:
scale = long_edge_cap / long_edge
width = int(width * scale)
height = int(height * scale)
return math.ceil(width * height / divisor)
def tile_based_tokens(width: int, height: int,
box: int = 2048, short_edge: int = 768,
tile: int = 512,
base: int = 85, per_tile: int = 170) -> int:
"""Fixed-tile pricing: fit a box, normalise the short edge, count tiles."""
if max(width, height) > box:
scale = box / max(width, height)
width, height = int(width * scale), int(height * scale)
if min(width, height) > short_edge:
scale = short_edge / min(width, height)
width, height = int(width * scale), int(height * scale)
tiles = math.ceil(width / tile) * math.ceil(height / tile)
return base + per_tile * tiles
print(area_based_tokens(3000, 2000)) # 2185
print(area_based_tokens(4000, 3000)) # 2459
print(tile_based_tokens(1600, 1200)) # 765Treat those outputs as an estimate that is good to a few percent, not as the
number you will be billed. The authoritative figure is what the API reports, and
there are two ways to get it. The response carries usage.input_tokens, which
includes the image and everything else in the request, so isolating the image
cost means sending the same prompt with and without it and taking the difference.
Better, most providers expose a token-counting endpoint that runs the real
tokeniser without running the model:
count = client.messages.count_tokens(
model="claude-opus-5",
messages=[{
"role": "user",
"content": [
{"type": "image", "source": {"type": "base64",
"media_type": "image/jpeg",
"data": encoded}},
{"type": "text", "text": "What is written on this whiteboard?"},
],
}],
)
print(count.input_tokens) # 2196 — 2185 for the image, 11 for the textRun that once for each image size your system actually produces and put the results in a table you keep. Ten measured numbers beat a formula you half-remember, and they will catch the case where the reference documentation and the deployed behaviour have drifted apart.
Here is that table for one support tool's real traffic, on the single-cap area-based provider above, priced at $3 per million input tokens. The rightmost column is what ends arguments in planning meetings, converting a per-image number nobody has intuitions about into a monthly line item everybody does.
| Where it comes from | Upload | After the 1568 px cap | Tokens | $ / image | $ / 10,000 |
|---|---|---|---|---|---|
| Phone camera, default quality | 4032 × 3024 | 1568 × 1176 | 2,459 | $0.0074 | $73.77 |
| Scanned page, 300 DPI US Letter | 2550 × 3300 | 1211 × 1568 | 2,532 | $0.0076 | $75.96 |
| Whiteboard photo | 3000 × 2000 | 1568 × 1045 | 2,185 | $0.0066 | $65.55 |
| Retina screen capture | 2880 × 1800 | 1568 × 980 | 2,049 | $0.0061 | $61.47 |
| 1080p window capture | 1920 × 1080 | 1568 × 882 | 1,844 | $0.0055 | $55.32 |
| Exported chart PNG | 800 × 600 | unchanged | 640 | $0.0019 | $19.20 |
| Avatar thumbnail | 320 × 240 | unchanged | 103 | $0.0003 | $3.09 |
A pair of those rows is worth working by hand, because between them they cover every trap in the column headings. The scanned page is portrait, so its long edge is the height rather than the width — 3300 against 2550 — and it is the height that lands on 1568 while the width is multiplied by the same factor, a little under a half, to reach 1211. The product of 1211 and 1568 is a shade under two million pixels, which over 750 is the 2,532 in the table, and reading the cap as a limit on width would have produced a confident wrong answer. The exported chart is the other case: its long edge of 800 is already under the cap, so no factor is applied at all, four hundred and eighty thousand pixels over 750 is exactly 640 tokens, and 640 at $3 per million is the $0.0019 beside it. The rightmost column is that per-image figure multiplied by ten thousand, which is the only step in the table anybody performs willingly.
Two things fall out of the table. Everything above the cap converges, so upload areas spanning six to one — 12.2 megapixels for the phone photo down to 2.1 for the window capture — come out as token counts spanning 37%, decided by aspect ratio rather than by size. That is why scanning at 600 dots per inch instead of 300 changes the bill by nothing at all, DPI being a straight multiplier on the pixel dimensions a scanner emits and therefore on exactly the quantity the cap is about to discard. The rows below the cap are then cheap in a way no resize of the rows above them can reach, since the exported chart at 640 tokens costs a quarter of the scanned page and the thumbnail costs a fortieth. A small bill comes from images that were small before they met the cap, and shaving a 4032-pixel photo down to 2000 pixels does not make an image small in that sense.
Once you have per-image numbers, the monthly arithmetic is straightforward and often surprising. A support tool handling 200,000 screenshots a month at 2,185 tokens each sends 437 million input tokens, which is $1,311 at $3 per million. Change nothing except the prompt design — say, an agent loop that re-sends the image on each of three tool-calling turns — and the same 200,000 screenshots cost $3,933, because the image is part of the input on every request in the loop. Image cost is rarely a per-image problem; it is a per-image cost multiplied by how many times your architecture sends it.
Tokens, bytes and the rest of the bill
A token count is not a measure of quality or of how much the model can see. Two images with identical token counts can differ enormously in whether the text on them is legible, and the whole of the next chapter turns on that gap. Token count answers "what does this cost", and nothing else.
It is not the whole bill either. Output tokens are priced several times higher than input on most models, so an image request that returns a 600-token structured extraction may cost more on the way out than on the way in. Prompt caching, where the provider supports it, changes the picture again. Prompt caching lets the provider keep the processed form of a prefix of your request — everything from the start of the messages up to a marker you place — so that a later request beginning with byte-identical content can reuse that work instead of redoing it. An image sitting inside a cached prefix is then charged at a fraction of the normal input rate on subsequent hits, which makes "send the image once and carry a text summary" a less obvious win than it looks. Work out both numbers before you restructure anything.
And it has nothing to do with your bandwidth. Base64 encoding inflates the payload by about a third, so a 1.8 MB JPEG arrives as a 2.4 MB request body; that affects your upload time, your gateway limits and any per-request size cap, and it is invisible to the token count. Teams sometimes conflate the two and start optimising JPEG quality to save tokens. Quality settings change bytes. Only dimensions change tokens.
Knowing an image's cost before sending it is exact in a specific and limited sense, and both of the limits are inherited by any estimator you write. The arithmetic is exact given the constants the provider publishes — the cap, the divisor, the floor, the ceiling — and those constants belong to a model version rather than to the API, so an exact answer is exact for the version you pinned and not for the alias you sent. It is also exact only where the reference is complete, since a page that omits the area cap or the rounding rule leaves a term out of your calculation, and a calculation missing a term returns a confident number wrong by the size of that term. Both are why the counting endpoint is the arbiter and the estimator is the thing that lets you ask the question before an upload is worth sending.
Within those two limits the cost of an image is knowable before you send it: read the cap and the formula out of the reference, apply them in that order, confirm the result against the counting endpoint, and keep the measured numbers next to the code that produces the uploads. Doing so converts image spend from a monthly surprise into a quantity you can reason about at the point where an upload enters your system, which is the only point at which you can still do something about it.
What the estimator will not tell you is what you lose by making the image smaller, and that is the missing half of every resize decision — the whiteboard photo at 1568×1045 is a quarter of the pixels of the upload, and whether that matters depends entirely on whether the answer you need lives in a large shape or in a small glyph.
Image inputs — read the current version at https://daviddominguez.dev/learn/en/image-inputs/image-token-cost