HTML to PDF January 11, 2026 · 8 min read

HTML to PDF with Python: wkhtmltopdf, WeasyPrint & pdfkit Guide

Learn how to convert HTML to PDF in Python using pdfkit, WeasyPrint, and xhtml2pdf — with code examples and pros & cons for each approach.

HTML to PDF with Python: wkhtmltopdf, WeasyPrint & pdfkit Guide
AT

AltoUnlockPDF Team

PDF Tools Expert

Python is a popular choice for automating document generation. If you’re building a Django web app, a data pipeline, or a reporting script, you’ll eventually need to convert HTML templates to PDF. Fortunately, Python has several excellent libraries for this.


Option 1: pdfkit (wkhtmltopdf wrapper)

pdfkit is a Python wrapper around the wkhtmltopdf command-line tool. It’s one of the most popular options because it produces near-browser-quality output.

Installation

pip install pdfkit
# Also install wkhtmltopdf:
# macOS: brew install wkhtmltopdf
# Ubuntu: sudo apt install wkhtmltopdf
# Windows: download from https://wkhtmltopdf.org/downloads.html

Usage

import pdfkit

# From HTML string
pdfkit.from_string('<h1>Hello World</h1>', 'output.pdf')

# From file
pdfkit.from_file('template.html', 'output.pdf')

# From URL
pdfkit.from_url('https://example.com', 'output.pdf')

# With options
options = {
    'page-size': 'A4',
    'margin-top': '15mm',
    'margin-right': '12mm',
    'margin-bottom': '15mm',
    'margin-left': '12mm',
    'encoding': 'UTF-8',
    'enable-local-file-access': None
}
pdfkit.from_string(html_content, 'report.pdf', options=options)
Python code for PDF generation

Pros: Excellent CSS support, handles most layouts
Cons: Requires external binary (wkhtmltopdf), can fail silently on servers


Option 2: WeasyPrint — Pure Python, No System Dependencies

WeasyPrint is a pure Python library that renders HTML/CSS to PDF. Unlike pdfkit, it doesn’t require external binaries, making it easier to deploy on cloud servers.

Installation

pip install weasyprint

Usage

from weasyprint import HTML, CSS

# From HTML string
HTML(string='<h1>Hello World</h1>').write_pdf('output.pdf')

# From file
HTML(filename='report.html').write_pdf('output.pdf')

# With custom CSS
html = HTML(string=html_content)
css = CSS(string='@page { size: A4; margin: 15mm; }')
html.write_pdf('output.pdf', stylesheets=[css])

Pros: Pure Python, excellent CSS3 support, actively maintained
Cons: Slower than pdfkit for complex documents, some CSS features not supported


Option 3: xhtml2pdf (Reportlab-based)

xhtml2pdf uses Reportlab under the hood and is excellent for simple templates.

pip install xhtml2pdf
from xhtml2pdf import pisa
import io

html_content = "<h1>Invoice</h1><p>Amount: $500</p>"
result_file = open("output.pdf", "w+b")
pisa_status = pisa.CreatePDF(html_content, dest=result_file)
result_file.close()

Option 4: Playwright (Headless Chromium)

For the highest-fidelity output — identical to what Chrome renders — use Python’s Playwright:

pip install playwright
playwright install chromium
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()
    page.set_content(html_content)
    page.pdf(path="output.pdf", format="A4", print_background=True)
    browser.close()
PDF files generated from HTML templates

Comparison Summary

LibraryInstall SizeCSS SupportServer-FriendlySpeed
pdfkit~10MB + binaryExcellentModerateFast
WeasyPrint~15MBVery goodExcellentModerate
xhtml2pdf~5MBBasicExcellentFast
Playwright~300MBPerfectGoodSlow

Django Integration Example

Here’s how to return a PDF response in a Django view:

from django.http import HttpResponse
import pdfkit

def generate_invoice(request, invoice_id):
    invoice = Invoice.objects.get(pk=invoice_id)
    html = render_to_string('invoices/invoice.html', {'invoice': invoice})
    pdf = pdfkit.from_string(html, False)  # False = return bytes, not save to file
    response = HttpResponse(pdf, content_type='application/pdf')
    response['Content-Disposition'] = f'attachment; filename="invoice-{invoice_id}.pdf"'
    return response

Recommendation

  • Django/Flask web apps on Linux serversWeasyPrint (no system dependencies)
  • Maximum layout fidelitypdfkit with wkhtmltopdf, or Playwright
  • Simple reports, scriptsxhtml2pdf
  • Complex, JavaScript-rendered pages → Playwright

For most Django projects, WeasyPrint has become the community standard due to its ease of deployment and solid CSS support.

Related Articles