Reducing Image Context Cost in Codex — Cutting Tokens with 32×32 Patches and detail: low / high / original on GPT-6.1, GPT-6, and GPT-5.6 Models
Passing screenshots to Codex or an OpenAI API vision model can burn through context faster than you would expect. What gets charged is image tokens, computed from pixel dimensions and per-model patch budgets, not the file size. Compressing a JPEG to half its size on disk does not reduce the token count if the width, height, and detail setting stay the same. This post walks through the current patch math, then orders the Codex adjustments that help from the ones that do not.
The Claude Code side of this optimization is written up in a companion post: Reducing Image Context Cost in Claude Code.
Models Codex ships with as of November 2026
As of 2026-11-07, Codex CLI’s model picker offers these eight options:
- GPT-6.1-Sol (latest workhorse, coding and everyday work)
- GPT-6-Astra (frontier intelligence for the most demanding work)
- GPT-6.1-Terra (fast, efficient model for clear writing, visual understanding, and computer use)
- GPT-6-Sol (previous-generation workhorse)
- GPT-6-Luna (fast and affordable, easier tasks)
- GPT-5.6-Sol / GPT-5.6-Terra / GPT-5.6-Luna (older but still available)
The GPT-4o family and GPT-4.1 family (previously the main vision targets) are no longer in Codex’s picker; the OpenAI API retires them on 2027-01-14, and gpt-4o-2024-05-13 and gpt-4.1-nano have already been removed as of 2026-10-23. This post focuses on the GPT-6.1 / GPT-6 / GPT-5.6 families that Codex actually offers today.
Image tokens come from 32×32 px patches
OpenAI’s Images and Vision guide describes a shared 32×32 px patch method for the models it lists, including GPT-6-Astra and the GPT-5.6 family. The per-image token count is:
ceil(width / 32) × ceil(height / 32) × per-model multiplier = image tokens
Every listed model uses a multiplier of 1.2. The detail parameter changes how the image is resized before the patches are counted.
| Model | detail options | low | high | original / auto |
|---|---|---|---|---|
| GPT-6-Astra | low / high / original / auto | fits within 512×512 | 2,500 patches, long edge up to 65,535 px | native size (resized only above 65,535 px per side) |
| GPT-5.6-Sol / GPT-5.6-Terra / GPT-5.6-Luna | low / high / original / auto | fits within 512×512 | 2,048×2,048 and 2,500 patches | native size (resized only above 65,535 px per side) |
The GPT-6.1 family, GPT-6-Sol, and GPT-6-Luna are not yet on the official per-model table (as of 2026-11), but the Codex picker’s descriptions put them in the same patch-based lineage as GPT-6-Astra. Check the official guide for the exact patch budgets if you need to be precise.
On top of the per-model sizing rules, every model enforces a hard cap of 30,000 patches per image. Images that still exceed that limit after resizing are rejected, not resized further. There are also per-request limits of 1,500 images and a 512 MB payload.
Worked examples with GPT-6-Astra at detail: auto:
- 512×512 image: ceil(512/32) × ceil(512/32) × 1.2 = 16 × 16 × 1.2 = 308 tokens
- 960×540 image: 30 × 17 × 1.2 = 612 tokens
- 1920×1080 image: 60 × 34 × 1.2 = 2,448 tokens
- 4K (3840×2160) image at
detail: high: exceeds the 2,500-patch budget, so it is resized before billing
detail: low is the strongest knob when the image is large. For instance, a 1920×1080 image at detail: low is scaled aspect-preserving to roughly 512×288, which gives ceil(512/32) × ceil(288/32) × 1.2 = 16 × 9 × 1.2 = 173 tokens. The trade-off is interpolation artifacts that make small text unreadable.
The old GPT-4o-style “detail: low = flat 85 tokens regardless of resolution” trick does not apply here. The current low mode still saves tokens by downscaling, but you pay per resulting patch rather than a fixed per-image amount.
What helps and what does not
| Adjustment | Effect | Reason |
|---|---|---|
Switch to detail: low | Large | Image is scaled to 512×512 max, so the patch count collapses |
| Downscale the image | Large | Fewer patches |
| Crop to the region you need | Large | Fewer patches |
| Replace the image with text or structured data | Large, depending on content | No image tokens at all |
| Keep images out of the running history | Large | Stops the same image from being re-tokenized turn after turn |
| Stitch multiple images into one | Small to medium | Amortizes the ceiling rounding and per-image overhead |
| Lower the JPEG quality | Almost none | File size and compression are not in the formula |
| Convert to grayscale | Almost none | The formula does not include color channels |
| Strip EXIF or other metadata | None | The file gets smaller, but the dimensions do not change |
Work through the options in order of impact
Use detail: low when the task allows
On GPT-6.1 / GPT-6 / GPT-5.6, detail: low scales the image to fit inside 512×512 aspect-preserving, then counts patches. The upper bound is 16 × 16 × 1.2 = 308 tokens; rectangular inputs come out lower. Fine text becomes unreadable, but the cost is nearly flat regardless of the input dimensions.
- Checking layout, colors, or overall composition
- Classifying images (photo vs. screenshot, light vs. dark mode)
- Checking a coarse UI state (logged in vs. logged out)
For any of these, detail: low is the cheapest path. In the OpenAI Python SDK:
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-6-astra",
input=[
{
"role": "user",
"content": [
{"type": "input_text", "text": "What screen is this?"},
{
"type": "input_image",
"image_url": "https://example.com/screenshot.png",
"detail": "low",
},
],
}
],
)For OCR, small on-screen text, or computer-use style tasks, detail: original is the right setting. auto (the default) behaves the same as original on GPT-6-Astra and the GPT-5.6 family, so an image sent without detail is billed at its native size. When you want a lower, predictable cost, set detail: low explicitly.
Codex CLI does not let you set detail: low or detail: high per message as of November 2026. The one related switch is the image_detail_original feature flag under [features] in ~/.codex/config.toml: when it is enabled, the model can request detail: original through its view_image tool (openai/codex PR #14175). If you need per-call control, wrap the OpenAI API with a thin layer of your own. The other lever that works from Codex is to preprocess the image (resize or crop) before sending it in.
Avoid sending the image when you can
A lot of what you want to convey in a Codex session does not depend on the image. Sending it as text or structured data uses fewer tokens and is also easier for the model to work with programmatically.
- For UI implementation or edits, send the HTML, CSS, or a DOM excerpt
- For flowcharts and screen transition diagrams, send the Mermaid source
- For tables, send CSV or a Markdown table
- For charts, send the underlying numeric data (CSV or JSON)
- For an error dialog, paste the error message as text instead of the screenshot
- For logos and icons, send the SVG source
For example, a terminal error is usually fully captured by this text:
Error: Cannot find module 'react'
File: src/main.tsx
Line: 12If you only need the characters inside an image, extract them with OCR or fetch the original log. Shapes, the placement of UI elements, and the relationships in a diagram are lost in text, so send the image alongside the text when those matter.
Crop to the region that matters
Cut out the part of the screen where the problem appears rather than sending the full screen. Because patch count scales directly with area, cropping is the most reliable saver. Cutting a 480×270 region out of a 1920×1080 screenshot gives ceil(480/32) × ceil(270/32) × 1.2 = 15 × 9 × 1.2 = 162 tokens, roughly 7% of the 2,448 you would pay for the full screen.
Switch resolutions in stages
Separate the step where you check the overall structure from the step where you inspect details, and use a different setting for each.
- For the overall layout, use
detail: low(at most 308 tokens regardless of input size) or resize to about 960 px on the long edge before sending - When you need small text or fine details, crop the relevant region from the original and send it as a follow-up at
detail: originalor at full resolution
Stitch multiple images into one
On the old GPT-4o tile model, every image carried an 85-token base, so stitching many small images into one amortized that overhead dramatically. On the current patch model, per-image overhead is much smaller: the savings reduce to the ceil() rounding across many tiny images.
- Ten 200×200 icons sent separately: ceil(ceil(200/32)² × 1.2) × 10 = ceil(49 × 1.2) × 10 = 59 × 10 = 590 tokens
- The same ten icons stitched into a 2×5 grid at ~1,000×400: ceil(32 × 13 × 1.2) = 500 tokens
Stitching still helps when you have many small images (icon catalogs, sequential screenshot comparisons), but the effect is modest compared with the old tile model. Watch the 30,000-patch per-image cap if you combine too much into one image.
Automate preprocessing with a command
ImageMagick can process images automatically before you send them. ImageMagick 7 uses the magick command; ImageMagick 6 uses convert.
# Trim surrounding margins
magick input.png -trim +repage output.png
# Shrink to fit within 960x540 (images already smaller are not enlarged)
magick input.png -resize '960x540>' output.png
# Append several images vertically
magick a.png b.png c.png -append combined.png
# Stitch four images into a 2x2 tile
magick a.png b.png c.png d.png -tile 2x2 -geometry +4+4 tiled.pngCombining steps:
magick screenshot.png \
-trim +repage \
-resize '960x540>' \
-strip \
context.pngThe -trim option decides what counts as margin from the color at the edges of the image. If the background is not a single color, it can remove parts you need, so check the result before you use it.
Do not keep the image in the running history
In a Codex session, an image you have sent stays in the conversation history and is included in every subsequent turn. If you paste a 2,448-token image on turn 1 of a 10-turn session, that image is included in the context on every one of those turns.
Once you have extracted what you need from the image, write the findings into a text note (AGENTS.md, .codex/notes/*.md, and so on) and avoid resending the same image. If a detail becomes relevant later, crop that region and send it again on its own.
For Playwright-driven Codex pipelines that produce screenshots on every step, building a diff step into the preprocessing keeps the per-turn image cost flat.
Where to start by input type
| Input | First thing to try |
|---|---|
| Web app screenshot (overview) | detail: low or resize to about 960 px on the long edge |
| Web app screenshot (close-up) | Crop and send at detail: original |
| Design mockup | Shrink the whole image, supplement with structured data for important UI elements |
| Flowchart | Replace with Mermaid or SVG source |
| Terminal error | Replace with the text log |
| Chart | Replace with the underlying numeric data (CSV or JSON) |
| Photograph | Resize to the smallest size that answers the question |
| UI before/after | Send only the diff region |
| Many logos or icons | Stitch into a single tiled image |
| Text or tables inside a PDF | Extract to text, Markdown, or CSV |
| OCR or small-text reading | Use detail: original |
Extra levers when you call the OpenAI API directly
If you call the OpenAI API (Responses API or Chat Completions API) directly rather than through Codex CLI, you have options beyond the detail parameter.
service_tierfor trading latency against price (flex processing and similar tiers)- Batch API for a 50% discount when you can wait
- Reuse
file_idreferences instead of re-uploading the same image (this saves transfer, not image tokens, which are billed the same on every call)
These are not always exposed through Codex CLI, so for workflows that need this level of control, wrapping the OpenAI API with your own thin layer gives you more room to tune.
In practice, four habits remove most of the waste: pick detail: low / high / original to match the task; crop; replace what can be expressed as text or structured data; and do not resend the same image.
The opposite failure mode matters too: cutting images too aggressively leads to follow-up questions and resends that cost more context than sending a slightly larger image once. The reliable way to tune this is to run the same image and question at a few resolutions and detail modes, then compare the token count against the accuracy of the answer. What you actually want to minimize is the total tokens spent to complete one task, not the tokens spent on a single image.
That’s all from mapping Codex’s current GPT-6.1 / GPT-6 / GPT-5.6 vision models to the 32×32 patch math, and cutting what you send through detail: low, cropping, downscaling, and keeping images out of history, from the Gemba.