Home / Compare / Puppeteer

Puppeteer Alternative

Same headless Chrome output, none of the browser babysitting. HTML to Image replaces self-hosted Puppeteer for screenshot and image generation workloads.

Disclosure: we built HTML to Image. Puppeteer is excellent open-source software; this page is about whether you should run it yourself just to make images.

Factor Puppeteer (self-hosted) HTML to Image
Cost to startFree (open source)$0 to start — 25 renders/month free
Infrastructure to runYour servers or Lambda, plus ChromeNone — hosted API
Ongoing maintenanceChromium updates, dependencies, memoryNone
Rendering engineHeadless ChromeHeadless Chrome
JavaScript executionYesYes
Scaling & concurrencyBrowser pools and queues you buildHandled by the API
Named templatesNo25
CDN-hosted outputNo — you store and serve outputYes — every render returns a CDN URL
Best forfull browser automation: testing, crawling, complex interactionsrendering images without owning browser infrastructure

Should you build or buy?

Keep Puppeteer when the browser is the point. Multi-step automation, authenticated crawling, end-to-end tests and bespoke PDF pipelines need a programmable browser, and Puppeteer is the standard tool for that. If screenshots fall out of automation you already run and maintain, there is nothing to migrate.

Buy the API when the browser only exists to produce images. That is the trap: the screenshot code takes an afternoon, then the browser needs somewhere to live. On Lambda that means special Chromium builds, layer size limits and slow cold starts — we wrote up the whole saga in Replacing Puppeteer on AWS Lambda for screenshots. On servers it means memory headroom, crash recovery, process reaping and a redeploy for every Chromium security update. HTML to Image is the same Chrome behind a single curl call, with the output already hosted on a CDN.

Where HTML to Image wins

Zero infrastructure. No Chrome binary, no Docker image gymnastics, no @sparticuz/chromium version-matching, no memory tuning, no zombie processes. One HTTP call replaces the launch-navigate-screenshot-close-upload pipeline and everything that keeps it alive.

Scaling is someone else's job. Concurrency, queueing and retries are handled behind the endpoint. A traffic spike that would exhaust a browser pool is just more API calls, and webhook delivery covers async batches.

More than raw captures. Twenty-five named templates render invoices, OG images and social cards from a JSON payload — jobs that in Puppeteer-land each mean writing and hosting an HTML page first. Output lands on our CDN with a stable URL, replacing the S3 upload step.

Where Puppeteer wins

Full programmability. Clicking, typing, waiting on arbitrary conditions, intercepting requests, running behind logins — a real automation API that an image endpoint does not attempt to be.

No per-render cost and no external dependency. At sustained very high volume with engineering time already sunk into a solid pool, the marginal render is nearly free and everything stays inside your network. You pay in upkeep instead of credits.

The same screenshot, both ways

javascript
// Puppeteer — plus Chrome, hosting and upkeep
const puppeteer = require('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: 'shot.png' });
await browser.close();
// ...then upload shot.png somewhere yourself
bash
# HTML to Image — same Chrome, no browser to run
curl -X POST https://app.html2img.com/api/screenshot \
  -H 'X-API-Key: your-key-here' \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://example.com","width":1280,"height":720}'
# Response includes a CDN-hosted URL

The mapping is direct. page.goto() becomes the url field, the viewport becomes width and height, page.setContent() becomes the HTML endpoint, and waitUntil or selector waits become ms_delay and wait_for_selector. Any language that can make an HTTP request qualifies — no Node.js required.

Total cost of ownership

Puppeteer's sticker price is zero and its running cost is not. Budget for Chrome's memory appetite (500MB to 1GB per instance), the pool-and-queue code around it, cold-start pain on serverless, and a redeploy on every Chromium security release. If a developer spends even a few hours a month on that plumbing, it costs more than our 10,000-render plan. Self-hosting starts to pay for itself only at sustained high volume with the engineering already amortised — and if that is you, fair enough.

Further reading

We have written up the sharp edges in detail:

FAQ

Is the output actually the same as Puppeteer?

Yes. Both render in headless Chrome, so the pixels match what page.screenshot() produces for the same markup and viewport. The difference is everything around the render: with the API there is no browser binary to ship, no --no-sandbox flags, no memory ceiling to tune and no zombie Chrome processes to reap.

What does Puppeteer actually cost to run?

The library is free; the total isn't. Chrome wants roughly 500MB to 1GB of memory per instance, Lambda deployments need special builds like @sparticuz/chromium that lag Chrome releases and inflate cold starts, and every Chromium security release is a redeploy. Most teams also end up writing pooling, retry and timeout logic. Our article on replacing Puppeteer on AWS Lambda walks through the full list. Against that engineering time, $9 a month for 1,000 renders is usually the cheap option.

When is Puppeteer the right choice?

When you need a programmable browser rather than an image. Multi-step interactions, logging into apps, crawling, PDF pipelines with custom logic, or integration testing — that is what Puppeteer is for, and an image API does not replace it. If screenshots are a side-effect of automation you are already running, keep them in Puppeteer.

How do I migrate a Puppeteer screenshot job?

Map the page.goto() URL and viewport to the Screenshot endpoint's url, width and height fields, or send the HTML you were feeding page.setContent() to the HTML endpoint. waitUntil and selector waits map to our ms_delay and wait_for_selector parameters. The response is a CDN URL, which usually replaces your S3 upload step too.

Retire your browser fleet

The free tier covers 25 renders a month with no credit card. Point your existing Puppeteer job at the API and compare the output.

Templates you can render with HTML to Image

Jobs you'd otherwise hand-build pages for. Twenty-five pre-built designs rendered from JSON — no HTML, no browser, no hosting.

See every template in the gallery

More comparisons