Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
There is no universal Chrome Headless PDF switch that fixes every rendering defect. The reliable approach is to reproduce the problem with the same Chrome/Puppeteer versions, HTML, CSS, fonts, operating system and PDF options used in production, then check settings in a fixed order: print media, page geometry, colors, content readiness, browser headers and runtime differences.
Start with a minimal, repeatable reproduction
Save the exact production HTML and assets, and record:
- Chrome or Chromium build number.
- Puppeteer version and Node.js version.
- Operating system or container image.
- Installed fonts and font files used by the page.
- Viewport, device scale factor and every
page.pdf()option. - The URL, cookies, authentication state and JavaScript data needed to render the page.
Compare the generated PDF with a screenshot of the same document in desktop Chrome using identical content. Change one variable at a time and keep the smallest reproducer; otherwise a CSS change can hide the real cause.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Baseline Puppeteer script
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({headless: true});
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900, deviceScaleFactor: 1 });
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
await page.pdf({
path: 'output.pdf',
format: 'A4',
printBackground: true,
displayHeaderFooter: false,
preferCSSPageSize: true,
waitForFonts: true
});
await browser.close();
})();
Replace the URL and options with your production values. Puppeteer’s page.pdf() generates a PDF with the print CSS media type by default, so a browser window that looks correct on screen is not necessarily the reference output.
#1 Best Overall
1. Check print media before changing layout
Inspect every @media print rule, inherited property and @page rule. Print styles often hide navigation, change colors, alter display modes or set different widths. A rule such as display:none or a print-only fixed width can explain an apparently missing or clipped element.
When the PDF should match the screen
Explicitly emulate screen media before calling page.pdf():
await page.emulateMediaType('screen');
await page.pdf({ path: 'screen-like.pdf', printBackground: true });
This does not make a PDF identical to a screenshot: pagination, paper dimensions and print-specific browser behavior still apply. If the document is intended for printing, keep the default print media and fix the print stylesheet instead.
Free tools Windows power users keep installed
One-click scans. No signup required.
2. Make page dimensions and scaling agree
Chrome can receive page geometry from CSS and from Puppeteer. Compare them rather than compensating with arbitrary widths or transforms.
Rank #2
- HTML CSS Design and Build Web Sites
- Comes with secure packaging
- It can be a gift option
| Setting | What it controls | Important behavior |
|---|---|---|
@page { size: ... } |
CSS page size and orientation | Used when CSS page size is given priority. |
format |
Named paper size such as A4 or Letter | Provides Puppeteer’s paper size when width/height are not supplied. |
width, height |
Explicit paper dimensions | Use consistent units and check orientation. |
preferCSSPageSize |
Precedence between CSS and Puppeteer dimensions | Defaults to false; set true when CSS @page must win. |
margin |
Printable inset | Large margins reduce the content box and can trigger unexpected wrapping. |
scale |
Overall PDF scaling | Review it together with dimensions and margins. |
For a CSS-controlled document:
@page {
size: A4 portrait;
margin: 14mm;
}
html, body {
margin: 0;
}
@media print {
.screen-only { display: none !important; }
}
await page.pdf({
path: 'report.pdf',
preferCSSPageSize: true,
printBackground: true,
margin: { top: '0', right: '0', bottom: '0', left: '0' }
});
Do not define a conflicting format while diagnosing a CSS-size problem. Conversely, if your service contract is “always Letter,” set that format explicitly and design the CSS for its resulting content width.
3. Restore backgrounds and intended colors
Puppeteer’s printBackground option defaults to false. Enable it when panels, gradients, images or colored table cells are part of the design.
await page.pdf({
path: 'colored.pdf',
printBackground: true
});
Chrome also modifies colors for printing by default. Request exact CSS colors where appropriate:
@media print {
* {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}
Exact color adjustment can increase ink or produce a less printer-friendly document, so apply it deliberately rather than globally when accessibility or paper economy matters.
Rank #3
4. Wait for fonts and application content
Puppeteer’s waitForFonts option defaults to true and waits for document.fonts.ready. That only confirms the browser’s font-loading promise; it does not prove that your application has fetched data, finished hydration or rendered charts.
Verify fonts explicitly
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.evaluate(() => document.fonts.ready);
await page.waitForSelector('[data-pdf-ready]', { visible: true });
await page.pdf({ path: 'report.pdf', waitForFonts: true, printBackground: true });
Make data-pdf-ready appear only after the page has its final data and layout. Also check the browser logs and network responses for blocked font files, incorrect MIME types, CORS failures and authentication-dependent URLs. A missing font changes glyph widths and can cascade into different line breaks and page counts.
Control time-dependent pages
Animations, delayed API calls and clocks can produce different output on every run. Disable animations in a print stylesheet or inject a deterministic class, then wait for a selector or application-specific state. When using the Chrome command line, --timeout bounds capture timing and --virtual-time-budget gives time-dependent code a controlled virtual interval; neither value guarantees that a particular application is ready.
5. Remove unexpected Chrome headers and footers
Headers containing the date and time, and footers containing the URL or page number, are browser print furniture—not page content. In Puppeteer, use displayHeaderFooter: false to suppress them, or set it to true only when supplying intentional templates.
Rank #4
- Brand: Wiley
- Set of 2 Volumes
- A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
await page.pdf({
path: 'clean.pdf',
displayHeaderFooter: false
});
For the Chrome CLI, the current flag is --no-pdf-header-footer. Older Chrome versions used --print-to-pdf-no-header; if the current spelling is rejected, check the installed build’s CLI documentation rather than assuming the PDF engine is broken.
6. Compare the actual runtime
Reproduce with the same Chrome build, Puppeteer release, OS or container, font packages and launch flags. Desktop Chrome and a Linux container can differ in font fallback, sandboxing, GPU availability and default resources even when the HTML is identical.
A historical Puppeteer issue (#2278, opened March 28, 2018) described a page-size discrepancy involving Puppeteer 1.2.0, macOS 10.13.3 and desktop Chrome 65. It is evidence that environment comparisons matter, not proof of a current universal defect. Do not “fix” a present release solely by copying a workaround for that old report.
Symptom-to-fix troubleshooting
| Symptom | Likely cause | First corrective action |
|---|---|---|
| Screen layout differs from PDF | Print media rules are active | Inspect @media print; use emulateMediaType('screen') only if screen styling is the requirement. |
| Wrong paper size or unexpected whitespace | Conflicting CSS and Puppeteer dimensions, margins or scale | Choose one authority; set preferCSSPageSize deliberately and verify orientation. |
| Colored sections are white | printBackground is false |
Set it to true and review print color adjustment. |
| Text wraps differently or uses a fallback font | Font failed to load or readiness was too early | Inspect requests, await document.fonts.ready and verify installed fonts. |
| Charts or data are missing | JavaScript had not reached its final state | Wait for an application readiness selector/state, not only networkidle0. |
| Date, URL or page number appears | Print header/footer enabled | Disable displayHeaderFooter or use the version-appropriate CLI flag. |
| Runs differ between machines | Chrome, fonts, OS or container mismatch | Pin and record the complete runtime; compare generated PDFs from the same image. |
| Capture times out | Slow assets, blocked requests or an unbounded readiness condition | Inspect failed requests, set an explicit timeout policy and ensure the ready selector can occur. |
Performance, reliability and cost considerations
- Reuse a browser process when safe, but create an isolated page and context per job so cookies and styles do not leak.
- Wait for the smallest reliable readiness condition; waiting indefinitely for global network idle can stall pages with analytics or long polling.
- Block nonessential ads and trackers only when doing so cannot change the document’s layout or required data.
- Store the Chrome build and PDF options alongside the artifact so a later visual difference is diagnosable.
- Use deterministic fonts, locale, timezone and data fixtures for regression tests. Compare page count, dimensions and rasterized pages, not only file size.
- Set job timeouts and clean up pages and browsers in failure paths. A timeout should produce a useful error and leave no orphaned Chrome processes.
Or skip the browser setup
If you need a hosted capture path instead of operating Chrome yourself, ScreenshotNeo provides a website screenshot API and MCP server, and its PDF endpoint can capture a URL in one request. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP tools—take_screenshot, get_page_info and capture_pdf—work with Claude, Cursor and other MCP clients.
One-call examples
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
See the complete option names and PDF controls in the ScreenshotNeo documentation. Every feature is on every plan: 1,000 shots per month are free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Best Value
Frequently Asked Questions
Should I use networkidle0 for every PDF job?
No. Pages with analytics, polling or streaming connections may never become idle. A page-specific readiness selector or application state is usually more reliable.
Why does changing the viewport not fix the PDF width?
Viewport size affects layout before printing, while paper dimensions, margins and scaling determine the PDF page. Check those settings separately.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsCan a PDF be pixel-identical to desktop Chrome?
Only when the browser build, fonts, OS, input and print settings match closely; PDF pagination and print media still make screen pixels an imperfect target.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

