Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a new Python project, start with WeasyPrint when your HTML is print-oriented and depends on modern CSS or paged-media features. Choose xhtml2pdf when a ReportLab-backed Python API and explicit PDF controls matter more. Use wkhtmltopdf only when you specifically need its older WebKit rendering path, and treat its warning about untrusted HTML and JavaScript as a deployment requirement.

The right choice depends less on the shortest API call than on CSS fidelity, JavaScript requirements, native libraries, external assets, authentication, and how much control you need over the resulting PDF.

Quick comparison

Option Rendering approach Best fit Important constraints
WeasyPrint Python HTML/CSS-to-PDF engine Print documents using modern CSS and paged-media rules Python 3.10 or newer and Pango 1.44 or newer are required; the default fetcher does not handle advanced cookies or authentication
xhtml2pdf Python library built on ReportLab, html5lib and pypdf Mostly Python implementations needing metadata, encryption, signatures or resource policies HTML5, CSS 2.1 and some CSS 3 are supported; a rendering backend such as PyCairo is needed
wkhtmltopdf Standalone WebKit command-line binary Projects that must use its WebKit rendering path The stable 0.12.6 series was released in 2020; the project warns not to process untrusted HTML

There is no authoritative, cross-project benchmark that establishes one universal winner for speed or visual fidelity. Test your own templates, fonts, images, page breaks and workload before committing to a production choice.

1. WeasyPrint: the default starting point for print CSS

WeasyPrint is usually the first library to evaluate for invoices, reports, statements, brochures and other documents designed for paper or PDF rather than interactive browser behavior. Its engine understands print-oriented CSS and paged-media concepts, and its documented output supports hyperlinks, bookmarks, attachments, forms, SVG, raster images and other common document features.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
MixPad Free Multitrack Recording Studio and Music Mixing Software [Download]
  • Create a mix using audio, music and voice tracks and recordings.
  • Customize your tracks with amazing effects and helpful editing tools.
  • Use tools like the Beat Maker and Midi Creator.
  • Work efficiently by using Bookmarks and tools like Effect Chain, which allow you to apply multiple effects at a time
  • Use one of the many other NCH multimedia applications that are integrated with MixPad.

Install and verify prerequisites

Create an isolated environment and install the package:

python -m venv .venv
# macOS/Linux
source .venv/bin/activate
# Windows PowerShell: .venvScriptsActivate.ps1
python -m pip install --upgrade pip
python -m pip install weasyprint

The current documentation lists Python 3.10 or newer and Pango 1.44 or newer. On systems where Pango is not already available, install the platform’s Pango package before diagnosing Python-level errors.

Minimal conversion

from weasyprint import HTML

html = """

Invoice

Paid in full.

""" HTML(string=html).write_pdf("invoice.pdf")

For a template stored on disk, use HTML(filename="templates/invoice.html").write_pdf("invoice.pdf"). A document that references relative stylesheets or images should have a meaningful base URL:

from pathlib import Path
from weasyprint import HTML

source = Path("templates/invoice.html")
HTML(filename=str(source), base_url=str(source.parent.resolve())).write_pdf("invoice.pdf")

External resources, cookies and authentication

The default URL fetcher can read file and HTTP URLs, but it does not provide advanced cookie or authentication handling. If a PDF needs private logos, authenticated CSS or protected images, supply a controlled custom fetcher that adds credentials only to approved hosts. Do not pass arbitrary user-supplied URLs or credentials through that fetcher.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Useful CSS for page layout

@page {
  size: A4;
  margin: 18mm 15mm 20mm;
  @bottom-right { content: "Page " counter(page) " of " counter(pages); }
}

h1 { break-before: page; }
table { break-inside: avoid; }
tr { break-inside: avoid; }

Use print-specific styles rather than relying on a browser’s screen layout. Check font availability, long table rows, widows and orphans, links, and images at the actual paper size.

2. xhtml2pdf: a ReportLab-backed Python API

xhtml2pdf converts HTML through ReportLab, html5lib and pypdf. It is a practical choice when you want a Python-centered API and documented controls for PDF metadata, encryption, digital signatures, resource policies and error handling. It can write directly to a file-like object, which is useful for HTTP responses or object storage.

Install and convert to a file

python -m pip install xhtml2pdf
from pathlib import Path
from xhtml2pdf import pisa

html = Path("templates/report.html").read_text(encoding="utf-8")
with open("report.pdf", "wb") as output:
    result = pisa.CreatePDF(html, dest=output)

if result.err:
    raise RuntimeError(f"PDF conversion reported {result.err} error(s)")

For current releases, the project recommends using the PyCairo extra or backend for ReportLab rendering. Confirm the native rendering dependency on your operating system if installation succeeds but PDF creation fails.

Return PDF bytes from memory

from io import BytesIO
from xhtml2pdf import pisa

def html_to_pdf_bytes(html: str) -> bytes:
    buffer = BytesIO()
    result = pisa.CreatePDF(html, dest=buffer)
    if result.err:
        raise ValueError(f"Conversion failed with {result.err} error(s)")
    return buffer.getvalue()

pdf_bytes = html_to_pdf_bytes("

Monthly report

") # Example web response: return Response(pdf_bytes, mimetype="application/pdf")

When diagnosing malformed markup or unsupported CSS, enable the library’s exception behavior in the version you use and inspect the returned status instead of silently serving a partial document.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. wkhtmltopdf: use the WebKit binary deliberately

wkhtmltopdf is not a pure Python library. It is a command-line converter based on a WebKit rendering path. Install the official platform binary, then call it directly or through a Python wrapper. Its official download page identifies version 0.12.6 as the stable series, released on 2020-06-11, so its browser behavior is substantially older than current Chromium-based engines.

Direct command

wkhtmltopdf input.html output.pdf

Calling it from Python

import subprocess

subprocess.run(
    ["wkhtmltopdf", "input.html", "output.pdf"],
    check=True,
    timeout=90,
)

Use an absolute executable path when the service account’s PATH differs from your shell. Capture standard error and exit codes so failed conversions do not produce a misleading success response.

Security boundary

The project explicitly warns: “Do not use wkhtmltopdf with any untrusted HTML.” Sanitize user-controlled HTML and JavaScript, isolate the conversion process, restrict outbound network access, and avoid exposing sensitive files or environment credentials to the converter. This warning is especially important for multi-tenant services.

How to choose

Choose WeasyPrint when

  • Your templates are designed for print and use modern CSS or paged-media rules.
  • You want a Python API without launching a browser process.
  • Bookmarks, links, forms, attachments and SVG/raster images are part of the document.
  • You can install and operate Pango and can provide a controlled fetcher for protected assets.

Choose xhtml2pdf when

  • ReportLab’s document pipeline fits your application.
  • You need documented metadata, encryption, signatures or resource-policy controls.
  • You want file output and in-memory output through the same API.
  • Your markup fits its HTML5, CSS 2.1 and partial CSS 3 support.

Choose wkhtmltopdf when

  • A legacy system already depends on its WebKit rendering behavior.
  • A separate binary is acceptable operationally.
  • You can strictly sanitize and isolate every HTML/JavaScript input.

Testing for fidelity and production readiness

  1. Build a representative fixture. Include long tables, nested lists, web fonts, SVG, raster images, links, page breaks, headers, footers and right-to-left or non-Latin text if your users need them.
  2. Render at the target paper size. Compare A4 and Letter separately; margins and page-break behavior can change pagination.
  3. Inspect resources. Test missing images, slow URLs, redirects, TLS failures, protected assets and relative paths.
  4. Exercise failure handling. Verify that your worker reports dependency errors, converter exit codes and partial output instead of returning a corrupt PDF.
  5. Measure your workload. Record conversion time, memory, queue depth and output size for your actual templates. No official universal throughput or fidelity score exists.

Troubleshooting

Import or shared-library errors with WeasyPrint

Confirm Python is 3.10 or newer and that Pango 1.44 or newer is installed and discoverable. Recreate the virtual environment after changing system libraries.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Images or CSS are missing

Set a correct base_url for string or file-based HTML, use absolute paths where appropriate, and verify that the converter process can read every asset. For private HTTP resources, implement an allow-listed authenticated fetcher rather than embedding unrestricted credentials.

xhtml2pdf reports errors or creates incomplete pages

Check the returned result.err, simplify unsupported CSS, validate the HTML, and install the recommended PyCairo backend. Test complex tables and page breaks independently.

wkhtmltopdf works locally but fails in a service

Use the full binary path, ensure the service account has permission to execute it, capture stderr, and set an explicit timeout. Check sandbox, filesystem and network restrictions before loosening them.

Rank #4
DeskFX Free Audio Effects & Audio Enhancer Software [PC Download]
  • Transform audio playing via your speakers and headphones
  • Improve sound quality by adjusting it with effects
  • Take control over the sound playing through audio hardware

JavaScript-dependent pages are blank

These tools are not interchangeable browser automation systems. If the source page requires client-side rendering, first produce a stable HTML snapshot or select a browser-based capture workflow rather than assuming a Python HTML-to-PDF engine will run the application’s JavaScript.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Or skip the browser setup

If your goal is a PDF or image of a live URL rather than rendering a Python template, ScreenshotNeo provides a website screenshot API and MCP server. One request can return PNG, JPEG, WebP or PDF, with options for full-page capture, lazy-loaded images, CSS selectors, dark mode, device and retina settings, custom CSS and JavaScript, waits, blocked resources, headers, cookies, user agents, timezone, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous webhooks and bulk capture.

Its cleanup step accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets before capture; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status. The MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.

See the complete parameter reference in the ScreenshotNeo documentation. A direct PDF request can be made with the same endpoint:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

The Free plan includes 1,000 shots each month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to try it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Frequently Asked Questions

Can these libraries convert a Jinja or Django template?

Yes. Render the template to a complete HTML string first, then pass that string to WeasyPrint or xhtml2pdf, or write it to a temporary file for wkhtmltopdf. Keep template rendering and PDF conversion as separate steps so missing variables are caught before conversion.

Best Value
WavePad Audio Editing Software - Professional Audio and Music Editor for Anyone [Download]
  • Full-featured professional audio and music editor that lets you record and edit music, voice and other audio recordings
  • Add effects like echo, amplification, noise reduction, normalize, equalizer, envelope, reverb, echo, reverse and more
  • Supports all popular audio formats including, wav, mp3, vox, gsm, wma, real audio, au, aif, flac, ogg and more
  • Sound editing functions include cut, copy, paste, delete, insert, silence, auto-trim and more
  • Integrated VST plugin support gives professionals access to thousands of additional tools and effects

Which option should run in a serverless function?

There is no universal answer. WeasyPrint and xhtml2pdf avoid a browser process but still need native libraries; wkhtmltopdf requires packaging a compatible executable. Build and test the exact deployment image rather than choosing from the Python API alone.

How should I handle fonts?

Install the required fonts in the conversion environment, declare them explicitly in print CSS, and test glyph coverage for every supported language. A font available on a developer laptop is not automatically available to a worker or container.

Should I use a screenshot API for HTML templates?

Use a Python converter for controlled template-to-document workflows. Use a screenshot or PDF API when the source is a live URL and you want remote browser capture, consent cleanup, URL-level waits, or an MCP workflow.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The Bottom Line

Evaluate WeasyPrint first for modern, print-focused CSS; choose xhtml2pdf for ReportLab-backed PDF controls; reserve wkhtmltopdf for deliberate legacy WebKit use behind a strong security boundary. Validate the decision with your own documents and deployment environment.

Quick Recap

Bestseller No. 1
MixPad Free Multitrack Recording Studio and Music Mixing Software [Download]
MixPad Free Multitrack Recording Studio and Music Mixing Software [Download]
Create a mix using audio, music and voice tracks and recordings.; Customize your tracks with amazing effects and helpful editing tools.
Bestseller No. 4
DeskFX Free Audio Effects & Audio Enhancer Software [PC Download]
DeskFX Free Audio Effects & Audio Enhancer Software [PC Download]
Transform audio playing via your speakers and headphones; Improve sound quality by adjusting it with effects

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.