ScreenshotOne

screenshotone.comcontributed by Samuele Ongaro

YES

Replaceable in one session with an AI coding agent.

A screenshot API with the awkward parts handled: cookie banners blocked, ads hidden, lazy images triggered and full-page capture that works.

Promptfree, for everyone, and the only version there is
Build me a screenshot API that replaces ScreenshotOne: a URL in, a clean image out, with the cookie banners and the lazy images dealt with.

STACK
- Node 20+ with Fastify
- SQLite through better-sqlite3 for jobs and cache metadata
- Playwright with Chromium, in a pool of long-lived browser contexts
- sharp for post-processing
- Caddy in front

THE DATA MODEL
- jobs: id, url, url_hash, options_hash, status, output_path, bytes, width, height, ms, error, created_at, expires_at
- cache: key, output_path, created_at, hits, last_hit_at — keyed on the URL plus every option that affects the image
- api_keys: id, name, hash, rate_per_minute, concurrent_limit, monthly_bytes, revoked_at
- blocklists: id, kind, pattern, source, updated_at — the banner and advert rules
- usage: id, key_id, bytes, ms, at

THE HARD PARTS, WHICH ARE ALL ABOUT THE PAGE NOT COOPERATING
- Cookie banners. Inject the standard consent-manager opt-out rules at document start, and additionally hide known banner selectors from a maintained list. Where a consent framework is present, set its stored preference before the page runs rather than clicking a button that may not exist
- Adverts and trackers blocked by request interception against a filter list, which also makes every capture faster and more deterministic
- Lazy images. Scroll the full height in steps, wait for network idle at each, then scroll back to the top before capturing. Also force-load anything with a loading attribute and wait for images to decode
- Animations and video: disable animations with a stylesheet injection, and set the media to a fixed frame, or the same URL produces a different image every time
- Fonts: wait for the document's font loading to settle, or text renders in a fallback and the screenshot looks wrong in a way nobody can put their finger on
- Sticky headers on a full-page capture, which repeat down the image. Detect fixed-position elements and hide them after the first viewport

CAPTURE OPTIONS
- Viewport width and height, device scale factor, and named device presets
- Full page, viewport only, or a specific element by selector
- Format: PNG, JPEG, WebP, or PDF, with quality
- Dark or light colour scheme, a chosen language and time zone, and a geolocation if the page needs one
- A delay, or a wait for a selector, or a wait for network idle — with a hard timeout over all of them
- Custom CSS and JavaScript injected before capture, which is the escape hatch for everything not covered above
- Blocking a list of selectors, and a cookie or header set for authenticated pages

THE API
- GET with signed parameters, so an image tag can be the whole integration
- POST for the complex cases, synchronous under a deadline and asynchronous with a webhook above it
- Cache by URL plus options hash: the same request returns the same stored file rather than launching a browser. This alone removes most of the load, and the cache lifetime is a parameter
- Idempotency keys, and errors that name the cause — a timeout, a navigation failure, a selector never appearing

RUNNING BROWSERS SAFELY, WHICH IS THE OPERATIONAL WHOLE OF IT
- A pool of contexts in a small number of browser processes, recycled after a fixed number of captures because Chromium leaks
- A hard concurrency cap. Each context is a hundred-odd megabytes and unbounded parallelism takes the machine down
- A wall-clock timeout on every capture, enforced by killing the context, not by hoping
- The browser in a container with no access to the host, non-root, with a seccomp profile
- This service fetches arbitrary URLs on request. Refuse private address ranges, link-local addresses and internal hostnames, resolve the name yourself and check the resolved address, and re-check after every redirect. Without that it is a server-side request forgery machine pointed at your own network
- A memory limit and a restart policy, because a browser will eventually misbehave

DELIVERY
- Images stored by content hash with immutable cache headers
- Optional post-processing with sharp: resize, crop, quality, format conversion, and a watermark if wanted
- A retention policy with a sweeper, and a disk watchdog that refuses jobs rather than filling the volume

OPERATIONS
- .env: DATABASE_PATH, STORAGE_PATH, BASE_URL, SIGNING_SECRET, MAX_CONCURRENCY, CAPTURE_TIMEOUT_MS, BLOCKLIST_URL
- Migrations on boot, each once
- The blocklists updated on a schedule, with the version recorded on each capture so a change in output is explicable
- Health endpoint that captures a local fixture page through the real path

WHAT MATTERS MOST
The request guard and the cache. Refuse internal addresses before anything else — this is the vulnerability class this product category is built on — then make the cache key exact, so the same request never launches a second browser.

Give me the repository, the container definition, migrations, .env.example, the blocklist updater, and a README with deploy steps behind Caddy and the network guard explained.

What you lose

  • Block lists that remove cookie banners and adverts from every screenshot, kept current
  • Browser capacity for a burst of requests
  • Device emulation presets already configured

If you would rather not build

  • Puppeteer, for the same job

What it costs

read from their page 15 Aug 2026

PlanBilled monthlyBilled yearlyLast read
—$17/mo—15 Aug 2026

Their pricing page is where these came from. Seeing a different price? Tell us.

The escape hatch

open source · no votes, no paid placement

Playwright

$0

Drives a real browser with good wait primitives for screenshots.

microsoft/playwrightfree · open source

browserless

$0

A self-hostable container exposing a browser over an API.

browserless/browserlessfree · open source

Why this verdict

our own opinion · changed only by a person

88/100

Verdict yes at 88. Playwright does the rendering; the wait sequence and the private-address block are the two things that make it usable and safe.

History

tracked since 10 Aug 2026 · nothing is ever overwritten

Interest · last 30 dayspeak 1/day
views0130 Aug4 Sept9 Sept14 Sept19 Sept24 Sept28 Sept
— views— prompt copies none yet— votes none yet

Questions about ScreenshotOne

answered from the record above

Is ScreenshotOne free?

No — the plan we track is $17 a month. Basic at around $17/month billed monthly for a fixed number of screenshots.

Can you replace ScreenshotOne by building your own?

YES. Replaceable in one session with an AI coding agent. Replacement score 88 out of 100, build time one session. Read what you lose before you decide.

How much does ScreenshotOne cost?

$17 a month on Basic — $204 a year. Recorded 10 Aug 2026.

What do you lose by replacing ScreenshotOne?

Block lists that remove cookie banners and adverts from every screenshot, kept current; Browser capacity for a burst of requests; Device emulation presets already configured. If any of those carry weight for you, keep paying.

Is there an open-source alternative to ScreenshotOne?

Yes: Playwright, browserless. The prompt on this page is for when you want it your way instead.

Related entries

same category first, most replaced first

All 56 in Dev tools

Not sending yet

Every week, something stops being worth paying for.

New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.

free forever · no tracking pixel · stored here, never passed to anyone

Esc