Free tools Windows power users keep installed
One-click scans. No signup required.
Use Puppeteer’s page.pdf() method after loading or building your document. Choose paper dimensions, margins, print CSS, backgrounds, headers and footers, then save the returned PDF bytes or write them directly to a file. The complete workflow below handles multi-page layouts, custom page sizes, dynamic content, fonts, page ranges and common failures.
What Puppeteer uses to create a PDF
Puppeteer renders the current page through Chromium’s print pipeline. Page.pdf() returns a Promise<Uint8Array>; supplying path writes the result to disk. The official guide’s basic flow navigates with waitUntil: 'networkidle2', calls page.pdf(), and closes the browser, but that network event is an example rather than a guarantee that every application has finished rendering.
By default, PDF rendering uses print CSS media. Consequently, a page can look different from its screen view. Call page.emulateMediaType('screen') when screen styles are required, or create a dedicated @media print stylesheet for a document designed for paper. See the Puppeteer PDF generation guide and the Page.pdf() API reference.
Complete multi-page example
Install Puppeteer in a Node.js project, then create a script such as generate-pdf.mjs. This example loads a URL, waits for the page’s own content, applies print settings, and produces an A4 PDF.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitches#1 Best Overall
npm install puppeteer
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await page.pdf({
path: 'output.pdf',
format: 'A4',
printBackground: true,
preferCSSPageSize: true,
margin: {
top: '18mm',
right: '16mm',
bottom: '18mm',
left: '16mm'
}
});
} finally {
await browser.close();
}
This is a documented API pattern; adapt the wait condition and page preparation to the site you are rendering. format selects a standard paper size. If you specify format, it takes precedence over width and height. With preferCSSPageSize: true, CSS @page dimensions take priority over those JavaScript options. The API defaults to no margins and printBackground: false, so set both deliberately when the document needs them. Details are in the PDFOptions reference.
Prepare content before calling page.pdf()
Navigate and wait for application rendering
page.goto() resolves according to the selected lifecycle event, not according to your application’s data model. Single-page applications may still be fetching data, images or charts after navigation. Wait for a selector that proves the report is ready, use a known delay only when necessary, or wait for an application-defined promise.
await page.goto('https://example.com/report', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('#report-ready');
For pages you generate yourself, page.setContent(html, { waitUntil: 'load' }) is often simpler. You can also call page.evaluate() to insert data or trigger rendering before creating the PDF.
Fonts and images
Puppeteer’s PDF method waits for fonts by default; PDFOptions.waitForFonts defaults to true. It still helps to make font loading explicit when a layout is sensitive to font metrics:
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →await page.evaluate(() => document.fonts.ready);
await page.waitForSelector('img.report-chart');
Use absolute, reachable asset URLs or embed assets as data URLs. If an image is lazy-loaded, scroll it into view or wait until its complete property is true before printing.
Control page size, orientation and margins
Standard paper
Use format: 'A4', 'Letter' or another supported standard. Add landscape: true for a horizontal report. Do not combine a format with custom width and height expecting the custom values to win.
Rank #2
Custom CSS page sizes
Put document dimensions and margins in your stylesheet when the layout owns those decisions:
@page {
size: A4 portrait;
margin: 18mm 16mm;
}
@media print {
.screen-only { display: none !important; }
.avoid-break { break-inside: avoid; }
h1, h2 { break-after: avoid; }
}
Then pass preferCSSPageSize: true. CSS page-break rules influence pagination, but no single rule works for every table, chart and nested flex layout. Inspect the generated PDF and adjust the print stylesheet rather than relying on screen layout alone.
Print colors, backgrounds and headers
Background graphics and exact colors
Set printBackground: true to include background fills and images. Print rendering can adjust colors; the Puppeteer API notes that CSS -webkit-print-color-adjust can request exact color treatment:
@media print {
* { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}
Page headers and footers
Enable displayHeaderFooter and provide HTML templates. Puppeteer substitutes classes such as date, title, url, pageNumber and totalPages.
await page.pdf({
path: 'report.pdf',
format: 'A4',
displayHeaderFooter: true,
headerTemplate: '<div style="font-size:8px;width:100%;text-align:center;">Quarterly report</div>',
footerTemplate: '<div style="font-size:8px;width:100%;text-align:center;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>',
margin: { top: '24mm', bottom: '20mm', left: '16mm', right: '16mm' }
});
Header and footer templates have their own constrained layout. Reserve enough top and bottom margin or the content can overlap them.
Save all pages or a selected range
Without path, use the returned bytes in an HTTP response, object store or database:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Rank #3
const pdfBytes = await page.pdf({ format: 'A4' });
// Example: return Buffer.from(pdfBytes) from your web handler
To export only selected pages, use pageRanges, for example '1-5, 8, 11-13'. Page numbering starts at one. Confirm the resulting page count when content is dynamic; a range that exceeds the document’s length may fail or produce an unexpected result.
Generate a PDF from HTML instead of a URL
This pattern is useful for invoices, reports and emails assembled by your server:
import puppeteer from 'puppeteer';
const html = `<!doctype html>
<html><head>
<style>
@page { size: A4; margin: 15mm; }
body { font-family: Arial, sans-serif; }
table { width: 100%; border-collapse: collapse; }
td, th { border: 1px solid #ccc; padding: 6px; }
</style>
</head><body>
<h1>Invoice</h1>
<p>Generated at ${new Date().toISOString()}</p>
</body></html>`;
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.setContent(html, { waitUntil: 'load' });
await page.pdf({
path: 'invoice.pdf',
printBackground: true,
preferCSSPageSize: true
});
} finally {
await browser.close();
}
Escape or sanitize any untrusted values inserted into HTML. A PDF job that accepts arbitrary markup can otherwise become an injection or data-access risk.
Options that matter in production
printBackground: include CSS backgrounds and graphics; default is false.preferCSSPageSize: let@pagedimensions override JavaScript paper settings; default is false.margin: set explicit top, right, bottom and left values; the default is no margin.displayHeaderFooter,headerTemplate,footerTemplate: add repeated page furniture.landscape: rotate standard paper for wide tables.pageRanges: export a subset such as1-3, 7.waitForFonts: retain the default true when font metrics affect wrapping.path: write directly to a file; omit it to receive PDF bytes.
Troubleshooting common failures
The PDF is blank or missing content
The capture probably ran before the application rendered. Replace a generic network wait with waitForSelector, an application-ready flag or an explicit data-loading wait. Verify that the target route works in the same Chromium environment and that authentication cookies are present.
Styles or colors differ from the browser
Print media is the default. Add print rules, call page.emulateMediaType('screen') when screen CSS is intended, and enable printBackground. For brand colors, use -webkit-print-color-adjust: exact and check the output.
Content is clipped or unexpectedly scaled
Check CSS @page, margins and the interaction between format, width, height and preferCSSPageSize. Wide tables often need landscape orientation or responsive print rules. Avoid fixed-height containers that hide overflow.
Rank #4
Fonts wrap differently or fallback fonts appear
Wait for document.fonts.ready, keep waitForFonts enabled, and ensure the browser can reach the font files. Cross-origin restrictions, blocked requests and incorrect MIME types can all cause fallback fonts.
Headers overlap the body
Increase the corresponding top or bottom margin. Header and footer templates do not automatically create usable space for the main document.
Recommended Free Tools
Navigation never finishes
networkidle2 can remain unsettled on pages with analytics, WebSockets or long polling. Use domcontentloaded followed by a selector or application-specific readiness check, and block or mock nonessential requests when appropriate.
The process is slow or runs out of memory
Reuse a browser process for batches, close each page in a finally block, avoid unnecessarily huge viewport dimensions, and limit concurrent jobs. Large images and very long pages consume substantial memory; resize assets and split exceptionally large reports when the document design permits.
Version and browser compatibility
The Puppeteer documentation search identifies version 25.12.0 and pairs it with Chrome for Testing 154.0.8037.57 and Firefox 156.0.1. These values are version-specific and can change; check the supported browsers page and your installed package before pinning a deployment. Puppeteer switched to Chrome for Testing beginning with v20.0.0.
Or skip the browser setup
If you need an HTTP screenshot or PDF service rather than maintaining Chromium workers, ScreenshotNeo accepts one GET request for a URL and can return a PDF. Its cleanup steps accept cookie and consent banners and remove more than 60 known consent platforms, newsletter popups and chat widgets before capture; each step can be disabled. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing result.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Use the API documentation at https://screenshotneo.com/docs/ for authentication and options. A minimal call is:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.pdf
ScreenshotNeo also provides an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account to get started.
Frequently Asked Questions
Can Puppeteer create a PDF without visiting a URL?
Yes. Call page.setContent() with your HTML, wait for required assets, and then call page.pdf().
Does page.pdf() include backgrounds automatically?
No. Set printBackground: true; its default is false.
How can I use CSS-defined paper dimensions?
Declare an @page rule and pass preferCSSPageSize: true.
Can I return the PDF from an API endpoint?
Yes. Omit path, receive the returned Uint8Array, and send it with a PDF content type.
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.

