Keep Playwright for testing. For production screenshots and image generation, HTML to Image delivers the same Chrome output without the browser fleet.
Disclosure: we built HTML to Image. Playwright is excellent open-source software; this page is about whether you should run it in production just to make images.
| Factor | Playwright (self-hosted) | HTML to Image |
|---|---|---|
| Cost to start | Free (open source) | $0 to start — 25 renders/month free |
| Infrastructure to run | Your servers or CI, plus browser binaries | None — hosted API |
| Ongoing maintenance | Browser downloads, version pinning, memory | None |
| Rendering engine | Chromium (plus Firefox and WebKit) | Headless Chrome |
| JavaScript execution | Yes | Yes |
| Scaling & concurrency | Browser contexts and pools you manage | Handled by the API |
| Named templates | No | 25 |
| CDN-hosted output | No — you store and serve output | Yes — every render returns a CDN URL |
| Best for | cross-browser end-to-end testing and automation | rendering images without owning browser infrastructure |
Keep Playwright where it belongs: end-to-end tests, cross-browser verification and browser automation. It is arguably the best tool ever built for that job, and nothing on this page argues otherwise.
Buy the API when Playwright has crept out of the test suite and into production image generation. The pattern is common: page.screenshot() worked in CI, so it became the OG image generator. Now production carries browser binaries, version pinning, memory headroom and process cleanup for a job that is one HTTP call. The operational bill is the same one we documented for Puppeteer on AWS Lambda — Playwright changes the API, not the physics. HTML to Image gives you the identical Chrome-rendered pixels from a single curl call, hosted on a CDN.
No browsers in production. Playwright wants its own patched browser builds shipped wherever it runs, kept in step with the library version. Removing that from your deploy artefact shrinks images, speeds cold starts and deletes a whole class of "works locally, breaks in CI" issues.
Concurrency without a pool. Parallel renders are parallel HTTP requests. No context juggling, no queue tuning, no memory-per-browser arithmetic, and webhooks for async batches.
Templates and hosting included. Twenty-five named templates cover invoices, OG images and social cards from JSON, and every render returns a CDN URL — two jobs (design hosting, artefact storage) that self-hosting leaves with you.
Everything test-shaped. Assertions, tracing, multi-browser engines, auto-waiting, network interception, authenticated flows. If the job is verifying behaviour rather than producing an image, Playwright is the right tool and an API is not.
No per-render cost inside infrastructure you already run. If a hardened browser fleet exists anyway and volume is very high, the marginal screenshot is effectively free — you have simply chosen to pay in maintenance rather than credits.
// Playwright — plus browser binaries, hosting and upkeep
const { chromium } = require('playwright');
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: 1280, height: 720 },
});
await page.goto('https://example.com');
await page.screenshot({ path: 'shot.png' });
await browser.close();
// ...then upload shot.png somewhere yourself # 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 waits become ms_delay and wait_for_selector. Works from any language with an HTTP client — Python and Java teams do not need the Node toolchain.
Free software, paid plumbing. Browser binaries in every deploy artefact, a rebuild per browser security release, memory headroom per instance and pool management under load. A few developer-hours a month on that upkeep costs more than our 10,000-render plan at $60. The build case holds at sustained high volume on infrastructure you already maintain for testing — if that is you, the render pipeline is a marginal add and you should probably keep it.
Because its page.screenshot() is so good that teams quietly promote it from the test suite into production image generation: OG images, PDFs-as-screenshots, email previews. That works, but it means running browser infrastructure in production for a job an HTTP call covers. This page is about that workload, not about testing — for tests, keep Playwright.
Yes — HTML to Image renders in Chrome only. For image generation this rarely matters: you are producing an artefact once, not verifying how three engines each display it. Cross-browser verification is a testing concern, and testing is exactly the job we would tell you to keep in Playwright.
The same operational bill as any browser fleet: shipping browser binaries with your app or CI image (Playwright downloads its own patched builds), pinning versions so renders stay reproducible, giving each browser instance memory headroom, cleaning up hung processes, and rebuilding whenever a browser security release lands. Serverless is harder still — the binaries are large and cold starts get slow. Our Puppeteer-on-Lambda article covers the same pain points, which apply to Playwright unchanged.
Map page.goto() and the viewport to the Screenshot endpoint's url, width and height. HTML you fed via page.setContent() goes to the HTML endpoint instead. Selector and timing waits map to wait_for_selector and ms_delay. The response is a CDN-hosted URL, which typically also replaces your artefact upload step.
The free tier covers 25 renders a month with no credit card. Point your production screenshot job at the API and compare the output.
Jobs you'd otherwise hand-build pages for. Twenty-five pre-built designs rendered from JSON — no HTML, no browser, no hosting.