Token-frugal screenshots for AI agents. Capture, shrink, and hand them to Claude/GPT/Gemini at a fraction of the vision-token cost.
Project description
tinyscreenshot
Token-frugal screenshots for AI agents. Hand Claude / GPT / Gemini a screenshot that costs ~540 tokens instead of ~2100, without losing a single word of information.
The problem
Every screenshot you hand to an LLM burns tokens. Anthropic meters vision at roughly
tokens ≈ (width × height) / 750
A raw retina screenshot hits the 1.6-megapixel server-side cap and costs ~2100 tokens. Multiply by dozens of captures in an agent session and you're paying real money to make the model squint at pixels it didn't need.
The fix is obvious once you see it: downsize before you send. The hard part is doing it fast, cross-platform, with the right defaults, and without losing the text you actually wanted the model to read.
That's tinyscreenshot.
The same screen, four token budgets
Each of these is a processed capture of the exact same Gmail window. Claude reads all four — but the last one costs 16× fewer tokens than the first.
| 800 px · grey · ~540 t | 640 px · grey · ~340 t | 400 px · grey · ~138 t | 200 px · mono · ~34 t |
|---|---|---|---|
| Full legibility. Reads every bullet, every sidebar label, every menu-bar icon. Recommended default. | Still fully readable. Best sweet spot if you want the tiniest capture that still reads prose. | Prose survives. Bullet points still readable; small UI chrome starts to blur. Great for "did the bug happen?" checks. | Presence only. You can tell it's Gmail with an open email; no text. Perfect for "is the modal still open?" yes/no. |
At every size, color mode does not affect token cost — only pixel count does.
greycosts the same ascolorbut stays crisper after resize.
30-second install
# isolated (recommended)
pipx install tinyscreenshot
# or:
pip install --user tinyscreenshot
# or one-line curl:
curl -fsSL https://raw.githubusercontent.com/franzenzenhofer/tinyscreenshot/main/scripts/install.sh | bash
Then, if you use Claude Code, wire up the bundled skill so Claude reaches for this tool automatically:
tinyscreenshot install-skill --force
30-second use
$ tinyscreenshot main
captured: /tmp/tiny-shots/20260423-101802-main.png
source: 1512x982 (main display)
output: 800x520 grey +sharpen [png]
tokens: ~554 (saved ~1425t vs full source)
size: 80.7 KB
/tmp/tiny-shots/20260423-101802-main.png
stdout: the path. stderr: a human-readable report. Pipe the path into your next step.
# capture and open in the default viewer
open "$(tinyscreenshot main)"
# capture a single app, 1-bit mono for a crisp terminal shot
tinyscreenshot app Ghostty -w 640 -c mono
# pixel-exact rectangle
tinyscreenshot region 0,0,1200,800 -w 400
# let me draw a selection
tinyscreenshot interactive
What it captures
| Mode | What you get |
|---|---|
tinyscreenshot main |
Primary display |
tinyscreenshot all |
Every display stitched into one image |
tinyscreenshot display 2 |
A specific display (run tinyscreenshot list to see the indexes) |
tinyscreenshot window |
Click-to-select window |
tinyscreenshot app "Google Chrome" |
The frontmost window of a named app — native resolution, no search |
tinyscreenshot region 0,0,1200,800 |
A pixel-exact rectangle in screen coordinates |
tinyscreenshot interactive |
Draw your own selection |
tinyscreenshot list |
Print display indexes, sizes, and full-res token cost |
The defaults are opinionated on purpose
- Width: 800 px. Chosen to land at ~540 tokens — the lowest number at which arbitrary modern UIs (Gmail, VS Code, Figma, Chrome DevTools) still read cleanly. Use
-w 640for compact,-w 1280for code-dense inspection. - Color:
grey. Identical token cost tocolor, but no chroma fringing on thin text after Lanczos downscale. Use-c coloronly when hue matters. - Sharpen: on (auto for grey/mono, off for color). A light unsharp mask recovers the edge contrast lost during resize. It's the difference between "I can read this" and "I can read this easily."
- Output:
/tmp/tiny-shots/<timestamp>-<slug>.png. Predictable, scriptable, disposable.
All overridable, none required.
How much does it really save?
Real example: one agent session that took eight screenshots of a web app during a debugging loop.
| Approach | Tokens per shot | Per session (8) | Per 1000 sessions |
|---|---|---|---|
| Raw retina capture | ~2100 | 16 800 | 16.8 M |
tinyscreenshot main -w 1280 |
~1365 | 10 920 | 10.9 M |
tinyscreenshot main (default) |
~540 | 4 320 | 4.3 M |
tinyscreenshot main -w 400 |
~138 | 1 104 | 1.1 M |
At $15/M input tokens for Claude Sonnet, the default setting saves you ~$190 per 1000 sessions vs raw retina captures — for free, with identical information.
Decision matrix (for humans and agents)
| Task | Recommended flags | Why |
|---|---|---|
| "What's on my screen?" | main -w 800 -c grey |
Default, reads everything |
| "Is the progress bar still spinning?" | main -w 400 -c grey |
Presence check — 4× cheaper |
| "Read the code in my editor" | main -w 1280 -c grey |
Dense text, still 35% off retina |
| "Show Claude this specific app" | app <Name> -w 800 |
Native-pixel window capture, ignores other windows |
| "The left monitor" | display <N> -w 800 |
Pick a specific physical display |
| "Just this panel" | region x,y,w,h -w 800 |
Pixel rectangle |
| "Terminal-only output" | ... -w 640 -c mono |
1-bit dither is crisper on bitmap glyphs |
Platform support
| Platform | Status | Notes |
|---|---|---|
| macOS (Apple Silicon + Intel) | ✅ every mode | Grant Screen Recording to your terminal the first time |
| Linux X11 | ✅ every mode | Install maim + xdotool (or scrot as fallback) |
| Linux Wayland | ✅ every mode | Install grim + slurp |
| Windows | 🚧 planned v0.2 |
Under the hood
mssfor fast, dependency-free screen capture on every platform.Pillowfor resize, colorspace conversion, and unsharp-mask — no ImageMagick dependency.- macOS
screencapture/ Linuxmaim·scrot·grimfor window and single-app capture (native window IDs). - A ~100-line token-cost model implementing Anthropic's public pricing formula.
- Zero network I/O. Screenshots live on your disk, nowhere else.
FAQ
Does color mode change token cost? No. The Anthropic vision model rasterizes your image before metering — it only sees pixels. grey and color at the same resolution cost the same number of tokens. grey is picked as the default because it stays sharper at small sizes.
Does file format change token cost? No. PNG / JPEG / WebP all rasterize to pixels. Format only matters for your own disk space and upload bandwidth.
What's the maximum useful resolution? Anthropic caps images at 1.6 MP server-side, so capturing retina@2x is money down the drain. tinyscreenshot never exceeds your requested width and never upscales.
Why isn't color the default for pretty screenshots? Because you're sending the image to a language model, not to a human. The model sees pixels regardless of mode, and greyscale downsamples cleaner. If you want a screenshot to paste into a slide deck, pass -c color.
Can I use it from Python directly? Yes:
from tinyscreenshot.capture import capture_main
from tinyscreenshot.process import ProcessOptions, process
img = process(capture_main().image, ProcessOptions(width=800, color="grey"))
img.save("out.png")
Development
git clone https://github.com/franzenzenhofer/tinyscreenshot && cd tinyscreenshot
python -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
pytest # 28 tests, unit + CLI
ruff check src tests # lint
python experiments/run_matrix.py --capture # Pareto experiment
Credits & licence
MIT. Built by Franz Enzenhofer as a weekend-scale "why is every screenshot wasting tokens?" problem. Contributions welcome — especially Windows support.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tinyscreenshot-0.1.0.tar.gz.
File metadata
- Download URL: tinyscreenshot-0.1.0.tar.gz
- Upload date:
- Size: 198.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad94eefd150c7f185489aef8298ac877c0ec6309626012ddc62d134bc434e550
|
|
| MD5 |
74ca1df6826bb0fc8787600c7b311499
|
|
| BLAKE2b-256 |
ce0cbc7e447e228a416661e2f8dcfbb9491615c2c04239c9133c0c33fcd33bef
|
Provenance
The following attestation bundles were made for tinyscreenshot-0.1.0.tar.gz:
Publisher:
release.yml on franzenzenhofer/tinyscreenshot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tinyscreenshot-0.1.0.tar.gz -
Subject digest:
ad94eefd150c7f185489aef8298ac877c0ec6309626012ddc62d134bc434e550 - Sigstore transparency entry: 1361536194
- Sigstore integration time:
-
Permalink:
franzenzenhofer/tinyscreenshot@45556c772f861ca55bf70b2edec937b23cebb427 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/franzenzenhofer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@45556c772f861ca55bf70b2edec937b23cebb427 -
Trigger Event:
push
-
Statement type:
File details
Details for the file tinyscreenshot-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tinyscreenshot-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
983533766e6d5fda8abe6f0b1e3ed8f45ac94ccf4727b72e8179c9eea09379b0
|
|
| MD5 |
e680d3620677a9ab4939cf9cbaed6779
|
|
| BLAKE2b-256 |
a541f501c8620981e901d51552935e08a55eff77d0aa568f1a48f73b49f41d4a
|
Provenance
The following attestation bundles were made for tinyscreenshot-0.1.0-py3-none-any.whl:
Publisher:
release.yml on franzenzenhofer/tinyscreenshot
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tinyscreenshot-0.1.0-py3-none-any.whl -
Subject digest:
983533766e6d5fda8abe6f0b1e3ed8f45ac94ccf4727b72e8179c9eea09379b0 - Sigstore transparency entry: 1361536201
- Sigstore integration time:
-
Permalink:
franzenzenhofer/tinyscreenshot@45556c772f861ca55bf70b2edec937b23cebb427 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/franzenzenhofer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@45556c772f861ca55bf70b2edec937b23cebb427 -
Trigger Event:
push
-
Statement type: