Get your API key
WeasyPrint vs Prince: CSS to PDF engines compared (2026)

WeasyPrint vs Prince: CSS to PDF engines compared (2026)

WeasyPrint is free and open source, Prince is commercial with deeper CSS print support. A side-by-side of CSS coverage, price, output quality and when each wins.

11 min read

WeasyPrint and Prince both turn HTML and CSS into PDF without a browser, and neither runs your page's JavaScript. The short answer: pick WeasyPrint when you want a free, BSD-licensed engine for invoices, reports, and everyday documents, and pick Prince (PrinceXML) when you need book-grade print typesetting (footnotes, cross-references, named page regions) and can pay a per-server license. Prince has the wider CSS print spec coverage; WeasyPrint has the wider reach because it costs nothing.

This article compares the two on license and price, CSS Paged Media support, JavaScript, footnotes and bookmarks, install footprint, and speed, then tells you which to choose by scenario.

WeasyPrint vs Prince at a glance

Both are dedicated CSS-to-PDF engines, not browsers. They parse HTML and CSS and lay out pages using the CSS Paged Media model rather than driving a render engine like Chromium. The table below summarizes the practical differences.

CriterionWeasyPrintPrince (PrinceXML)
LicenseBSD (open source)Commercial, closed source
PriceFreePer-server perpetual license (thousands USD/server), free mode stamps a logo
Language / runtimePythonC++ binary (CLI + bindings)
Runs page JavaScriptNoLimited JS engine at load (optional), not a browser
CSS 2.1 + basic paged mediaStrongStrong
CSS Paged Media (named pages, margin boxes)GoodMost complete
Footnotes (float: footnote)Limited / historically unsupportedFull support
Cross-references and page numbers (target-counter)PartialFull support
PDF bookmarks / outlineYes (from headings + CSS)Yes
Install footprintpip + Pango/cairo system libsSingle binary or OS package
Speed on large docsSlower (pure Python)Faster (compiled)
Best forInvoices, reports, free pipelinesBooks, manuals, print typesetting

Both engines ignore client-side JavaScript by default. If your HTML renders content with JS (a charting library, a React or Vue app), neither WeasyPrint nor Prince will see that content. Render the HTML to static markup first, or use a Chromium-based path.

What is WeasyPrint and when should you use it?

WeasyPrint is a free, open-source Python library that renders HTML and CSS to PDF using its own layout engine, with no browser involved. Use it when you want zero license cost, a pip-installable pipeline, and your documents use standard CSS 2.1 plus common CSS Paged Media features like @page margins, page size, and running headers.

WeasyPrint is published under the BSD license, so you can ship it in commercial products with no per-server fee. It implements a large slice of CSS 2.1, CSS Paged Media, and CSS color, fonts, and transforms. It reads web fonts, embeds images, and writes a PDF outline from your heading structure. It does not run JavaScript at all, which keeps the security surface small and the output deterministic.

Where WeasyPrint is weaker: CSS footnotes (float: footnote), full cross-reference counters, and some advanced named-page features are partial or absent, and it is pure Python so very large documents render slower than a compiled engine.

# pip install weasyprint
from weasyprint import HTML
 
html = """
<!DOCTYPE html>
<html>
  <head>
    <style>
      @page { size: A4; margin: 20mm 15mm; }
      h1 { font-family: Inter, sans-serif; color: #111827; }
      .total { font-weight: 700; }
    </style>
  </head>
  <body>
    <h1>Invoice INV-001</h1>
    <p class="total">Total: $1,500.00</p>
  </body>
</html>
"""
 
HTML(string=html).write_pdf("invoice.pdf")

WeasyPrint needs native libraries (Pango, cairo, GDK-PixBuf) for text shaping and images. pip install weasyprint pulls the Python bindings, but on Linux you also install OS packages (for example libpango-1.0-0, libpangocairo-1.0-0, libgdk-pixbuf-2.0-0). A bare pip install on a minimal container can fail at import time until those are present.

What is Prince and when should you use it?

Prince (PrinceXML) is a commercial, closed-source C++ engine that renders XML, HTML, and CSS to PDF with the widest support for the CSS Paged Media and Generated Content for Paged Media specifications. Use it when you produce books, manuals, scientific papers, or long documents that need footnotes, page cross-references, named page regions, and fine widow and orphan control.

Prince ships as a single binary with command-line, library, and server bindings. It supports float: footnote for automatic footnotes, target-counter() for "see page 42" cross-references, named pages and running content pulled from the document, and PDF/A and PDF/X output profiles used in professional publishing. It can run a limited JavaScript engine at document load when you enable it, though it is not a browser and does not behave like one for interactive scripts.

The trade-offs are cost and openness. Prince sells a per-server perpetual license that runs into the thousands of US dollars per production server, published on the official Prince site. There is a free unlicensed mode, but it stamps a small Prince logo on the first page of every document, so it is for evaluation rather than production.

# render an HTML file to PDF
prince invoice.html -o invoice.pdf
 
# render a remote URL
prince https://example.com/report.html -o report.pdf
 
# enable the built-in JavaScript engine at load
prince --javascript report.html -o report.pdf

How do WeasyPrint and Prince compare on CSS print support?

Prince supports more of the CSS print specifications than WeasyPrint, especially the parts that matter for books rather than invoices. Both handle @page rules, page size, margins, margin boxes, and basic running headers. The gap opens on advanced generated content.

Prince implements float: footnote for automatic footnotes that collect at the bottom of the page, target-counter() and target-text() for cross-references like "continued on page 12", named page areas, and bookmark levels controlled from CSS. These come from the CSS Generated Content for Paged Media module, which is largely a Prince-driven specification. WeasyPrint implements @page, named pages, page counters, and many margin-box features, but footnotes and full cross-reference counters are partial or unsupported.

For widow and orphan control, page breaks (break-before, break-after, break-inside), and keeping table headers across page breaks, both engines do well. If your documents are invoices, statements, certificates, and reports, you will rarely hit the WeasyPrint ceiling. If you are typesetting a 300-page manual with footnotes and an index, Prince's extra spec coverage is the reason it costs money.

A fast test: open your CSS and search for float: footnote, target-counter, target-text, or @footnotes. If you use any of them, you are in Prince territory. If you do not, WeasyPrint likely covers you for free.

Do WeasyPrint or Prince run JavaScript?

No, not the way a browser does. WeasyPrint never executes JavaScript. Prince can run a limited JavaScript engine at document load when you pass --javascript, but it does not drive a DOM event loop, fetch like a browser, or run modern SPA frameworks reliably. Both are layout engines for static HTML and CSS.

This matters because a large share of "my PDF is blank" problems come from HTML that builds its content client-side. A dashboard that mounts a React tree, a chart drawn by Chart.js on a canvas, or a price table fetched after page load will all be invisible to a non-browser engine. The two safe patterns are: render your HTML to static markup on the server before handing it to WeasyPrint or Prince, or use an engine that actually runs a browser.

When you need true browser parity (JS-rendered content, CSS Grid and Flexbox edge cases, web fonts loaded by script, emoji and complex text shaping that matches Chrome), a headless Chromium path is the right tool. You can self-host that with Playwright or Puppeteer, or use a hosted API so you never manage a Chromium binary at all.

How do you generate PDFs with PDF4.dev (the hosted Chromium path)?

PDF4.dev is a hosted REST API that renders HTML to PDF with headless Chromium server-side, so you POST HTML (or a saved template id plus data) and get a PDF back. Use it when you want browser-accurate rendering, JavaScript support, and no engine, font stack, or Chromium binary to install and maintain yourself.

Unlike WeasyPrint and Prince, PDF4.dev runs a real browser, so JS-rendered content, web fonts, and modern CSS layout behave the way they do in Chrome. It also supports Handlebars {{variables}} so you can store a template once and pass data per render. This is one option among the engines in this article, not a drop-in replacement for a print engine: if you specifically need float: footnote typesetting, Prince is still the specialist.

curl -X POST https://pdf4.dev/api/v1/render \
  -H "Authorization: Bearer p4_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<h1>Hello</h1>",
    "data": {},
    "delivery": "url"
  }'

You can also try the rendering without an account using the free HTML to PDFTry it free tool, which uses the same Chromium pipeline.

How much does each option cost?

WeasyPrint is free, Prince is a paid per-server license, and PDF4.dev is usage-based. The table below frames the cost shape, not exact numbers, since Prince and hosted pricing change over time. Check each vendor's pricing page for current figures.

OptionCost modelWhere the cost lives
WeasyPrintFree (BSD)Your servers + engineering time
PrincePer-server perpetual license, thousands USD/serverLicense fee + your servers
Headless Chromium (self-hosted)Free engineYour servers + Chromium ops + memory
PDF4.devUsage-based APIPer render, no infra to run

The hidden cost with WeasyPrint and self-hosted Chromium is operations: you maintain the Python and native library stack, or you keep a Chromium binary patched, memory-bounded, and warm. Prince removes the open-source maintenance but adds a license line item. A hosted API moves both into a per-render price.

For self-hosted Chromium, plan for memory. A headless Chromium process can use 100 to 300 MB of RAM per concurrent render, which is why a managed pool or a hosted API is often cheaper than it looks once you account for the instances you need to keep online.

Which option should you choose?

Choose by what your documents need and what you are willing to operate. There is no single winner: WeasyPrint, Prince, and a Chromium-based path each win a different scenario.

  • Invoices, receipts, quotes, statements, certificates, reports with standard CSS and no JavaScript: use WeasyPrint. Free, BSD-licensed, pip-installable, and more than enough for business documents.
  • Books, manuals, scientific papers, catalogs that need footnotes, cross-references, named page regions, and PDF/X output: use Prince. Its CSS print spec coverage is the widest and worth the license for print typesetting.
  • JavaScript-rendered HTML, charts drawn on canvas, SPA frameworks, web fonts loaded by script, or pixel-parity with Chrome: use a headless Chromium engine. Self-host with Playwright or Puppeteer if you want to run the browser, or use PDF4.dev if you want browser-accurate output with no Chromium to manage.
  • You want zero infrastructure and per-render pricing: use PDF4.dev. You POST HTML or a template id and get a PDF, no engine, font stack, or binary to maintain.

A common real-world setup mixes them: WeasyPrint for the high-volume invoice path where CSS is simple and cost matters, and a Chromium-based render for the marketing PDFs and dashboards that depend on JavaScript and exact browser fidelity.

Free tools mentioned:

Html To PdfTry it free

Start generating PDFs

Build PDF templates with a visual editor. Render them via API from any language in ~300ms.