A hosted alternative to Playwright
Playwright is Microsoft's browser automation library, and it is what getSnap.dev runs internally — version 1.50 at the time of writing. So this page is not an argument that Playwright is the wrong tool. It is an account of what it costs to operate it as a service, written by people who do.
The same screenshot, both ways
Playwright (self-hosted)
import { chromium } from "playwright";
const browser = await chromium.launch();
const context = await browser.newContext({
viewport: { width: 1280, height: 720 },
});
const page = await context.newPage();
await page.goto("https://example.com", { waitUntil: "networkidle" });
await page.screenshot({ path: "out.png", fullPage: true });
await context.close();
await browser.close();
// npx playwright install chromium is a 656 MB install on disk here,
// inside a 3.97 GB image.
getSnap.dev
curl -X POST https://api.getsnap.dev/v1/screenshot \
-H "X-API-Key: sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "format": "png", "full_page": true}'
# -> {"url": "https://cdn.../screenshots/....png"}
What running it yourself costs
These are not estimates. They are measured from the getSnap.dev production deployment on 5 October 2026, which runs Playwright 1.50 on Chromium:
| What | Measured | Why it matters |
|---|---|---|
| Container image | 3.97 GB | Pulled on every deploy, cached on every CI runner, stored in every registry. |
| Chromium on disk | 656 MB | Downloaded by playwright install; a cold CI cache pays for it every time. |
| Memory ceiling | 3 GiB | A full-page capture of a heavy site is the spike that finds this limit. |
| Concurrent captures | 3 | Throughput against OOM risk. Raising it is not free. |
| Capture timeout | 30 s | Long enough for slow pages, short enough that a stuck one does not hold a worker. |
None of this is exotic. It is simply the part that does not appear in the five-line example on the library's front page.
What actually breaks when you run it yourself
Not a list of hypotheticals. Every one of these is fixed in getSnap.dev's source with a comment explaining the symptom, because each one reached production first.
Teardown that skips itself and leaks a renderer
The obvious cleanup is wrong:
} finally {
await page.close();
await context.close(); // never runs if the line above rejects
}
When the renderer has already died — "Target closed", an OOM on a
heavy full-page capture, the common cases — page.close()
rejects and the context is never closed. The orphaned context keeps its
renderer process alive on the shared browser until the container hits its
memory ceiling. Worse, the rejection propagates out of the
finally and replaces the real capture error, so your logs
name the wrong cause.
networkidle that never arrives
Waiting for the network to go quiet is the natural choice and it is a trap. Any page with long-polling, websockets or analytics beacons never goes quiet, so the capture runs to the full timeout and fails. You need a weaker condition available per request, and you need to decide which pages get which.
Options that contradict each other
Set quality on a PNG and Chromium throws
options.quality is unsupported for the png screenshots. Pass
a cookie with both a URL and a domain and you get
Cookie should have either url or path. These are easy to fix
once and easy to reintroduce, and they surface as a failed capture rather
than a validation error.
Capacity you have to pick in advance
This deployment runs 3 concurrent workers against a 3 GiB ceiling with a 30-second capture timeout. Those numbers are a compromise between throughput and being OOM-killed, and they are yours to tune, re-tune, and get paged about.
Which should you use?
Stay with Playwright if…
- You are writing tests. Playwright is a test framework as much as a browser driver, and a screenshot API replaces none of that.
- You need the trace viewer, test runner, fixtures or parallel sharding.
- You need to interact with the page in ways no request body can express.
- You are happy operating it — it is genuinely good software, and this page is not a claim otherwise.
Use a hosted API if…
- You only ever call
page.screenshot()at the end, and everything before it is boilerplate. - The operational surface — image size, memory ceiling, worker count, renderer leaks — is cost without benefit to you.
- You want the same capture from several services without each one shipping a browser.
- You want caching and a CDN in front of captures you take repeatedly.
Frequently asked questions
If getSnap.dev is Playwright, why not run Playwright myself?
You can, and for testing you should. The difference is everything around the call: a 3.97 GB image, a 656 MB Chromium install, a 3 GiB memory ceiling, three concurrent workers, a 30 second timeout, renderer leak handling and a cache. That is what you are paying someone else to operate.
Is getSnap.dev a replacement for Playwright?
For taking screenshots, yes. For everything else Playwright does, no - and the "stay with Playwright" list above is there because those cases are real.
Do I need to run or maintain a browser?
No. Chromium runs server-side on getSnap.dev and you receive a finished image, PDF or video. No binary in your image, no memory ceiling to tune, no renderer leaks.
Is there a free tier?
Yes - 100 captures a month at 5 requests a minute, no credit card. Paid plans start at $9/month for 5,000 captures.
Next steps
- Playground — take a capture in the browser, no signup
- Code examples — every option, with cURL, Node.js and Python
- Quick starts for Python, Node.js, PHP, Ruby, Go, Java, C#
- Already paying for a screenshot API? Compare the hosted options
Related reading
- Where the DevTools screenshot stops working — the manual and self-hosted options, compared honestly
- Puppeteer vs Playwright in 2026 — how the two libraries actually differ
Stop shipping a browser
100 captures a month on the free tier. No credit card required.
Get Free API Key