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.
Updated 31 August 2026
Both tools turn HTML into PDF. They are not interchangeable, and the difference is not quality — it is what kind of HTML you feed them.
The setup
Same machine (8 cores, 32 GB), same three inputs: a one-page invoice (tables, one logo, system fonts), a 14-page report with two SVG charts and a web font, and a live marketing page with JavaScript-rendered sections. Each rendered 50 times; we report medians.
Timings
- Invoice — WeasyPrint 0.19 s, Playwright warm 0.64 s (cold browser start adds ~1.3 s once per process)
- 14-page report — WeasyPrint 1.9 s, Playwright 1.1 s
- JavaScript page — WeasyPrint: layout wrong (no script executed), Playwright 2.4 s including network idle
The invoice result surprises people: WeasyPrint is three times faster on simple documents because there is no browser at all — it is a Python layout engine writing PDF directly. The report flips the order: WeasyPrint's layout pass grows with page count and complex floats, while Chromium's engine is built for exactly that.
Memory
A WeasyPrint render peaks around 120 MB for the report. One Chromium context sits at 90–150 MB, but the browser process underneath holds 300–400 MB permanently. If you render one document a minute, WeasyPrint is far cheaper. If you render one a second, the browser is already warm and the per-document cost is what matters.
Where WeasyPrint loses outright
Anything that needs JavaScript: charts drawn client-side, frameworks that mount after load, lazy images. WeasyPrint sees the empty shell. It also skips a handful of CSS features that browsers ship — check its documentation before assuming flexbox behaviour matches.
Where Playwright loses
Typography on long text documents. Chromium prints screen layout; WeasyPrint implements paged-media CSS properly: running headers, footnotes, `string-set`, page counters that behave. Contracts and statements look more like typeset documents out of WeasyPrint.
What we do
PDFGeny runs both behind one endpoint. HTML that looks like a document — tables, no scripts — can go to WeasyPrint with `"engine": "weasy"`; everything else goes to Chromium. You pick per request:
curl -X POST https://pdfgeny.com/api/v1/render \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"html": "<table>…</table>", "engine": "weasy"}' --output statement.pdf
Rule of thumb
Authored as a document, no JavaScript, hundreds a day: WeasyPrint. Comes from a web page, or must match what the browser shows: Chromium. Not sure: Chromium — it is never wrong, only sometimes slower.
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.
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.