# 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.