webcapture Get a free key

HTML to PDF without losing formatting

Formatting breaks because the converter is not the browser that displayed the page. The fix is to render with the same engine class your users see: a real browser engine executes the JavaScript, loads the web fonts, and lays out flexbox and grid, then prints. That is what "rendered by a real browser engine" means, and it is the only class of converter that reproduces a page you can already see.

The three ways formatting gets lost

Every "my PDF looks wrong" report falls into one of three buckets. First, the engine cannot parse the layout: WebKit-era converters like wkhtmltopdf predate flexbox and grid, so modern sheets silently fall back. Second, the page was not finished: JavaScript-rendered content and web fonts get captured before they exist, which produces blank sections and fallback serif text. Third, print assumptions differ: margins, page size, and background colors are print settings, and converters that guess them differently shrink, clip, or drop backgrounds. Each bucket has a different fix, and only the first one requires changing tools.

Fix 1: finish the page before printing

Wait for the network to settle and for the content to exist before calling print. In Playwright, print after waitUntil: "networkidle" plus an explicit page.waitForFunction() on something your page renders client-side, and pass printBackground: true or backgrounds vanish. Set margins and format explicitly instead of inheriting printer defaults. On a hosted renderer these are engine defaults: backgrounds print by default, and what you tune per request is the format, scale, page ranges, the color scheme the page sees, and header or footer templates the API reference lists. Playwright callers who ran page.emulateMedia({ colorScheme: "dark" }) before printing should pass "colorScheme": "dark" instead; it is the same emulation at the same layer.

Fix 2: stop fighting smart shrinking

wkhtmltopdf shrank content to fit unless you passed --disable-smart-shrinking; tuned templates are full of workarounds for it. Chromium's print pipeline does not smart-shrink, so migrating templates usually means deleting those workarounds, not rewriting them.

On a hosted renderer the whole checklist is one call; webcapture prints backgrounds by default, and waitForNetwork opts the render into waiting for the network to go quiet before the print:

Hosted renderone call
curl -X POST https://webcapture.io/v1/convert \
  -H "Authorization: Bearer wc_your_key" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/report",
       "scale": 1, "pageRanges": "1-3"}'

Fix 3: check the engine before the CSS

If your page uses flexbox, grid, custom web fonts, or client-side rendering, only a browser-engine converter can reproduce it correctly. Print-CSS engines (WeasyPrint, Prince) are excellent for documents authored for print, and the wrong tool for reproducing a web app screen. The decision table in our wkhtmltopdf alternatives guide maps engines to page types.

A worked breakage: page break splits text

The autocomplete-phrased version of this problem is "convert html to pdf page break splits text". In browser rendering, two CSS properties control pagination directly: break-inside: avoid keeps cards and table rows whole, and break-before: page starts a heading on a fresh sheet; the legacy page-break-* aliases still work.

/* keep cards and rows whole across page breaks */
.card, tr { break-inside: avoid; }
h2 { break-before: page; }   /* legacy page-break-before: page also works */

If lines split mid-glyph in your current output, that is the old engine drawing text in slices; a browser engine draws whole lines.

Method and sources

Checked 2026-09-20 against the Chromium print pipeline documentation. This guide is maintained by webcapture, a hosted renderer that runs a real Chromium for every job; the API reference lists what you can tune per request (format, scale, page ranges, header and footer templates), and backgrounds with A4 rendering are engine defaults. The guides index lists every comparison and migration path on the site. The recipes hub turns the hosted call into runnable programs in curl, Python, Node, and TypeScript.

Render your first page in seconds

Mint a key, POST a URL, and the finished document comes back in the same response; pass ?wait=false for a job ticket with poll and download URLs. The first 50 renders a month are free, and there is no credit card. Not ready for a key? The free URL to PDF tool renders public pages without one.