📋 Table of Contents
Why HTML to PDF?
Historically, generating PDFs required learning specialized libraries like libpdf,
ReportLab, or PDFKit. These tools typically have their own drawing APIs, meaning
you have to "draw" text at specific X,Y coordinates.
This is tedious and brittle. If you want to change a font size, you might have to recalculate the position of everything below it.
The modern approach is different: Use HTML and CSS to design your document. You already know these tools. Then, use a browser engine to "print" that HTML to a PDF file.
Print Stylesheets (CSS)
Before you generate a PDF, you need to make sure your HTML looks good on paper. This is where
@media print comes in.
@media print {
/* Hide navigation and buttons */
nav, footer, .btn {
display: none !important;
}
/* Ensure text is black for saving ink */
body {
color: #000;
background: #fff;
}
/* Improve link readability */
a {
text-decoration: none;
}
}
Using Puppeteer (Node.js)
Puppeteer is the gold standard for HTML-to-PDF conversion in the Node.js ecosystem. It uses headless Chrome to render the page.
import puppeteer from 'puppeteer';
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
// Load your HTML content or URL
await page.setContent(`<h1>Invoice #101</h1><p>Top-notch service</p>`);
// Generate PDF
await page.pdf({
path: 'invoice.pdf',
format: 'A4',
printBackground: true,
margin: {
top: '20px',
bottom: '20px'
}
});
await browser.close();
})();
Using Python (WeasyPrint vs. Playwright)
In Python, you have two main options:
1. WeasyPrint: A dedicated visual rendering engine for HTML/CSS to PDF. It doesn't use a browser. It's lightweight but doesn't support JavaScript or modern CSS features (like Grid or Flexbox perfectly).
2. Playwright (Python): Uses a real browser engine (Chromium/WebKit). It supports everything Chrome supports.
from playwright.sync_api import sync_playwright
def run():
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto('https://example.com/report')
page.pdf(path="report.pdf", format="Letter")
browser.close()
if __name__ == "__main__":
run()
The API Approach (SnapAPI)
Managing headless browsers in production is painful. They consume huge amounts of RAM, can crash unexpectedly, and require constant updates.
Using a managed API simplifies this to a single HTTP request.
# POST request to SnapAPI
curl -X POST "https://snapapi.alterra-solutions.com/v1/pdf" \
-H "Content-Type: application/json" \
-d '{
"html": "<h1>Certificate of Completion</h1>",
"api_key": "YOUR_KEY",
"format": "A4",
"print_background": true
}' -o certificate.pdf
Pro Tips for Page Breaks
One of the hardest parts of PDF generation is handling page breaks efficiently. You don't want an image or a table row to be cut in half.
Use modern CSS break properties:
/* Force a break before this element */
.section-start {
break-before: page;
}
/* Prevent an element from breaking inside */
.card, tr {
break-inside: avoid;
}
Conclusion
Stop generating PDFs pixel-by-pixel. Embrace the power of the web platform. Design with HTML/CSS, test in your browser, and render with Puppeteer or an API like SnapAPI for reliable results.
Generate PDFs Effortlessly
SnapAPI supports high-fidelity PDF generation from HTML or URLs.
Start Generating PDFs →