---
name: weasyprint
description: >-
WeasyPrint HTML/CSS-to-PDF expert skill (Kozea/CourtBouillon). CLI, Python API,
@page paged media, PDF/A/UA/X, Factur-X, URL fetchers, FontConfiguration, server
security. MUST use for: (1) untrusted HTML on servers, (2) PDF/A or PDF/UA,
(3) Factur-X/ZUGFeRD, (4) print-pagination CSS. Triggers: WeasyPrint, HTML-to-PDF,
invoices, reports, @page, footnotes, CourtBouillon. Always open
references/resource-matrix.md first when scope is unclear — before any other file.
WeasyPrint
Pagination-first CSS engine (Python + Pango). Not headless Chrome: no JS, no RTL/bidi, print media default.
MANDATORY — read first when scope is unclear: references/resource-matrix.md
Load one flat expert lesson from references/ root (e.g. security-untrusted-html.md, css-paged-media.md). Do not open full-docs/ unless the matrix sends you there as last resort.
Before You Act
- Trust — Untrusted HTML/CSS? →
security-untrusted-html.md + security-url-fetcher.md (before code).
- Runtime — CLI one-off (
cli-basics.md), batch, or embedded Python (python-instantiation.md)?
- Output — Plain PDF, PDF/A/UA/X (
pdf-*.md), Factur-X, fillable forms?
- Wrong tool? — JS layout, RTL, live DOM, pixel-perfect screen CSS → Puppeteer, not WeasyPrint.
Debug Bisect (wrong output)
debug-pipeline.md — enable logging; unsupported CSS fails silently by default.
css-browser-vs-print.md — print vs browser gaps?
- Closest sample from
resource-matrix.md Examples catalog — ≤120 lines of relevant .css.
- Still blocked? One matching flat lesson from the matrix.
full-docs/ only as last resort (≤120 lines/§).
NEVER
- NEVER use positional string HTML or omit
base_url on HTML(string=...) — see python-instantiation.md.
- NEVER enable
presentational_hints on untrusted HTML — CVE-2026-49452; see security-untrusted-html.md.
- NEVER expose untrusted HTML without process limits + fetcher blocking
file://.
- NEVER set page size via imagined CLI flags — only
@page or -s; see cli-basics.md.
- NEVER assume PDF/A validity without
image-rendering: crisp-edges + user-side validation — see pdf-a-archival.md.
- NEVER expect
:hover, :focus, :visited to match; NEVER rely on RTL/bidi — see css-browser-vs-print.md.
- NEVER use
zoom != 1 casually — scales all units including cm and A4.
- NEVER bulk-load
full-docs/ or example .pdf files.
- NEVER load
full-docs/contribute.md or full-docs/support.md.
Common Failures → Fix
| Symptom |
Lesson |
cannot load library 'pango...' |
install-windows.md or install-macos.md + install-troubleshooting.md |
| Tofu / blank text |
css-fonts.md |
| Broken relative assets |
python-instantiation.md (base_url=) |
| Styles ≠ browser |
css-browser-vs-print.md |
| Dual screen+print dashboard (nav/hover) |
Prefer flex; no hover-only content; @media print hides screen chrome; css-browser-vs-print.md |
| Auth assets 404 |
web-flask-django.md |
| PDF/A rejected |
pdf-a-archival.md |
| SSRF / file read |
security-url-fetcher.md |
| Slow batch renders |
web-performance.md |
Platform Quick Pointers
| Platform |
Start here |
| Linux |
install-linux.md |
| Windows |
install-windows.md |
| macOS |
install-macos.md |
| Any install failure |
install-troubleshooting.md |
Expert Notes
- Versions: major bumps change rendering — see
debug-version-upgrades.md; visual diff PDFs on upgrade.
- Performance: cascade cost ∝ selectors × elements; multi-page tables are slow — see
web-performance.md.
- Defaults:
presentational_hints=False; finisher(document, pdf) hooks pydyf before trailer.
1---2name: weasyprint3description: ---4---5---6name: weasyprint7description: >-8 WeasyPrint HTML/CSS-to-PDF expert skill (Kozea/CourtBouillon). CLI, Python API,9 @page paged media, PDF/A/UA/X, Factur-X, URL fetchers, FontConfiguration, server10 security. MUST use for: (1) untrusted HTML on servers, (2) PDF/A or PDF/UA,11 (3) Factur-X/ZUGFeRD, (4) print-pagination CSS. Triggers: WeasyPrint, HTML-to-PDF,12 invoices, reports, @page, footnotes, CourtBouillon. Always open13 references/resource-matrix.md first when scope is unclear — before any other file.14---1516# WeasyPrint1718Pagination-first CSS engine (Python + Pango). Not headless Chrome: **no JS, no RTL/bidi, print media default**.1920**MANDATORY — read first when scope is unclear**: [`references/resource-matrix.md`](references/resource-matrix.md)2122Load **one** flat expert lesson from `references/` root (e.g. `security-untrusted-html.md`, `css-paged-media.md`). Do not open `full-docs/` unless the matrix sends you there as last resort.2324## Before You Act25261. **Trust** — Untrusted HTML/CSS? → `security-untrusted-html.md` + `security-url-fetcher.md` (before code).272. **Runtime** — CLI one-off (`cli-basics.md`), batch, or embedded Python (`python-instantiation.md`)?283. **Output** — Plain PDF, PDF/A/UA/X (`pdf-*.md`), Factur-X, fillable forms?294. **Wrong tool?** — JS layout, RTL, live DOM, pixel-perfect screen CSS → Puppeteer, not WeasyPrint.3031## Debug Bisect (wrong output)32331. [`debug-pipeline.md`](references/debug-pipeline.md) — enable logging; unsupported CSS fails silently by default.342. [`css-browser-vs-print.md`](references/css-browser-vs-print.md) — print vs browser gaps?353. Closest sample from [`resource-matrix.md`](references/resource-matrix.md) Examples catalog — ≤120 lines of relevant `.css`.364. Still blocked? One matching flat lesson from the matrix. **`full-docs/` only as last resort** (≤120 lines/§).3738## NEVER3940- **NEVER** use positional string HTML or omit `base_url` on `HTML(string=...)` — see `python-instantiation.md`.41- **NEVER** enable `presentational_hints` on untrusted HTML — CVE-2026-49452; see `security-untrusted-html.md`.42- **NEVER** expose untrusted HTML without process limits + fetcher blocking `file://`.43- **NEVER** set page size via imagined CLI flags — only `@page` or `-s`; see `cli-basics.md`.44- **NEVER** assume PDF/A validity without `image-rendering: crisp-edges` + user-side validation — see `pdf-a-archival.md`.45- **NEVER** expect `:hover`, `:focus`, `:visited` to match; **NEVER** rely on RTL/bidi — see `css-browser-vs-print.md`.46- **NEVER** use `zoom != 1` casually — scales all units including `cm` and `A4`.47- **NEVER** bulk-load `full-docs/` or example `.pdf` files.48- **NEVER** load `full-docs/contribute.md` or `full-docs/support.md`.4950## Common Failures → Fix5152| Symptom | Lesson |53|---------|--------|54| `cannot load library 'pango...'` | `install-windows.md` or `install-macos.md` + `install-troubleshooting.md` |55| Tofu / blank text | `css-fonts.md` |56| Broken relative assets | `python-instantiation.md` (`base_url=`) |57| Styles ≠ browser | `css-browser-vs-print.md` |58| Dual screen+print dashboard (nav/hover) | Prefer flex; no hover-only content; `@media print` hides screen chrome; `css-browser-vs-print.md` |59| Auth assets 404 | `web-flask-django.md` |60| PDF/A rejected | `pdf-a-archival.md` |61| SSRF / file read | `security-url-fetcher.md` |62| Slow batch renders | `web-performance.md` |6364## Platform Quick Pointers6566| Platform | Start here |67|----------|------------|68| Linux | `install-linux.md` |69| Windows | `install-windows.md` |70| macOS | `install-macos.md` |71| Any install failure | `install-troubleshooting.md` |7273## Expert Notes7475- **Versions**: major bumps change **rendering** — see `debug-version-upgrades.md`; visual diff PDFs on upgrade.76- **Performance**: cascade cost ∝ selectors × elements; multi-page tables are slow — see `web-performance.md`.77- **Defaults**: `presentational_hints=False`; `finisher(document, pdf)` hooks pydyf before trailer.78