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.