# WeasyPrint alternative WeasyPrint alternative: WeasyPrint has great print CSS but no JavaScript and partial flexbox and grid. See when Chrome rendering fits better. **Quick answer.** If your HTML needs JavaScript, modern flexbox or grid, use a Chromium renderer. With html-pdf.com it is one call. ```bash curl https://html-pdf.com/v1/pdf \ -H "Authorization: Bearer $HTML_PDF_KEY" \ -H "Content-Type: application/json" \ -d '{"html": "

Hello

", "format": "A4"}' \ -o report.pdf ``` WeasyPrint is a BSD-licensed Python library that turns HTML and CSS into PDF with its own layout engine. It is one of the best tools for print-focused CSS. It is also not a browser, which matters when your HTML depends on JavaScript or modern layout. This page is a fair look at both sides. ## What WeasyPrint does well These are the areas where WeasyPrint is strong. - **Paged media CSS.** `@page` rules, named pages, margin boxes for running headers and footers, `counter(page)` and `counter(pages)`, page-based cross references, and footnotes. - **Typesetting features** aimed at books, reports, and documentation. - **No browser to install.** Pure Python plus system libraries (Pango), so it runs offline and in locked-down environments. - **Permissive license.** BSD, free for commercial use. ```css @page { size: A4; margin: 20mm; @bottom-center { content: "Page " counter(page) " of " counter(pages); } } ``` ## Where WeasyPrint falls short These are the limits you are most likely to hit. - **No JavaScript.** Scripts don't run, so charts (Chart.js, D3, ECharts), client-rendered tables, and SPA pages come out empty. You would have to pre-render charts to SVG or images. - **Partial flexbox.** The docs describe flex support as working for simple cases but not deeply tested. - **Basic grid.** `display: grid`, grid areas, and `fr` work. Features like `auto-fill`/`auto-fit`, subgrid, and intrinsic sizing aren't supported. - **Different from the browser.** Because it is a separate engine, a page that looks right in Chrome can lay out differently. You debug in the PDF rather than DevTools. - **System dependencies.** Pango and related libraries need to be installed in Docker images and on some platforms. ## Comparison This table compares WeasyPrint, self-hosted Chromium and the html-pdf.com API side by side. | | WeasyPrint | Playwright/Puppeteer (self-hosted) | html-pdf.com API | |---|---|---|---| | Engine | Own layout engine | Chromium | Chromium (hosted) | | JavaScript | No | Yes | Yes | | Flexbox / grid | Partial / basic | Full | Full | | Margin boxes (`@top-center` etc.) | Yes | Yes (Chrome 131+) | Yes, or `header_html` / `footer_html` | | Running headers, page counters | Yes, in CSS | Header/footer templates | `header_html` / `footer_html` | | Footnotes, cross references | Yes | No | No | | Works offline | Yes | Yes | No | | License / cost | BSD, free | Free + servers | 1 credit per page | ## When WeasyPrint is the better choice WeasyPrint is the right pick in these cases. - **Print-CSS-heavy documents** like books, manuals, and reports that rely on footnotes and page-based cross references. Chrome handles margin boxes and page counters, but not these. - **Offline or air-gapped** systems, or when content must never leave your servers. - **Static HTML** with no JavaScript and simple layouts. If that is your case, WeasyPrint is likely a better fit than any Chrome-based tool. ## When Chrome rendering fits better Chrome is the better choice when your PDF should match what the browser shows. - The HTML is the same page your app shows in the browser, built with flexbox, grid, or Tailwind. - You need **charts or other JavaScript** to run before printing. - You want to convert a **live URL** as it looks in Chrome. - You don't want to maintain Pango or Chrome in your images. Chrome supports `@page` size and margins, `break-before`, `break-after`, and `break-inside`. Since Chrome 131 it also renders `@page` margin boxes such as `@bottom-center { content: counter(page) }`. That means most WeasyPrint running headers and page numbers work as-is, and header and footer templates are an alternative. ## Python example This example renders a Chart.js report with a CSS grid and page numbers. ```python import os import requests html = """

Monthly report

Revenue: $12,400
Orders: 318
""" resp = requests.post( "https://html-pdf.com/v1/pdf", headers={"Authorization": f"Bearer {os.environ['HTML_PDF_KEY']}"}, json={ "html": html, "format": "A4", "margin": {"top": "15mm", "right": "12mm", "bottom": "20mm", "left": "12mm"}, "footer_html": '
' 'Page of
', "wait_for_expression": "window.chartReady === true", "max_pages": 20, }, timeout=40, ) resp.raise_for_status() with open("report.pdf", "wb") as f: f.write(resp.content) ``` `wait_for_expression` holds the print until the chart has drawn. Turning off Chart.js animation avoids capturing a half-drawn chart. The bottom margin leaves room for `footer_html`. ## Mapping WeasyPrint habits Use this table to translate common WeasyPrint calls to html-pdf.com options. | WeasyPrint | html-pdf.com | |---|---| | `HTML(string=html).write_pdf("out.pdf")` | `{"html": html}` and save `resp.content` | | `HTML(url).write_pdf(...)` | `{"url": "https://..."}` (public pages) | | `@page { size: A4 landscape }` | Keep it with `prefer_css_page_size`, or `format` + `landscape` | | `@bottom-center { content: counter(page) }` | works as-is (Chrome 131+), or `footer_html` with `pageNumber` / `totalPages` | | `stylesheets=[CSS(...)]` | `"css": "..."` | | `media_type="print"` | `"media": "print"` | ## Or skip the server If you would rather not run any renderer, use the hosted API. html-pdf.com is an HTML/URL to PDF API on headless Chromium. `POST https://html-pdf.com/v1/pdf` with a Bearer key and `{"html": "..."}` or `{"url": "https://..."}` returns a PDF with selectable text, as binary, base64, or a 24-hour link. 1 credit = 1 PDF page. You get 100 free credits once, then packs from $10 for 1,000 pages down to $0.005 per page, and purchased credits never expire. AI assistants can also use it through the [remote MCP server](https://html-pdf.com/pdf-mcp-server). [Get a free API key](https://html-pdf.com/login) · [API docs](https://html-pdf.com/docs) · [HTML to PDF in Python](https://html-pdf.com/html-to-pdf-python) · [Page breaks](https://html-pdf.com/html-to-pdf-page-breaks) · [Templates](https://html-pdf.com/templates) ## FAQ ### What is the best alternative to WeasyPrint? If your HTML uses JavaScript, charts, or modern flexbox and grid, a Chromium renderer like Playwright, Puppeteer or the html-pdf.com API is the closest fit. For footnote-heavy print documents, WeasyPrint is still a strong choice. ### Does WeasyPrint support JavaScript? No. WeasyPrint does not run scripts, so charts and client-rendered content come out empty unless you pre-render them to SVG or images. ### Can Chrome do CSS page numbers like WeasyPrint? Yes. Since Chrome 131, `@page` margin boxes such as `@bottom-center { content: "Page " counter(page) " of " counter(pages) }` work, and you can use `prefer_css_page_size` to keep your CSS page size. You can also use `footer_html` instead. ### Is WeasyPrint free? Yes, it is BSD-licensed and free for commercial use. html-pdf.com charges 1 credit per PDF page, with 100 free credits to start and no card needed.