PDF Options & Templating
Page setup
Section titled “Page setup”{ "html": "<h1>Invoice</h1>", "format": "A4", "landscape": false, "print_background": true, "margins": { "top": 0.4, "right": 0.4, "bottom": 0.4, "left": 0.4 }}margins are in inches. print_background: true (the default) renders CSS backgrounds and colors — turn it off for a print-style black-and-white document.
Using variables
Section titled “Using variables”{ "html": "<h1>{{ title }}</h1><p>Total: {{ total }}</p>", "variables": { "title": "Invoice #142", "total": "€1,200.00" }}<table> {% for item in items %} <tr><td>{{ item.description }}</td><td>{{ item.amount }}</td></tr> {% endfor %}</table>{ "items": [{ "description": "Design work", "amount": "€500.00" }] }Filters
Section titled “Filters”Any Jinja2 built-in filter works, e.g. {{ qr_data | urlencode }} for safely embedding a variable inside a URL (handy alongside a QR-code image service in an <img src>).
Fonts and images
Section titled “Fonts and images”The renderer is a real, internet-connected headless browser — <link>-based Google Fonts and <img> tags pointing at public URLs work exactly as they would in any browser.
Waiting for content
Section titled “Waiting for content”By default the renderer prints once the page fires load. That’s too early for a page whose real content arrives afterwards — a chart drawn by JavaScript, a table fetched on mount, a slow webfont. Use page_load to say what “ready” means:
{ "html": "<div id=\"report\"></div><script>/* fills #report */</script>", "page_load": { "wait_until": "networkidle0", "timeout_ms": 15000, "wait_for_selector": "#report" }}All three fields are optional:
wait_until—load(default),domcontentloaded,networkidle0(no network connections for 500ms) ornetworkidle2(at most 2).networkidle0is the usual choice for a page that fetches its own data.wait_for_selector— a CSS selector that must appear before printing, for content that shows up afterwait_untilhas already fired. This is the most reliable signal when you control the markup: render a known element last, and wait for it.timeout_ms— how long to wait, 1000–120000, default 30000. It’s also clamped to the service’s own render budget, so asking for more than the server allows quietly gets the server’s limit instead of failing.
If the wait runs out — a selector that never appears, a page that never goes idle — the request fails with 504 PDF_RENDERING_TIMEOUT. A selector typo looks exactly like a slow page, so check it first.
Waiting longer than you need costs you latency on every render: prefer a precise wait_for_selector over a large timeout_ms.
Limits
Section titled “Limits”- HTML input and the rendered PDF both have size ceilings, and there’s a page-count ceiling — a document that’s too big or has too many pages fails clearly (
422/413) rather than hanging. - Rendering has a timeout; a page that never finishes loading fails as
504 PDF_RENDERING_TIMEOUTinstead of hanging the request. - Only HTML+CSS is accepted as input — there’s no “render this URL” endpoint (a deliberate scope limit, not a missing feature).