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.
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)
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()
Comparison Summary
| Library | Install Size | CSS Support | Server-Friendly | Speed |
|---|---|---|---|---|
| pdfkit | ~10MB + binary | Excellent | Moderate | Fast |
| WeasyPrint | ~15MB | Very good | Excellent | Moderate |
| xhtml2pdf | ~5MB | Basic | Excellent | Fast |
| Playwright | ~300MB | Perfect | Good | Slow |
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 servers →
WeasyPrint(no system dependencies) - Maximum layout fidelity →
pdfkitwith wkhtmltopdf, or Playwright - Simple reports, scripts →
xhtml2pdf - 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
How to Convert HTML to PDF Free Online (No Signup Required)
Discover the easiest ways to convert HTML files and web pages to PDF format online — completely free, without watermarks or account registration.
Read Article
How to Save an HTML Email as PDF (Gmail, Outlook & Apple Mail)
Step-by-step instructions to save HTML emails as PDF in every major email client — and how to handle emails that print poorly.
Read Article
Convert HTML to PDF with JavaScript: Best Libraries Compared
A comprehensive comparison of the top JavaScript libraries for HTML-to-PDF conversion — jsPDF, Puppeteer, html2pdf.js, and more.
Read Article