Comparison
A Python alternative to ReportLab
ReportLab is the standard Python library for programmatic PDF generation. Its drawing API and PLATYPUS layout engine work, but they require you to describe your document as a sequence of drawing calls rather than as HTML. Every pixel of margin, every font weight, every table cell needs to be expressed in Python. PDFPipe renders your HTML template, including the Tailwind or Bootstrap your team already uses, with a real browser and returns a PDF with one HTTP call.
ReportLab versus a PDF render API
| PDFPipe | ReportLab | |
|---|---|---|
| Template format | HTML + CSS (Jinja2, etc.) | Python drawing API (PLATYPUS / canvas) |
| Renders HTML | Yes, full browser engine | No (own layout model) |
| CSS support | Complete | None |
| Web fonts | Loaded automatically | Must embed manually as TTF |
| Images | Any URL or inline | Must encode or load from disk |
| JavaScript in template | Runs before capture | Not supported |
| Install size | None (HTTP call) | ~10 MB + GTK on some platforms |
| Designer workflow | Design in HTML, ship as PDF | Rewrite design in Python code |
The PLATYPUS problem
PLATYPUS (Page Layout and Typography Using Scripts) is ReportLab's high-level layout engine. It introduces its own box model, paragraph styles, table classes, and flowable primitives. To render an invoice you already have in HTML, you need to rewrite it entirely in PLATYPUS classes. Any time your design changes, you update both the HTML template your users see and the PLATYPUS code that renders the PDF. Two sources of truth diverge over time. PDFPipe has one: your template.
Fonts, images, and modern layouts
ReportLab requires TTF or OTF font files to be registered before use. Every Google Font or brand typeface your design team chose needs to be downloaded, stored with your app, and registered at startup. Flexbox, CSS Grid, and modern spacing utilities are unavailable. PDFPipe loads fonts from any URL, renders CSS Grid natively, and supports modern CSS including custom properties and clamp().
From Jinja2 to PDF in one call
import os
import requests
html = """
<html>
<body style="font-family: system-ui; padding: 40px">
<h1 style="color:#d23a1d">Invoice #4012</h1>
<p>Acme Corp · 12 June 2026</p>
<table style="width:100%;border-collapse:collapse;margin-top:24px">
<tr style="border-bottom:1px solid #ccc">
<td style="padding:8px">Design retainer</td>
<td style="padding:8px;text-align:right">$2,400</td>
</tr>
</table>
<h2 style="text-align:right;margin-top:24px">Total: $2,400</h2>
</body>
</html>
"""
res = requests.post(
"https://api.pdfpipe.xyz/v1/pdf",
headers={"Authorization": f"Bearer {os.environ['PDFPIPE_API_KEY']}"},
json={"html": html, "options": {"format": "A4"}},
)
res.raise_for_status()
with open("invoice.pdf", "wb") as f:
f.write(res.content)When to keep ReportLab
ReportLab is a good choice for pure Python environments with no external HTTP dependencies, where the document layout is simple and entirely code-driven, and where you need fine-grained control over PDF internals like encryption or custom metadata fields. For HTML-first workflows, web fonts, or modern CSS layouts, a render API produces better output with far less code.
Try it on the live playground with no signup. Full Python examples on the Python guide.
See pricing →