HTML-to-PDF engines, benchmarked honestly
There is no single “best” HTML-to-PDF engine — it depends on the document. We rendered 11 fixtures through five engines (Chromium, PrinceXML, WeasyPrint, Vivliostyle, wkhtmltopdf) and measured what each can render, how fast, and at what size. The short version: only a browser engine (Chromium) runs JavaScript; Prince owns print typography and raw speed; WeasyPrint makes the smallest files. No engine wins everything — so we say plainly where each one does.
Reproducible: the fixtures + harness are open source. Docweave renders with Chromium, so it competes here as the “Chromium” row — we publish this because it's true, not because it's flattering.
What each engine can render
| Capability | Chromium | Prince | WeasyPrint | Vivliostyle | wkhtmltopdf |
|---|---|---|---|---|---|
| Modern CSS — flexbox, grid, web fonts, print backgrounds | ✓ | ✓ | ✓ | ✓ | ~ |
| JavaScript — dynamic tables, Chart.js, client-rendered content | ✓ | ✗ | ✗ | ◑ | ✗ |
| Print typography — footnotes, running headers, cross-references, ToC leaders | ✗ | ✓ | ◑ | ◑ | ✗ |
| Pixel-identical to Chrome | ✓ | ✗ | ✗ | ✗ | ✗ |
✓ yes · ◑ partial · ~ mostly · ✗ no
The JavaScript divide
This is the clearest, most consequential result. A document with a JavaScript-generated table or a Chart.js chart renders fully in Chromium and comes out empty in Prince, WeasyPrint, and wkhtmltopdf — they render static HTML/CSS only. If your PDF is built or populated by JavaScript (dashboards, dynamic reports, anything an app or AI agent assembles at runtime), a browser engine is the only option.
Print typography — where Chromium loses
The flip side, stated just as plainly: CSS Paged Media features — footnotes, running headers via string-set, cross-references via target-counter, dotted ToC leaders — render in Prince and not in Chromium. For a book or a print-shop document, Prince (or Antenna House / PDFreactor) is the right tool, not a browser.
Speed & size
| Engine | Median render (ms) | Note |
|---|---|---|
| Prince | 33 | native compiled engine — fastest by far |
| WeasyPrint | 236 | pure-Python, no browser |
| Chromium (warm) | 556 | reused browser — a hosted API's normal path |
| Chromium (cold) | 631 | fresh browser per render (serverless cold start is far worse) |
| Vivliostyle | 1862 | browser launch per render |
Chromium is not the fastest — Prince is ~16× quicker, WeasyPrint ~2×. Chromium's cost is the browser itself; the answer a hosted API gives is a warm worker (no per-render cold start) rather than raw engine speed. WeasyPrint produces the smallest files (4–11 KB vs Chromium's 23–73 KB).
Which should you use?
Chromium (Puppeteer / Playwright / hosted APIs)
The only engine that runs JavaScript, and it renders pixel-identical to Chrome. The right choice for the dynamic, app-generated, and AI-agent-generated content most people actually make. Cost: the heaviest engine, and a cold browser launch is slow (why hosted APIs keep a warm pool). Docweave is a Chromium engine.
PrinceXML
The print-shop gold standard — footnotes, running headers, cross-references, PDF/UA — and astonishingly fast (~16× Chromium here). No JavaScript. Commercial (~$3,800+/yr for a server license); DocRaptor resells it as an API.
WeasyPrint
Free, open-source, smallest files, and fast. Its own CSS engine (not a browser), so no JavaScript and occasional divergence from Chrome on complex CSS. Great for server-side static documents in Python.
Vivliostyle / Paged.js
Open-source, standards-first CSS Paged Media (books, long documents). Browser-backed, so slower; strong on paged-media rules.
wkhtmltopdf
Archived since 2023, built on a decade-old QtWebKit, no modern arm64 builds, and carries an unpatched CVSS 9.8 SSRF. Do not start a new project on it — migrate off.
Where Docweave fits
Docweave is a Chromium engine behind an API — so it renders your modern, JavaScript-driven HTML pixel-identical to the browser, which is what developers and AI agents actually generate. It runs on a warm worker (no cold-start penalty), guards URL rendering against SSRF, and is priced per document, not per page. If you need print-shop typography, use Prince; for the documents most apps produce, one API call gets you a browser-faithful PDF — and Docweave also reads PDFs back into text.
FAQ
What is the best HTML-to-PDF engine?
There isn't one best engine — it depends on the document. For books and print-shop typography (footnotes, running headers, cross-references) PrinceXML leads. For static server-side documents, WeasyPrint is a fast, free choice. For the dynamic, JavaScript-driven, browser-rendered content most apps and AI agents generate, a Chromium engine is the only one that renders it correctly and pixel-identical to Chrome.
Which HTML-to-PDF engines support JavaScript?
In this benchmark, only Chromium (Puppeteer/Playwright and the hosted APIs built on it) executes JavaScript. PrinceXML, WeasyPrint, and wkhtmltopdf render a page's static HTML/CSS only — a JavaScript-generated table or a Chart.js chart comes out empty. If your document is built or populated by JavaScript, you need a browser engine.
Is wkhtmltopdf still safe to use?
wkhtmltopdf was archived in January 2023, is built on an outdated QtWebKit fork years behind modern CSS, has no modern arm64 builds, and carries an unpatched SSRF vulnerability (CVSS 9.8). It's a legacy baseline only — migrate to a maintained engine.
How was this benchmarked?
Each engine rendered 11 fixtures (modern CSS, JavaScript, and print-media features) to PDF. We record whether it rendered, whether the marker text survived, file size, median render latency (including Chromium cold vs warm), and a page-1 pixel-diff against Chromium's output. The harness and fixtures are open source and reproducible.
Browser-faithful PDFs from HTML, a URL, or a template — one API, per document.
Get an API key