Back to blog
EngineeringArchitecturePerformanceCaching

Anatomy of a capture request: from edge to pixels

What happens between POST /capture and the file URL you get back - validation, dedup, caching, browser selection, and the post-processing that runs after you already have your response.

Thien Nguyen
Thien Nguyen
Creator & Maker
· Sep 2, 2026· 3 min read

A screenshot API looks simple from the outside: send a URL, get an image. Behind that one request sits a small pipeline that decides whether a browser needs to launch at all, which browser to use, and what to do after the pixels exist. This post walks through it in order.

1. Validation at the edge

Every request lands on a Cloudflare Worker first. The body is validated against the same Zod schema that powers our docs and the dashboard playground, so a typo in viewport.width fails in a few milliseconds with a precise error instead of burning a browser session.

{
  "url": "https://example.com",
  "format": "webp",
  "viewport": { "width": 1440, "height": 900 },
  "isFullPage": true
}

2. A content-addressed cache key

Next we hash the parameters that affect the output - URL, format, viewport, color scheme, blocking options and so on - into a cache key. Two requests that would produce the same pixels get the same key, regardless of JSON key order.

3. Deduplication

If an identical capture is already in flight, we do not start a second one. The second request waits for the first to finish and receives the same result. This matters more than you would think: link-preview bots and retrying clients often fire the same URL several times within a second.

4. Cache lookup

When responseCache.enabled is true and a fresh result exists, we return it straight from storage. No browser, no queue, and the response tells you so with fromCache: true.

5. Auth, rate limits and quota

Only now do we check the API key, the per-tier rate limit, and your token balance. Doing the cheap checks first keeps the hot path fast; doing auth before any expensive work keeps it safe.

6. Picking a browser

Captures are rendered with Playwright on a pool of browser providers. The queue manager picks one based on your plan, current load, the region you asked for, and features like antiBot that need a stealth-capable provider.

7. Respond first, then clean up

As soon as the file exists we respond with its CDN URL:

{
  "success": true,
  "error": null,
  "data": {
    "uuid": "8a4e6d02-1c3b-4f5a-b7e9-0d2c4a6f8e13",
    "fileUrl": "https://cdn.snapopa.com/...",
    "fromCache": false,
    "tokenCost": 1,
    "processingTimeMs": 1840
  }
}

Storing the file, recording usage, syncing your capture history and clearing the dedup marker all happen after the response is sent. You are not waiting on bookkeeping.

What this buys you

  • Invalid requests fail fast and cost nothing.
  • Duplicate and cached requests skip the browser entirely.
  • The expensive step - rendering - only happens when it has to.

If you want to see the parameters that feed the cache key, the API reference lists every one of them.

Try Snapopa

Reading about screenshots? Try the API.

100 free tokens on signup. No credit card. One request is all it takes.

$ curl https://api.snapopa.com/capture \
    -H "Authorization: Bearer sk_•••" \
    -d '{"url":"https://stripe.com"}'

✓ 200 OK
{ "data": { "fileUrl": "https://cdn.snapopa.com/…" } }