Puppeteer alternative
Puppeteer Alternative for Managed Headless Chrome PDF Rendering with No Fleet
Puppeteer is an excellent library and a miserable service to operate. If you are here because the browser fleet keeps waking someone up, this page is the honest version of the trade off, including when you should just keep Puppeteer.
- PDF and archive in one call
- Plans from $49 a month
- Your HTML stays yours
Short answer
The best Puppeteer alternative for PDF generation is a managed rendering API: you keep the same Chromium output quality, but the vendor runs the browser pool, patches it, and absorbs the memory leaks. Puppeteer itself is free; what costs money is the engineer who owns the fleet. Swap the library for one HTTP call when render reliability starts consuming on call time, or when you need a dated record of what you rendered, which no headless browser gives you.
Written and fact checked by the SitePDF team.
Puppeteer, wkhtmltopdf and a managed API, side by side
This is a comparison of operating models, not a benchmark. All three produce good PDFs on a good day. They diverge on who fixes it at 3am.
| Puppeteer (self-hosted) | wkhtmltopdf | SitePDF API | |
|---|---|---|---|
| Licence cost | Free (Apache 2.0) | Free (LGPL) | Paid, from $49/mo |
| Rendering engine | Current Chromium | Old WebKit fork, archived upstream | Managed current Chromium |
| Modern CSS and JS | Full support | Partial: flexbox and grid are unreliable | Full support |
| Who runs the browser | You do | You do | We do |
| Typical failure mode | Memory leak, zombie processes, pool wedges | Silently renders the page wrong | Explicit error, no quota charged |
| Wait for late content | You write it yourself | Not really | wait_for selector, built in |
| Timestamped archive of the render | No | No | Yes, archive=true |
| Scales by | Adding servers you manage | Adding servers you manage | Your plan's concurrency |
Licence and engine facts are from each project's own documentation. wkhtmltopdf's upstream repository has been archived and its maintainers recommend moving to a Chromium based renderer, which is the honest reason it sits third here.
The bill for "free" is not zero, it is just not on the invoice
Puppeteer costs nothing to install. It costs a great deal to run. The pattern is so consistent it is almost a rite of passage: a single puppeteer.launch() in a request handler works beautifully in staging, then production traffic arrives and the box runs out of memory because browsers were never closed on the error path. So you build a pool. The pool wedges. So you add a health check and a reaper. Chrome ships a new major version and your page breaks in a way that reproduces on nobody's laptop. Someone patches a font package at 11pm because Arabic invoices are rendering as boxes.
None of that appears on a budget line. It appears as an engineer's week, repeatedly, and as the on call rotation nobody volunteers for. The library is free; the fleet is a product you did not mean to build and do not get paid for.
We wrote the full arithmetic in HTML to PDF library vs API, including the volumes at which self-hosting genuinely does win.
When you should keep Puppeteer, honestly
We are not going to pretend the API is always right. Keep the library when any of these are true. Your rendering needs are trivial and stable, a handful of simple templates that have not changed in a year. You already operate browser automation for other reasons, scraping or end to end tests, so the fleet exists whether or not you make PDFs with it. Your data cannot leave your network for regulatory reasons, and no vendor contract fixes that. Or your volume is so high that per render pricing genuinely exceeds the cost of servers plus the fraction of an engineer who tends them.
That last one is a real number, not a rhetorical one. Work it out before you buy anything. If self-hosting wins on your numbers, self-host.
We have done that arithmetic at the settings the serverless Chromium maintainers recommend. At 100,000 renders a month, Chromium on AWS Lambda costs about $10.44 of compute against roughly $140 on a managed browser plan, so the entire annual difference is worth 10 to 21 hours of engineering time. The full working, including Cloud Run, the free tier effect and the timeout trap that catches most teams, is in what Chrome on AWS Lambda really costs per PDF.
If you keep Puppeteer but stop hosting the browsers yourself, the managed Chrome market is the next thing to price, and its billing increments vary much more than its hourly rates do. We compared eight of those vendors on Browserbase pricing.
Playwright vs Puppeteer for PDF generation, and why switching libraries changes little
For PDF output the two libraries produce near identical files, because both drive Chromium and call the same print to PDF function. WebKit and Firefox headless do not expose the same capability, so a Playwright PDF is a Chromium PDF in practice. Anyone who says one makes visibly better PDFs than the other from the same HTML is measuring noise. The real differences are in the API, browser management and language support:
| Puppeteer | Playwright | |
|---|---|---|
| PDF output | Chromium print to PDF | Identical, same Chromium |
| Official languages | JavaScript | JavaScript, Python, .NET, Java |
| Waiting for content | waitUntil: 'networkidle0' and waitForSelector, written out by hand | Auto waiting built into actions, plus networkidle and wait_for_selector |
| Browser management | Downloads a bundled Chromium on install | Pinned per release through playwright install |
| PDF from WebKit or Firefox | No | No, Chromium only in practice |
| Who runs the browser fleet | You | You |
Pick Playwright if your stack is Python, .NET or Java, because Puppeteer is JavaScript first and the community ports (PuppeteerSharp, pyppeteer) lag upstream. Pick Puppeteer if you are Node only and want the smallest, most established dependency. Set printBackground: true in either one, since Chromium drops background colors and images in print mode by default and that flag is the usual reason a PDF looks washed out next to the screen.
Now look at the last row. Switching libraries does nothing to the memory leaks, zombie processes, restart policies and concurrency queues described above, because the weight is in the browser, not the wrapper. If PDFs are a supporting feature (invoices after checkout, monthly statements, exported reports), the cheaper move is to stop running either one and send the same render as an HTTP call, with wait_for doing the job of waitForSelector.
Can you convert HTML to PDF without headless Chrome?
Yes, and there are exactly two honest ways to do it. They pull in opposite directions. The first is a pure code engine that draws the PDF from HTML and CSS with no browser at all: WeasyPrint in Python, dompdf and mPDF in PHP, OpenHTMLtoPDF in Java. These start instantly and fit a small serverless function, but they only support the CSS their authors implemented and none of them run JavaScript. WeasyPrint is the strongest, with flexbox, grid and paged media implemented; dompdf sits around CSS 2.1, so a Tailwind template collapses in it. A chart drawn client side simply does not appear, which is why WeasyPrint renders charts as empty boxes.
The second keeps browser grade rendering and moves the browser off your servers, by calling a hosted rendering API. Flexbox, grid, web fonts and JavaScript all behave, and it fits hosts that forbid launching a browser process. The trade is that your HTML, or a URL to it, is rendered by a third party, which is a data residency question to answer before you commit. A middle position exists too: run Gotenberg as its own container, so you still run Chrome but a crash takes down a pod rather than your API.
| Your situation | Best fit |
|---|---|
| Simple, static, print style HTML you fully control | Pure code engine (WeasyPrint, dompdf) |
| Real app pages, modern CSS or JavaScript, output must match Chrome | Hosted rendering API |
| Browser fidelity, but the data cannot leave your network | Self hosted browser service (Gotenberg) |
| Serverless, or a host that will not launch a browser | Hosted rendering API |
| You need a dated, verifiable record of each PDF | Hosted rendering API with archiving |
There is no option that is both pure code and pixel identical to Chrome, because matching a browser is precisely what requires a browser. Decide whether you mean "without a heavy engine" or "without me babysitting a browser", and the right tool follows.
What you get by switching that Puppeteer cannot give you at all
Output quality is a wash. It is the same engine, so the PDF looks the same. What changes is everything around the render.
The pool, the patching and the page at 3am become someone else's job. Failed renders return an explicit error with the HTTP status the page returned, instead of a blank PDF you discover three weeks later in a customer complaint. And the render can carry a record: archive=true stores a timestamped, immutable snapshot of the page under your account, retrievable by id for the life of your retention window. Headless Chrome has no concept of this, and bolting it on means building a second pipeline, a storage layer and a retention policy. Archiving is the half of the job Puppeteer was never going to do for you.
If a record is the reason you are reading this, the save webpage as PDF and screenshot API pages cover the capture side, and the PDF generator API covers document generation from your own templates.
Migrating off the fleet is a one function change
Almost every Puppeteer PDF integration reduces to one internal function: give it HTML or a URL, get back a buffer. Replacing the body of that function with an HTTP call is usually an afternoon, and you can run both paths side by side behind a flag while you compare output on real documents. Nothing about your templates changes, because the engine did not change.
Tiers are on the pricing page, and the seven tool comparison lists the other vendors worth pricing against us, because you should check.
// before: you own the browser, the pool and the leak
const browser = await puppeteer.launch({ args: ['--no-sandbox'] })
const page = await browser.newPage()
await page.goto(url, { waitUntil: 'networkidle0' })
await page.waitForSelector('.order-summary')
const pdf = await page.pdf({ format: 'A4' })
await browser.close() // the line everyone forgets on the error path
// after: one call, plus a dated record you never had before
const res = await fetch('https://api.sitepdf.com/v1/render', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.SITEPDF_KEY}` },
body: new URLSearchParams({
url,
wait_for: '.order-summary',
format: 'A4',
archive: 'true',
}),
})
const { pdf_url, archive } = await res.json()
This is the documented API call shape. Full request and response walkthrough.
Questions about this job
Is Playwright better than Puppeteer for PDF generation?
Can I convert HTML to PDF without headless Chrome?
What is the best alternative to Puppeteer for generating PDFs?
Why does Puppeteer leak memory in production?
Is wkhtmltopdf still a good option in 2026?
Will my PDFs look different if I switch from Puppeteer to an API?
How hard is it to migrate off Puppeteer?
Index
More PDF and archiving tools
- Convert HTML to PDF
- Webpage to PDF
- URL to PDF API
- Website archiving
- Monitor website changes
- Screenshot API
- React to PDF
- Java PDF library
- C# PDF library
- Python PDF generation
- HTML to PDF Node.js
- Laravel HTML to PDF
- Vue to PDF
- Next.js PDF generator
- Angular to PDF
- Markdown to PDF API
- Django HTML to PDF
- Blazor HTML to PDF
- Spring Boot HTML to PDF
- Airtable to PDF
- Rails HTML to PDF
- PDF generator API
- Website archiving software
- Document generation API
- Legal document automation software
- Document automation software
- Bulk HTML to PDF
- Accessible PDF generation
- ADA compliance audit cost
- 508 compliance testing
- PDF remediation
- VPAT and ACR
- PDF accessibility checker
- Wayback Machine alternative
- Best HTML to PDF API
- DocRaptor alternative
- Wkhtmltopdf alternative
- PDFShift pricing and alternative
- Urlbox pricing and alternative
- PDFCrowd alternative
- Api2Pdf alternative
- Browserless alternative
- APITemplate alternative
- CraftMyPDF alternative
- PDFMonkey alternative
- dompdf alternative
- Gotenberg alternative
- GrabzIt alternative
- Adobe PDF Services API
- PDF SDK pricing
- HTML to image API pricing
- Adobe Document Generation API pricing
- jsreport pricing
- PDFBolt pricing
- PDFEndpoint pricing
- Formstack Documents pricing
- Documint pricing
- iLovePDF API pricing
- Browserless pricing
- PandaDoc API pricing
- CloudConvert API pricing
- Encodian pricing
- IronPDF pricing
- Salesforce document generation pricing
- SelectPdf, HiQPdf and EvoPdf pricing
- CloudConvert alternative
- Direct mail API pricing
- E-signature API pricing
- Sparticuz Chromium Lambda cost
- Browserbase pricing
- Aspose PDF pricing
- PDF API pricing
- How it works
- Features
- Pricing
Get started
Render and archive with one API call
A pixel perfect PDF and a dated copy of the page from the same request. Plans from $49 a month, half price billed yearly.