Convert HTML to PDF: six methods, and how each one breaks
Browser print dialog, wkhtmltopdf, WeasyPrint, Puppeteer/Playwright, LibreOffice, and a hosted API. What each produces, what it costs to run, and the failure you will hit first.
Updated 31 August 2026
There are more ways to turn HTML into a PDF than there are good reasons to. Here is the honest map.
1. The browser's print dialog
Open the page, press Ctrl+P, choose Save as PDF. Free, perfect fidelity, zero automation. Fine for one document; useless the moment a second person or a cron job needs it. Breaks when: you need it done more than once.
2. wkhtmltopdf
A command-line tool wrapping an old WebKit. It was the default answer for a decade and still appears in every Stack Overflow thread. The project is archived; the engine predates modern flexbox and grid. Breaks when: your CSS is younger than 2016, or you need web fonts to reliably load. See what to use instead.
3. WeasyPrint
A Python library that implements paged-media CSS and writes PDF without a browser. Excellent typography for documents; no JavaScript at all. Breaks when: the page needs a script to render anything.
4. Puppeteer or Playwright
Drive real headless Chromium and call `page.pdf()`. Output matches the browser exactly. The cost is operational: install Chromium and its libraries on every machine, keep the browser alive between renders (a cold start is over a second), pool concurrent renders, and restart it when it leaks. Breaks when: you deploy to a small container and discover Chromium wants 400 MB before it renders anything.
5. LibreOffice headless
`soffice --headless --convert-to pdf file.html`. Surprisingly serviceable for plain HTML, terrible for anything styled. Breaks when: CSS matters.
6. A hosted API
You POST HTML, you receive a PDF. Someone else runs the browser, patches it, pools it and pays for its memory. Breaks when: you have no network, or you render millions a month and the per-document price stops making sense against a dedicated box.
The comparison that matters
- Fidelity: Chromium-based (4, 6) > WeasyPrint for web pages; WeasyPrint > Chromium for typeset documents
- Setup time: 1 < 6 < 3 < 2 < 4 < 5
- Cost at 1,000 documents/month: all negligible except your own engineering time
- Cost at 100,000/month: run your own Chromium pool, or negotiate volume with an API
A working example of method 6
curl -X POST https://pdfgeny.com/api/v1/render \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"html":"<h1>Invoice 001</h1><p>Total: €149</p>","format":"A4"}' \
--output invoice.pdf
That is the entire integration. The free tier covers 50 documents a month, which is enough to find out whether the output matches what you need.
Try it: convert HTML to PDF in the browser, or get a free API key — 50 documents a month.
More guides
How to generate 10,000 PDFs without running out of memory
Bulk PDF generation fails in predictable ways: one browser per document, unbounded concurrency, results held in RAM. Here is the shape of a pipeline that survives.
WeasyPrint vs Playwright for HTML to PDF: real timings and when each wins
We rendered the same invoices, reports and web pages with WeasyPrint and headless Chromium via Playwright. Cold and warm timings, memory, and the cases where one is simply the wrong tool.