Skip to content

PDF like on screen: settings that just work

If you want a PDF that looks as close as possible to what you see in the browser, this page gives you a ready-to-use request body that works in most cases. Copy it, replace the URL, add your API key, and adjust it only if needed.

A request body that covers the common cases

  • Loads the page fully: waits until the network is idle (networkidle0).
  • Waits for your content: uses optional waitForSelector support so SPAs and async content are ready.
  • Prints backgrounds: printBackground: true ensures CSS backgrounds and colors appear in the PDF.
  • Matches screen rendering: emulateMediaType: "screen" makes the PDF follow the on-screen layout instead of print CSS.

Use this with the PDF sync or PDF direct route.

json
{
  "page": {
    "goto": {
      "url": "https://your-page.com/your-document",
      "options": {
        "waitUntil": ["networkidle0"]
      }
    },
    "emulateMediaType": "screen",
    "waitForSelector": {
      "selector": "body",
      "options": { "timeout": 15000, "visible": true }
    },
    "pdf": {
      "printBackground": true,
      "format": "A4"
    }
  }
}
  • waitUntil: ["networkidle0"] — Doppio waits until there are no more than 0 network connections for 500ms. Your images, fonts and API calls have time to finish.
  • emulateMediaType: "screen" — The page is rendered with @media screen (and no @media print), so the PDF looks like the browser view.
  • waitForSelector — Waits for body to be visible (up to 15s). For SPAs or slow pages, replace "body" with a selector that appears when content is ready (e.g. "#app .loaded", ".report-ready").
  • printBackground: true — Backgrounds and box-shadows are included in the PDF.

When to tweak

SituationWhat to do
Content appears after JS (SPA, dashboard)Set waitForSelector.selector to an element that exists only when the main content is rendered (e.g. "#chart", "[data-ready]").
Page sets a “ready” flagUse waitForFunction instead of or after waitForSelector, e.g. "pageFunction": "() => window.__APP_READY__ === true".
You want print styles (margins, page breaks)Use "emulateMediaType": "print" so the browser uses @media print CSS.
Very long page / lazy-loaded sectionsKeep networkidle0; if some content only loads when in view, add a waitForSelector (or waitForFunction) that targets an element at the bottom or a “loading complete” indicator.

Minimal “no surprises” example

If you don’t need to wait for a specific selector, this is the smallest body that still loads the page fully and prints like the screen:

json
{
  "page": {
    "goto": {
      "url": "https://your-page.com/your-document",
      "options": { "waitUntil": ["networkidle0"] }
    },
    "emulateMediaType": "screen",
    "pdf": { "printBackground": true }
  }
}

For more options (margins, paper size, timeout, etc.) see Common params and PDF params.

Dark theme / background

Sites that use a class on html for dark mode (e.g. html.dark) or prefers-color-scheme often render in light mode in headless Chrome, because no theme is forced. So the PDF can have a white or light background even with printBackground: true. That’s the page’s behavior in that context, not an API bug. To get a dark PDF, the page would need to force dark mode (e.g. always add the class, or detect the render context).

All rights reserved