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
  • 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

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.