WeasyPrint
Overview
WeasyPrint is an open-source Python library that renders HTML/CSS documents to PDF.
It lets developers use HTML/CSS as input for generating PDFs.
Installation
Install via pip:
pip install weasyprint Alternative installation methods:
- Poetry:
poetry add weasyprint - Conda:
conda install -c conda-forge weasyprint - Pipenv:
pipenv install weasyprint - pipx (command-line only):
pipx install weasyprint
Core Features
Multiple Usage Modes
- Standalone command-line tool
- Python library for programmatic control
- Integration with web frameworks
HTML Input Sources
- File pointers
- Filenames
- URLs
- HTML strings
- File-like objects
CSS Support
- Inline stylesheets
- External stylesheets
- CSS variables
- Media queries
- Custom fonts via
@font-face
Document Manipulation
- Page-level access and control
- Extract specific pages
- Split documents (odd/even pages)
- Access page dimensions and information
- Zoom control
Metadata and Structure
- Bookmark/outline generation
- Hyperlink extraction
- Document metadata access
- Page count tracking
- Custom PDF properties
Basic Usage Examples
Simplest Approach: URL to PDF
from weasyprint import HTML
HTML('http://weasyprint.org/').write_pdf('/tmp/weasyprint-website.pdf') From HTML String
from weasyprint import HTML
html_string = '<h1>Hello World</h1><p>This is a PDF</p>'
HTML(string=html_string).write_pdf('/tmp/output.pdf') With Inline CSS
from weasyprint import HTML, CSS
HTML('http://weasyprint.org/').write_pdf(
'/tmp/output.pdf',
stylesheets=[CSS(string='body { font-family: serif !important }')]
) Advanced Features
Custom Fonts
from weasyprint import HTML, CSS, FontConfiguration
font_config = FontConfiguration()
html = HTML(string='<h1>The title</h1>')
css = CSS(string='''
@font-face {
font-family: Gentium;
src: url(http://example.com/fonts/Gentium.otf);
}
h1 { font-family: Gentium }
''', font_config=font_config)
html.write_pdf('/tmp/output.pdf', stylesheets=[css], font_config=font_config) Document Page Access
from weasyprint import HTML
document = HTML(string='<h1>Multi-page Document</h1>').render()
# Write odd pages
document.copy(document.pages[::2]).write_pdf('odd_pages.pdf')
# Write even pages
document.copy(document.pages[1::2]).write_pdf('even_pages.pdf') Bookmark Tree Generation
def print_outline(bookmarks, indent=0):
for i, (label, (page, _, _), children) in enumerate(bookmarks, 1):
print('%s%d. %s (page %d)' % (
' ' * indent, i, label.lstrip('0123456789. '), page))
print_outline(children, indent + 2)
document = HTML(string='...').render()
print_outline(document.make_bookmark_tree()) Custom URL Fetcher
from weasyprint import default_url_fetcher, HTML
def my_fetcher(url):
if url.startswith('graph:'):
graph_data = map(float, url[6:].split(','))
return dict(
string=generate_graph(graph_data),
mime_type='image/png'
)
else:
return default_url_fetcher(url)
HTML(
string='<img src="graph:42,10.3,87">',
url_fetcher=my_fetcher
).write_pdf('out.pdf') Zoom and Page Control
from weasyprint import HTML
html = HTML(string='<h1>Zoomed Document</h1>')
# Scale CSS units (zoom factor)
html.write_pdf('output.pdf', zoom=2.0) Page-Level Painting
from weasyprint import HTML
document = HTML(string='...').render()
# Access individual pages for custom painting with pydyf
for page in document.pages:
# Custom page operations
pass Practical Use Cases
Statistical Reports
- Transform data analysis results into formatted documents
- Combine charts and tables with calculated values
Invoices and Receipts
- Generate formatted billing documents
- Include company branding and customization
Certificates
- Create personalized documents with variable data
- Support for images, custom fonts, and styling
Documentation
- Convert web-based documentation to PDF format
- Maintain styling consistency between web and PDF
Tickets and Passes
- Generate event tickets, boarding passes, etc.
- Dynamic content with consistent formatting
Email Attachments
- Generate PDF reports on-the-fly
- Attach to automated emails
Key Capabilities
CSS Features Supported
- Flexbox
- Grid (limited)
- Media queries
- Transforms
- Animations (limited)
- Custom properties
- Pseudo-classes and pseudo-elements
Output Control
- Resolution (DPI) adjustment
- Paper size presets (A4, Letter, etc.)
- Custom dimensions
- Margins and bleed
- Multiple output formats via CLI
Command-Line Usage
# Basic conversion
weasyprint https://example.com output.pdf
# From file
weasyprint input.html output.pdf
# With options
weasyprint --resolution 300 input.html output.pdf Rendering Engine
WeasyPrint uses:
- Pango for text layout
- pydyf for PDF generation (current versions no longer use Cairo; the docs list Pango, pydyf, CFFI, tinycss2, Pillow and fontTools)
- Pillow for image processing
- cffi for C library bindings
Strengths (author’s view)
✅ Open source - BSD-3-Clause licence (GitHub API; the earlier note said MIT, which was wrong)
✅ Python-native - usable as a Python library and CLI
✅ Web standards support - Uses familiar HTML/CSS syntax
✅ Programmatic control - Python API for rendering and page access
✅ Custom fonts - via @font-face (font-format coverage not verified)
✅ Document structure - Bookmark and outline generation
✅ Flexible input - URLs, files, strings all supported
✅ No browser required - needs the Pango system library, not a browser engine
Limitations
❌ JavaScript not supported - No dynamic content execution
❌ Limited CSS support - Some advanced CSS features unsupported
❌ Performance - relative speed vs other tools not measured here
❌ Image handling - image-format coverage vs browsers not verified
❌ Grid layout - Only partial CSS Grid support
❌ Platform dependencies - Requires Pango 1.44+ and Python 3.10+ (WeasyPrint 70.0 docs); Windows needs the release executable or MSYS2
Comparison (author’s opinion; not benchmarked)
vs ReportLab
- WeasyPrint: HTML/CSS-based, familiar web syntax
- ReportLab: Programmatic, more control, lower-level API
vs Puppeteer/Playwright
- WeasyPrint: Lightweight, no browser required
- Puppeteer: runs JavaScript in a browser engine
vs Commercial Tools (iText, PDFKit)
- WeasyPrint: open source
- Commercial: more features and support are assumed, not verified
Related Tools
- ReportLab - Programmatic PDF generation for Python
- Puppeteer - Browser-based PDF generation
- Jinja2 - Template engine for dynamic HTML generation
Examples Repository
The earlier note listed these example topics (not re-verified against the docs):
- Invoice generation
- Reports with charts
- Certificates
- Brochures
Version and licence
Latest release seen: v70.0 (2026-09-08); BSD-3-Clause licence; ~9.7k GitHub stars (2026-10-05); maintained by Kozea / CourtBouillon (https://weasyprint.org/).
Sources
- https://doc.courtbouillon.org/weasyprint/stable/first_steps.html (fetched 2026-10-05)
- GitHub API for Kozea/WeasyPrint (fetched 2026-10-05)
Open items
- Limitation list (partial CSS Grid, image formats, relative speed) comes from the earlier text and was not re-verified.
- Install-method list (Poetry, Conda, pipx) not re-checked; docs fetched list distro packages, Homebrew and a Windows executable.