Playwright alternatives for HTML to PDF in 2026: five ways to stop shipping browsers
The best Playwright alternative for HTML-to-PDF work depends on what is actually hurting. If it is the browser payload (the playwright install step in every CI run, the missing-dependencies errors, the memory bill), a managed API like Transformy keeps the same Chrome-quality output and removes the browser from your stack. If you want the browser out of your app but inside your infrastructure, Gotenberg gives it a service shape. And if your documents never execute JavaScript, WeasyPrint renders them with no browser anywhere.
Scope note: Playwright is primarily an end-to-end testing tool, and a very good one. This comparison covers only its HTML-to-PDF job. If Playwright runs your test suite, keep it there; nothing below argues otherwise.
$ npx playwright install chromium
Downloading Chromium 127.0.6533.17 (build v1124)
158.6 MiB [====================] 100%
$ node render-pdf.js
Host system is missing dependencies to run browsers.
Please install them with: sudo npx playwright
install-deps
ci minutes on browser downloads ··· this month: 214
$
KEY TAKEAWAYS
- Diagnose before you switch. Browser-ops pain and document overkill are different problems; a managed API fixes the first, skipping the browser entirely fixes the second.
- A managed API keeps the output, not the payload. Transformy renders with the same headless Chromium; the install steps, pools, and upgrades move to the vendor.
- Puppeteer is a sideways move for PDFs. Same engine, same ops bill; switch for ecosystem preference, not relief.
- The browser download is a tax on every environment. CI runs, Docker images, and serverless deploys all pay for the ~150 MB browser payload and its system dependencies.
- JS-free documents have a browser-free exit. WeasyPrint (HTML/CSS) and construction libraries like pdf-lib skip rendering infrastructure entirely.
Why teams look past Playwright for PDFs
Credit where due first: for PDF generation, Playwright is arguably the nicest DIY option there is. page.pdf() produces exactly what Chrome's print dialog would, the API is clean, and official bindings cover Node.js, Python, Java, and C#, which is why our other comparison pages recommend it freely. The reasons teams look past it are the operations around the rendering, not the rendering.
Every environment ships a browser. npx playwright install chromium downloads on the order of 150 MB per browser, per version, and fresh Linux hosts routinely add the "Host system is missing dependencies to run browsers" chapter. CI caches help until the version bumps; Docker images grow to carry a browser next to your app; serverless platforms need special builds and layers. None of it is hard once, and all of it recurs.
Production browsers are an ops workload. The rendering code is 15 lines; the hardening is the project. Memory recycling, crash recovery, zombie processes, a pool with a queue for realistic throughput, and a regression pass when Chromium bumps with each Playwright release. This is the same bill Puppeteer pays; the engine is the point, not the wrapper.
Your PDF volume may not justify a browser fleet. Teams running a handful of browser instances to render invoices at month-end are doing capacity planning for a workload a POST request could carry.
Some documents never needed the browser. Server-rendered templates with no JavaScript render beautifully in lighter engines; a testing-grade browser is a heavy way to print an invoice.
Tip
If Playwright renders your PDFs correctly and the ops load is invisible, keep it; it is what we recommend to teams in the reverse position. The alternatives below earn their place when browser operations reach your incident channel or your CI minutes bill.
The shortlist at a glance
| TOOL | TYPE | ENGINE | PRICING | BEST FOR |
|---|---|---|---|---|
| Transformy | Managed API | Headless Chrome | Free 100 docs/mo, then $99/mo for 10,000 | Same Chrome output with zero browser infrastructure |
| Puppeteer | Library (Node.js) | Headless Chrome | Free (your infra) | Node-only teams preferring its ecosystem; otherwise lateral |
| Gotenberg | Self-hosted service | Chromium + LibreOffice | Free (your infra) | Service-shaped rendering inside your cluster |
| Headless Chrome CLI | Command-line tool | Headless Chrome | Free | Scripts and scheduled jobs |
| WeasyPrint | Library (Python) | Own CSS paged-media engine | Free | JS-free templates with no browser in the stack |
The managed option: Transformy
Transformy is the "keep the output, delete the payload" move: rendering happens on real headless Chromium, so everything Playwright gives you (flexbox, grid, webfonts, JavaScript that settles before capture) survives the migration, while the playwright install step, the browser pool, and the Chromium upgrade cadence stop existing in your codebase. The mapping is direct because the engine is shared; page.pdf() options rename onto request parameters (cheat sheet below), and the browser lifecycle code deletes rather than translates.
curl -X POST https://api.transformy.io/v1/pdf/chrome \
-H "Authorization: Bearer tfy_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://app.example.com/statements/2026-06",
"page_size": "a4",
"footer": { "html": "<span style=\"font-size:10px\">Page {{page}} of {{pages}}</span>" }
}' \
--output statement.pdf
You also pick up the production plumbing DIY setups rarely build: async jobs with signed webhooks, delivery straight to your own S3/GCS/Azure/R2 bucket, idempotency keys for safe retries, and a free watermarked test mode. Pricing starts free (100 documents a month, no credit card); the Pro plan is $99/month for 10,000 documents, then $0.01 per additional document. The honest trade-offs are the usual managed-API set: rendering leaves your network boundary, very large steady volume can be cheaper self-hosted if you staff it, and a per-document fee replaces a free library.
Run it yourself: the open-source routes
Puppeteer
The obvious question deserves a straight answer: for PDF generation, switching Playwright for Puppeteer changes almost nothing. Same headless Chrome, equivalent page.pdf(), same browser-operations bill, minus Playwright's non-Node bindings. Move for ecosystem preference if you like; move for relief and you will not find it. Our Puppeteer alternatives page covers that road's own exits, which are, unsurprisingly, the same ones on this page.
Gotenberg
If the goal is getting browsers out of your application processes while keeping rendering in-house, Gotenberg wraps Chromium (and LibreOffice) behind an HTTP API in a Docker container. Your services POST HTML and receive PDFs; the browser payload lives in one image you control instead of every app that renders. You still own that container's memory, scaling, and upgrades; our Gotenberg alternatives page weighs what that costs as volume grows.
Headless Chrome from the command line
When the Playwright script was only ever a cron job, Chrome itself may be all the machinery required:
chrome --headless --no-pdf-header-footer --print-to-pdf=report.pdf https://example.com/report
No library, no install step beyond Chrome itself, same engine. The flags are coarse (no proper page-number headers, limited wait control), which makes this right for a nightly report and wrong for an application feature.
WeasyPrint
If your documents are server-rendered templates that never execute JavaScript, WeasyPrint removes the browser question at the root: a Python library with its own CSS paged-media engine, unusually good @page and page-numbering support, deterministic output, and PDF/A variants when compliance asks. Python-only and no JS by design; that design is why it is lighter than everything else here. Where its own limits sit is mapped in our WeasyPrint alternatives page.
Migrating: mapping page.pdf() options to Transformy
The engine is shared, so the port is renames plus deletions:
- const browser = await chromium.launch();
- const page = await browser.newPage();
- await page.goto(url, { waitUntil: "networkidle" });
- await browser.close();
+ one authenticated POST; JavaScript settles automatically
- format: "A4", landscape: true
+ "page_size": "a4", "orientation": "landscape"
- margin: { top: "2cm" }, printBackground: true
+ "margin": {"top": "2cm"}, "print_background": true
- pageRanges: "1-5", scale: 1.3, preferCSSPageSize: true
+ "page_ranges": "1-5", "zoom": 1.3, "prefer_css_page_size": true
- displayHeaderFooter + <span class="pageNumber"> templates
+ "header"/"footer" with {{page}}, {{pages}} tokens
- npx playwright install chromium # per CI run, per image
- sudo npx playwright install-deps # per fresh host
+ not a step anymore
Header and footer fragments remain isolated documents in both worlds, so keep their styles inline. And where Playwright setups tune wait conditions per page, the API's default settle behavior usually means deleting that logic rather than porting it.
Frequently asked questions
Is Playwright still maintained?+
Yes, very actively, by Microsoft, and it remains our recommendation for end-to-end testing regardless of what renders your PDFs. This page is about the cost of self-hosting browsers for document generation, not project health.
Playwright or Puppeteer for PDFs?+
For PDF output they are equivalent: same engine, same options, same ops. Playwright adds Python, Java, and C# bindings; Puppeteer keeps a slightly larger Node mindshare. Neither reduces the browser-operations cost; that takes moving the browser (API or service) or removing it (WeasyPrint, construction libraries).
Can Playwright run in AWS Lambda?+
Yes, with special builds and packaging care, and it shares Puppeteer's serverless friction: size limits, cold starts, and version drift. If serverless PDFs are the pain, an HTTP rendering API avoids the packaging entirely.
Do I need a browser to render invoices?+
Only if they use JavaScript or must match a browser pixel-for-pixel. JS-free templates render well in WeasyPrint with no browser at all, and very simple documents can be constructed directly with pdf-lib or ReportLab.
What is the difference between Playwright and a managed API like Transformy?+
Same rendering engine, different operator. Playwright runs Chrome on hosts you maintain; a managed API runs it behind one authenticated HTTPS call, with the install, pooling, scaling, and upgrade work on the vendor side. Options map one-to-one; the infrastructure chapter disappears.
The bottom line
Name the pain and pick accordingly. Browser payload and ops with output you love: Transformy keeps the rendering and deletes the infrastructure, and the free tier (100 documents a month, no credit card) is enough to port your page.pdf() options against the table above. Rendering must stay in-house: Gotenberg gives the browser a service shape. Documents that never needed a browser: WeasyPrint. And Puppeteer remains what it always was here: a fine sibling, not an exit.
Playwright made browsers programmable in four languages. The alternatives above are for the moment you notice the PDF feature only ever needed the printout, not the browser.