Design pixel-perfect print formats with Jinja2 templates, rendered by WeasyPrint or Playwright — with repeating headers, page numbers, QR codes, and multi-copy output.
FrapPDFy handles the hard parts — layout, measurement, multi-copy, and remote delegation — so you can focus on your template design.
Choose WeasyPrint for CSS paged media and counters, or Playwright (Chromium) for full CSS/JS support. Selectable per template, with automatic fallback.
Define .pdf-header and .pdf-footer. Heights are auto-measured so content is never clipped or overlapping.
CSS counter-based page numbers for WeasyPrint (counter(page)) and Chromium template classes for Playwright.
Generate Original / Duplicate / Triplicate in one PDF. Inject different text into each copy using CSS class selectors and a simple JSON config.
Render e-Invoice QR codes via Frappe Web Template blocks. Size them with a simple CSS class override.
Automatically resolves Frappe Attach field values to absolute URLs so images always render correctly in the PDF, regardless of engine.
Offload PDF rendering to a dedicated remote Frappe site. Useful when production sites can't run Playwright or need isolated rendering capacity.
Remote delegation uses Frappe's standard token authentication. API secrets are stored encrypted in the database.
Enable verbose logging per template. Every measurement, margin calculation, and routing decision is logged with a unique error code for easy tracing.
From a Frappe document to a downloaded PDF in five clean steps.
frappe.render_template(), producing a static HTML string with real data..pdf-header, .pdf-content, and .pdf-footer.application/pdf download.Both engines are supported. The right choice depends on your template's CSS requirements and server environment.
| Feature | WeasyPrint | Playwright (Chromium) |
|---|---|---|
CSS Paged Media (@page) | ✅ Full support | ❌ Not supported |
| CSS counters for page numbers | ✅ | ❌ |
| JavaScript rendering | ❌ | ✅ |
| Flexbox & CSS Grid | ⚠️ Partial | ✅ Full |
| Background images in headers | ✅ | ✅ |
| Minimum page margin | None | ~6.35 mm per side |
| Speed | Faster | Slower (browser launch) |
| Memory usage | Lower | Higher |
Install FrapPDFy on any Frappe bench in four steps.
Clone the repository into your bench using bench get-app.
$ bench get-app https://github.com/krunal1904/frappdfy.git
Replace your-site.local with your actual site name.
$ bench --site your-site.local install-app frappdfy
WeasyPrint is required. Playwright is optional — only needed if you want the Chromium engine.
# Required $ bench pip install weasyprint beautifulsoup4 PyPDF2 # Optional — Playwright / Chromium engine $ bench pip install playwright $ python -m playwright install chromium
Run migrations to create the new doctypes, then restart your bench.
$ bench --site your-site.local migrate $ bench restart
Useful when your production site can't run Playwright, or when you want to isolate PDF rendering capacity.
Comprehensive guides covering every feature of FrapPDFy.
Complete reference for building HTML templates — headers, footers, images, QR codes, page numbers, multi-copy labels, and more.
Open guide →Step-by-step setup for WeasyPrint, Playwright, and the FrapPDFy app on any Frappe bench.
View on GitHub →Configure cross-site PDF delegation with token authentication and automatic engine fallback.
Read docs →Found a bug or have a feature request? Open an issue on GitHub and we'll look into it.
Open issue →