Render raw HTML or a live URL into a print-ready PDF with real Chromium.
html_to_pdf
renderbrowser
Boots a headless browser: ~2–6s and roughly 0.1 browser-minute of the daily free 10.
Renders with the same Chromium that ships in Cloudflare's Browser Rendering, so your CSS —
including @page, web fonts, flexbox and grid — behaves exactly as it does in a desktop browser's print preview.
Pass either html (a full document or a fragment) or url. When you pass html, add a <base href>
tag if you reference relative assets. The page is rendered with print media emulation and backgrounds enabled,
which is what most people want and what headless Chrome does not do out of the box.
Chromium's default is "pour the document into fixed-size boxes and cut wherever the box ends". That is the wrong
answer for both documents people actually convert, so layout changes the paginator:
| Layout | Use it for | What it does |
|---|---|---|
report |
long-form reports, whitepapers, invoices | Never strands a heading at the foot of a page, never slices a table, figure or code block, repeats <thead> across a long table, and honours orphans/widows. Set sectionBreak to also start each section on a fresh sheet. |
slides |
decks — reveal.js, Slidev, Marp, impress.js, remark, or your own .slide markup |
Finds the slide elements, forces the hidden ones visible, and pins one slide to exactly one page at the deck's own aspect ratio. No slide ever spans a page boundary and there is no trailing blank sheet. |
continuous |
screen reading, transcripts, dashboards | One single page as tall as the content. No page breaks exist at all. |
flow |
documents with their own tuned print stylesheet | Chromium's untouched behaviour. |
auto (default) |
anything | Detects a deck; falls back to report. |
For a reveal.js deck served over HTTP the tool reloads it with reveal's own ?print-pdf mode, which knows about
vertical stacks and fragments — better than anything an external stylesheet could do.
The response metadata reports what happened: layout, pages, and for decks slides, slideSelector and the
page geometry, so you can check the slide count came out right.
sectionBreak: "h1" (or h2) so each section starts on a fresh sheet.class="avoid-break"; class="page-break" forces a break before an element.slideSelector with the CSS selector for a single slide, and check the returned slides count.slideSize explicitly.printBackground is already on — check for @media print { … display:none } in the page's own CSS.displayHeaderFooter: true and use <span class="pageNumber"></span> / <span class="totalPages"></span>. (Not applicable to slides or continuous.)| Parameter | Type | Default | Description |
|---|---|---|---|
| html | string | — | HTML source to render. Takes precedence over url. |
| url | string | — | Page to render. Ignored when html is supplied. |
| layout | `auto` | `report` | `slides` | `continuous` | `flow` | "auto" |
How the document is paginated. report protects headings, tables and figures from being split. slides maps one slide element to exactly one PDF page. continuous emits a single tall page with no breaks at all. flow is Chromium's untouched behaviour, for documents that ship their own print stylesheet. auto detects a slide deck and otherwise uses report. |
| sectionBreak | `none` | `h1` | `h2` | `h3` | `section` | "none" |
Start each section on a fresh page. report layout only. The first section never gets a break, so you never get a blank opening page. |
| slideSize | `auto` | `16:9` | `16:10` | `4:3` | `a4-landscape` | "auto" |
Page geometry for slides layout. auto measures the deck's own slide box. |
| slideSelector | string | — | CSS selector matching one slide. Leave empty to auto-detect reveal.js, Slidev, Marp, impress.js, remark and the common .slide conventions. |
| format | `A4` | `A3` | `A5` | `Letter` | `Legal` | `Tabloid` | "A4" |
Paper size. |
| landscape | boolean | false |
Landscape orientation. |
| printBackground | boolean | true |
Render CSS backgrounds and images. Off by default in Chromium; on by default here. |
| scale | number | 1 |
Render scale, 0.1–2. |
| margin | string | "16mm" |
CSS length applied to all four margins, or four space-separated lengths (top right bottom left). |
| pageRanges | string | — | Pages to keep, e.g. 1-3,8. Empty means all pages. |
| displayHeaderFooter | boolean | false |
Show the header/footer templates. |
| headerTemplate | string | — | HTML for the running header. Supports Chromium's .title, .date, .pageNumber, .totalPages classes. |
| footerTemplate | string | — | HTML for the running footer. |
| filename | string | "document.pdf" |
Download filename. |
| emulateMedia | `print` | `screen` | "print" |
CSS media type to emulate. |
| waitUntil | `load` | `domcontentloaded` | `networkidle0` | `networkidle2` | "networkidle2" |
When to consider navigation finished. |
| waitForSelector | string | — | Block until this CSS selector appears. Useful for lazily hydrated SPAs. |
| timeoutMs | integer | 20000 |
Hard timeout for the page load, in milliseconds. |
The PDF bytes. Send `Accept: application/json` (or `?output=json`) to get `{mime, filename, bytes, base64|url, layout, pages, slides, …}` instead.