A hosted alternative to Puppeteer

Puppeteer is Google's Node.js library for driving Chrome over the DevTools Protocol. It is excellent, widely used, and the right tool for a great many jobs. Taking screenshots in production is the one where the library is the easy part and everything around it is not.

The same screenshot, both ways

Puppeteer (self-hosted)

import puppeteer from "puppeteer";

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 720 });
await page.goto("https://example.com", { waitUntil: "networkidle0" });
await page.screenshot({ path: "out.png", fullPage: true });
await browser.close();

// Still to solve: where this runs, how many at once, what happens when
// the renderer dies, fonts in the container, and the ~400 MB Chromium
// download in your CI 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:

WhatMeasuredWhy it matters
Container image3.97 GBPulled on every deploy, cached on every CI runner, stored in every registry.
Chromium on disk656 MBDownloaded by playwright install; a cold CI cache pays for it every time.
Memory ceiling3 GiBA full-page capture of a heavy site is the spike that finds this limit.
Concurrent captures3Throughput against OOM risk. Raising it is not free.
Capture timeout30 sLong 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 Puppeteer if…

Use a hosted API if…

Frequently asked questions

Does getSnap.dev use Puppeteer?

No, it runs Playwright, which drives the same Chromium engine. From the outside the rendering is equivalent; the difference is that the browser, its memory ceiling and its failure modes are ours to operate rather than yours.

Is getSnap.dev a replacement for Puppeteer?

For taking screenshots, yes. For everything else Puppeteer does, no - and the "stay with Puppeteer" 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

Related reading

Stop shipping a browser

100 captures a month on the free tier. No credit card required.

Get Free API Key