Use Puppeteer’s page.pdf(), not the browser’s native print dialog, when you need an unattended PDF file. Navigate to the page, wait until it is ready, then call await page.pdf({ path: 'output.pdf' }). Puppeteer renders with print CSS by default, waits for fonts by default, and writes the resulting PDF to the path you provide.
window.print() is a different workflow: the HTML Standard defines it as prompting a user to print. Puppeteer’s documented PDF API creates the file directly; the official material does not provide a supported recipe for clicking Save in a native print-preview window.
Generate a PDF directly with Puppeteer
Install Puppeteer in a Node.js project, then run this complete example:
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' });
} finally {
await browser.close();
}
The path value is the output filename. Relative paths are resolved from the process’s current working directory. After the script finishes, output.pdf is on disk and the browser is closed even if navigation or PDF generation throws an error.
#1 Best Overall
- BEST FOR SMALL BUSINESSES – Engineered for extraordinary productivity, the Brother DCP-L2640DW Monochrome (Black & White) 3-in-1 combines laser printer, scanner, copier in one compact footprint and delivers high-quality black & white prints
- FAST PRINTER WITH EFFICIENT SCANNING – Produces documents quickly with print speeds up to 36 ppm(2) and scan speeds up to 23.6/7.9 ipm(3) (black/color). A 50-page auto document feeder(4) allows for convenient, time saving multi-page scanning and copying
- FLEXIBLE CONNECTION OPTIONS – Easily navigate the changing demands of your business with secure multi-device connectivity via built-in dual-band wireless (2.4GHz / 5GHz) and Ethernet. Or connect locally to a single computer via USB interface
- BROTHER MOBILE CONNECT APP – Print, scan, and manage your wireless printer anytime, from almost anywhere from your mobile device. Order Brother Genuine Supplies, track toner usage, and complete more work on-the-go(5)
- CHOOSE BROTHER GENUINE TONER – When it’s time to replace your toner, be sure to choose Brother Genuine TN830 or TN830XL replacement toner. And with Refresh EZ Print Subscription Service, you’ll never worry about running out of toner again and you’ll enjoy savings of up to 50%(6) on Brother Genuine Toner. Get started with Refresh today with a Free Trial(1)
Why this is not the print dialog
A visible print dialog is designed for a person to choose a printer or destination. It can vary by operating system, browser channel and desktop session, making it unsuitable for a headless job. page.pdf() uses Chromium’s PDF renderer without opening that UI. If your requirement is a human choosing “Save to PDF,” use window.print() in a headed browser; if the requirement is reliable, unattended storage, use page.pdf().
Control where and how the PDF is saved
Return bytes instead of writing a file
Omit path when your application should upload or process the document itself. The API returns the PDF as a Uint8Array:
const pdfBytes = await page.pdf();
await storageClient.put('reports/example.pdf', pdfBytes);
Use a filesystem path when you want Puppeteer to write the file directly; use the returned bytes for object storage, an HTTP response or post-processing.
Paper, orientation and dimensions
format selects a standard paper size (Letter is the default). You can instead set width and height, and set landscape: true for a horizontal page. When both are supplied, format takes precedence over explicit dimensions.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallRank #2
- BEST FOR HOMES & HOME OFFICES – Engineered for consistent, premium print quality, the Brother HL-L2405W Monochrome (Black & White) Laser Printer delivers sharp, crisp prints at an affordable price. Prints one-sided documents at speeds up to 30ppm(2)
- COMPACT, CONNECTED PRINTER – Flexible connection options make this an ideal printer for home use and at-home offices. Securely connect to multiple devices with built-in dual-band wireless (2.4GHz/5GHz) or locally to a single computer via USB interface
- BROTHER MOBILE CONNECT APP – Manage your printer remotely and print from your mobile device anytime, from almost anywhere. Order Brother Genuine Supplies, track toner usage, and complete more work on-the-go(3)
- VERSATILE PAPER HANDLING – Enjoy seamless, reliable everyday printing with the 250-sheet paper tray(4) and a manual feed slot that enables printing on envelopes and specialty pape
- BROTHER IS AT YOUR SIDE – Backed by Brother with a 1-year limited warranty and free online, call, or live chat support for the life of your printer
Margins, scale and CSS page size
Margins accept CSS length strings. scale changes the rendered size when content is clipped or too small. Set preferCSSPageSize: true when your document’s @page rule should determine the paper dimensions; otherwise Puppeteer fits content to the selected paper.
await page.pdf({
path: 'report.pdf',
format: 'A4',
landscape: false,
margin: { top: '12mm', right: '10mm', bottom: '12mm', left: '10mm' },
preferCSSPageSize: true,
scale: 1
});
Backgrounds and color
Background graphics are excluded by default. Set printBackground: true to include them. Print rendering can alter colors; CSS -webkit-print-color-adjust: exact can request exact colors where Chromium supports it.
await page.addStyleTag({
content: '@media print { * { -webkit-print-color-adjust: exact; print-color-adjust: exact; } }'
});
await page.pdf({ path: 'branded.pdf', printBackground: true });
Headers, footers and page ranges
Set displayHeaderFooter: true and provide header or footer templates when you need repeating print elements. Use pageRanges for selected pages, such as '1-3,5'. Templates are HTML strings and support Puppeteer’s documented page-number placeholders.
Make dynamic pages ready before capture
waitUntil: 'networkidle2' waits for navigation to settle, and page.waitForNetworkIdle() can be used later in a workflow. Neither proves that every client-side component has finished rendering: an application may fetch data after the network becomes quiet.
Rank #3
- FAST PRINT SPEEDS: Print up to 19 pages per minute.
- COMPACT DESIGN: Space-saving, compact design fits anywhere in your home, school or small office.
- WIRELESS CONNECTIVITY: Print from almost anywhere in your workspace using your compatible mobile device.
- PAPER CAPACITY: Up to 150 sheets.
- SUSTAINABILITY: Uses less than 2 watts in Energy Saver mode.
Wait for an application-specific signal
await page.goto('https://example.com/report', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('[data-report-ready]', { visible: true });
await page.pdf({ path: 'report.pdf', printBackground: true });
Have the page add a marker such as data-report-ready only after charts, images and API data are ready. A bounded timeout is safer than waiting forever:
await page.waitForSelector('[data-report-ready]', {
visible: true,
timeout: 30000
});
Fonts and page focus
Puppeteer waits for fonts by default during PDF generation. If a background page prevents fonts from settling, bring it to the front before calling page.pdf(). You can also make font loading explicit in page code when your application has a known readiness promise.
Choose print CSS or screen CSS deliberately
PDF output uses print media by default, so rules inside @media print apply and screen-only elements may disappear. If the PDF should match the screen design, emulate screen media first:
await page.emulateMediaType('screen');
await page.pdf({ path: 'screen-style.pdf', printBackground: true });
When output is unexpectedly different, inspect @media print, @page, margins, paper format, scale and background settings in that order. Keep print-specific navigation, cookie notices and interactive controls hidden when they do not belong in the document.
Rank #4
- BEST FOR HOME OFFICES & SMALL TEAMS – Engineered for consistent, premium print quality, the Brother HL-L2460DW Monochrome (Black & White) Laser Printer produces documents that are clear, crisp, and easy to review and share, all at an affordable price
- COMPACT, CONNECTED, EXCEPTIONALLY EFFICIENT– Connect with built-in dual-band wireless (2.4GHz/5GHz), Ethernet, or to a single computer via USB interface. Prints at speeds up to 36ppm(2), plus automatic duplex printing saves time and reduces paper waste
- BROTHER MOBILE CONNECT APP – Manage your wireless printer remotely and print from your mobile device anytime, from almost anywhere. Order Brother Genuine Supplies, track toner usage, and complete more work on-the-go(3)
- VERSATILE PAPER HANDLING – Tackle high-volume black & white printing with the 250-sheet capacity paper tray.(4) The manual feed slot enables printing on envelopes and specialty paper
- BROTHER IS AT YOUR SIDE – Backed by Brother with a 1-year limited warranty and free online, call, or live chat support for the life of your printer
A production-ready example
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
await page.goto('https://example.com/invoice/123', {
waitUntil: 'domcontentloaded',
timeout: 60000
});
await page.waitForSelector('[data-invoice-ready]', {
visible: true,
timeout: 30000
});
await page.emulateMediaType('print');
await page.pdf({
path: 'invoice-123.pdf',
format: 'A4',
printBackground: true,
preferCSSPageSize: true,
displayHeaderFooter: true,
headerTemplate: '',
footerTemplate: 'Page of ',
margin: { top: '14mm', right: '12mm', bottom: '16mm', left: '12mm' },
waitForFonts: true
});
} finally {
await browser.close();
}
Replace the readiness selector and URL with values from your application. The example intentionally uses a finite navigation timeout and a separate readiness timeout so failures are diagnosable.
Common failures and fixes
The file is empty, missing or written elsewhere
- Confirm the process has write permission for the directory.
- Log
process.cwd(); relative paths resolve from there, not necessarily from the script’s directory. - Use an absolute path while diagnosing and check that the browser closes only after
page.pdf()resolves.
Content is missing from the PDF
- Wait for a page-specific selector or application-ready flag instead of relying only on network idle.
- Ensure lazy-loaded images are triggered before capture and that their requests are not blocked.
- Check that the content is not hidden by print CSS.
Layout is clipped or breaks across pages
- Set the intended
formator explicit dimensions and review@page. - Adjust margins or scale; use
preferCSSPageSizewhen CSS defines the document size. - For tables, apply print-safe widths and avoid unbreakable containers that exceed the page.
Colors or backgrounds differ
- Enable
printBackground: true. - Use
-webkit-print-color-adjust: exactfor elements whose exact colors matter. - Check whether print media rules intentionally change the palette.
Navigation times out
- Raise the navigation timeout only when the site is legitimately slow.
- Investigate blocked third-party requests, redirects, authentication and service-worker behavior.
- Use
domcontentloadedplus a readiness selector when perpetual connections make network-idle criteria unsuitable.
Fonts never settle
- Verify font URLs and CORS responses.
- Keep
waitForFonts: trueunless you have a reason to disable it. - Bring the page to the front if the API’s font-wait behavior is blocked by a background page.
Performance, reliability and cost decisions
Launching a browser is relatively expensive compared with reusing one. For batches, keep one browser process alive, create isolated pages or contexts, and close each page after its PDF is complete. Limit concurrency so CPU, memory and the target site are not overwhelmed. Reuse cached assets only when your content policy permits it; invoices and other personalized documents generally require fresh data.
For reproducible output, pin the Puppeteer version used in deployment and verify options against the documentation for that installed version. The documentation identified for this guidance is version 25.12.0, and individual options can change between releases. Record the URL, readiness condition, paper settings and rendering errors with each job so a failed PDF can be investigated.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request can return a PNG, JPEG, WebP or PDF, so it is useful when you need a hosted capture service rather than maintaining Chromium yourself. Cookie and consent banners, newsletter popups and chat widgets are removed before the shot. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the page verdict and billing status.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →For a PDF or image capture, see the ScreenshotNeo API documentation. cURL:
Best Value
- FROM AMERICA'S MOST TRUSTED PRINTER BRAND – Perfect for small teams printing professional-quality black & white documents and reports. Perfect for 1-3 people
- WORLD'S SMALLEST LASER IN ITS CLASS – Precision laser printing that fits anywhere
- FAST PRINT SPEEDS – Up to 21 black-and-white pages per minute single-sided
- WIRELESS WITH SELF-RESET – Helps you stay connected
- PRINT FROM ANY DEVICE – Wireless printing from any mobile device, PC or tablet. Works with Microsoft, Mac, AirPrint, Android, Chromebook and more
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
The service also offers an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. Its 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.
Frequently Asked Questions
Can Puppeteer click the operating system’s Save in the print preview?
The documented Puppeteer PDF workflow does not provide a native print-preview Save automation recipe. Generate the file with page.pdf() instead.
What happens if I omit the PDF path?
Puppeteer returns PDF bytes as a Uint8Array and does not write a file automatically.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Which media type does PDF generation use?
Print media is used by default. Call page.emulateMediaType('screen') before page.pdf() when screen styling is required.
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.




