DEV Community

rastersly
rastersly

Posted on Originally published at rasterly.dev

Screenshot APIs in 2026: what you're actually paying for

Disclosure up front: I build one of these APIs (rasterly). I've tried to keep the comparison fair and the numbers checkable — call out anything that reads as a plug.

Every few months someone on my team says "let's just run headless Chrome ourselves." Two weeks later there's a memory-leak cron, a font that renders as tofu in the container, and a Chromium version pinned three releases back because upgrading broke PDFs. So most teams end up renting the render instead. This post is about what you're actually paying for when you do.

What a "screenshot" really is

A screenshot API does one mechanical thing: boot a headless browser, navigate to a URL, wait for the page to settle, and hand back the pixels (or a PDF, or the extracted text). The interesting part is the word warm. A cold browser start is 300–800ms of pure overhead. A warm browser that's reused across requests turns a render into roughly one second of CPU — and that single fact is why prices are all over the map. Some vendors price on that cost. Some price on "it's a magic image service" and charge accordingly.

That's the lens for the whole market: is this priced like a CPU-second, or like a SaaS seat?

The runnable version

Every hosted option is basically the same shape — a URL, some options, a key. Here's the same job three ways:

# curl
curl "https://api.rasterly.dev/v1/screenshot?url=https://stripe.com&full_page=true&format=png" \
  -H "X-Api-Key: sk_live_..." -o shot.png
Enter fullscreen mode Exit fullscreen mode
// Node — save a full-page PNG
import { writeFile } from "node:fs/promises";

const res = await fetch(
  "https://api.rasterly.dev/v1/screenshot?" + new URLSearchParams({
    url: "https://stripe.com", full_page: "true", format: "png", scale: "2",
  }),
  { headers: { "X-Api-Key": process.env.RASTERLY_KEY } }
);
await writeFile("shot.png", Buffer.from(await res.arrayBuffer()));
Enter fullscreen mode Exit fullscreen mode
# Python
import os, requests

r = requests.get(
    "https://api.rasterly.dev/v1/screenshot",
    params={"url": "https://stripe.com", "full_page": True, "format": "png"},
    headers={"X-Api-Key": os.environ["RASTERLY_KEY"]},
)
open("shot.png", "wb").write(r.content)
Enter fullscreen mode Exit fullscreen mode

Swap the base URL and header name and this is Urlbox, ScreenshotOne, ApiFlash or Browserless too. Migration between them is mostly a find-and-replace, which is worth remembering when a vendor's price creeps up.

The five things that actually matter

Forget the feature matrices for a second. In production these are what bite:

  1. Warm vs cold. Ask (or benchmark) whether renders reuse a browser. It's the difference between ~1s and ~3s per call, and it shows up directly in your bill.
  2. Full-page + retina done right. full_page=true and scale=2/3 sound trivial; they're where lazy-loaded images and sticky headers break. Test on a real, heavy page, not example.com.
  3. PDF page control. If you generate documents, you need @page, margins, and break-inside: avoid. Chromium honours these; lighter HTML-to-PDF tools mostly don't, and that's usually what makes a PDF look wrong.
  4. SSRF protection. A "render any URL" endpoint is an SSRF cannon if it isn't locked down. Whatever you use, confirm it refuses localhost, private ranges, and 169.254.169.254. If you self-host, this is on you.
  5. Pricing units. Per-render, per-1,000, monthly tiers, credits-that-cost-different-amounts-per-feature… normalize everything to dollars per 1,000 renders at your real volume before comparing. It's often a 10x spread.

Rough cost intuition

I won't quote competitors' live prices — they change, and you should check them yourself — but the shape is consistent: category-priced screenshot APIs tend to land in the low single-digit dollars per 1,000 renders at mid volume, sometimes higher. A CPU-cost-priced one lands in the cents. On rasterly that's $0.58 per 1,000 at the Growth tier and a free 100/month with no card; the point isn't the specific number, it's that a one-second render can be cents, so if you're paying dollars, know why.

Self-hosting Puppeteer/Playwright looks free until you price the cold starts, the memory headroom for full-page captures, the base image with the right fonts and codecs, and the human who babysits it. For a low, spiky volume it can win. For steady volume it usually doesn't.

How to actually pick

  • Just need a picture of a URL? Any of them work; sort by dollars-per-1,000 at your volume and by whether full-page/retina look right on your worst page.
  • Generating documents/invoices? Prioritise PDF page-control and font handling.
  • Feeding an LLM or agent? You'll want the page as Markdown/JSON too, not just an image — check whether one key covers screenshot + read/extract, or whether you're bolting on a second vendor.
  • Tiny or bursty volume? Self-hosting or a generous free tier may beat any paid plan.

See it before you sign up

The most useful thing I added to my own site is a page that just renders your URL live and shows the cost next to whatever vendor you're on, no signup:

rasterly.dev/proof?url=your-site.com — swap in your own domain.

If you're evaluating any screenshot API, do that with all of them: throw your ugliest real page at each, full-page, and compare the output and the per-1,000 side by side. The winner is usually obvious once you stop reading marketing pages and start rendering your own worst case.

Happy to answer questions on the rendering pipeline, PDF gotchas, or the pricing math in the comments.

Top comments (0)