The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Use a headless browser to open the URL and print the rendered page to PDF. Puppeteer and Playwright both provide this workflow: navigate, wait for the page to be ready, generate the PDF, then save or return the resulting bytes. The choice of wait condition and print settings matters more than a one-size-fits-all code snippet.
Convert a URL to PDF with Puppeteer
Puppeteer’s PDF guide demonstrates launching a browser, navigating to a page, generating a PDF, and saving it to disk. Install Puppeteer in a Node.js project, then use this ES module function:
import puppeteer from 'puppeteer';
export async function urlToPdf(url, outputPath) {
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto(url, { waitUntil: 'networkidle2' });
await page.pdf({
path: outputPath,
format: 'A4',
printBackground: true,
preferCSSPageSize: true,
});
} finally {
await browser.close();
}
}
await urlToPdf('https://example.com', './page.pdf');
The example uses ES module syntax. The project must be configured to run ES modules, or the imports and exports must be adapted to the project’s module system. Replace the example URL and output path with the destination and file location you need.
page.pdf() uses print CSS media by default. When no path is provided, Puppeteer returns PDF bytes instead of writing the file; those bytes can be saved or sent by an HTTP handler. The API reference documents the PDF options and behavior.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
Choose when the page is ready
A PDF captures the rendered browser page, so navigation readiness is a practical decision, not just a syntax detail. Puppeteer’s documented example uses networkidle2, but that is not suitable for every site.
networkidle2: a useful starting point for pages whose network requests settle. Long polling, streaming, analytics, or other persistent requests can prevent the page from reaching an idle state.domcontentloaded: lets you proceed once the document has been parsed, but the page may still be loading images, fonts, or client-rendered content.- An explicit selector or application-ready signal: often better when the content you need appears after a known UI element or app state. Wait for that condition before printing rather than assuming all network activity has ended.
For example, if the relevant content is marked with #report-ready, wait for that selector after navigation:
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.waitForSelector('#report-ready');
const pdf = await page.pdf({ format: 'A4', printBackground: true });
Choose a signal that corresponds to the content you intend to print. A navigation event can finish before a single-page app has populated its report, while network idle can be unreachable on a page that keeps connections open.
Rank #2
Set paper size, margins, and print appearance
Puppeteer’s PDF options let you specify paper format or explicit dimensions, orientation, margins, scaling, backgrounds, headers, and footers. The PDF options reference lists the supported settings.
- Paper geometry: Use
formatfor a standard paper size such as A4, or setwidthandheight. Setlandscape: truefor a horizontal page andmarginfor print margins. - CSS page rules: Set
preferCSSPageSize: truewhen the page’s@pageCSS should take priority over the PDF dimensions supplied in code. - Backgrounds and colors: Set
printBackground: truewhen background fills or images are part of the intended output. Print rendering can modify colors by default; when exact colors matter, use the CSS property-webkit-print-color-adjust. - Scale: The documented
scalerange is 0.1 to 2. Adjust it when content needs to fit differently, while checking that text remains readable. - Headers and footers: Set
displayHeaderFooterand provideheaderTemplateorfooterTemplatefor print decorations. Templates can include injected values such as date, title, URL, page number, and total pages. - Fonts: Puppeteer documents
waitForFonts: trueas the default for PDF generation. If a page’s fonts are still not ready, investigate font loading and the selected readiness condition.
Print CSS is the default source of styling for a Puppeteer PDF. If the page is designed for screen media and that appearance is what you need, call page.emulateMediaType('screen') before page.pdf(). This changes the CSS media type used for rendering; it does not guarantee a particular layout if the site itself styles screen and print differently.
Generate a PDF with Playwright
Playwright’s Page API also supports URL navigation and PDF generation. Its PDF API returns a PDF buffer:
Rank #3
import { chromium } from 'playwright';
export async function urlToPdfBuffer(url) {
const browser = await chromium.launch();
try {
const page = await browser.newPage();
await page.goto(url, { waitUntil: 'domcontentloaded' });
return await page.pdf({ format: 'A4', printBackground: true });
} finally {
await browser.close();
}
}
const pdfBytes = await urlToPdfBuffer('https://example.com');
Handle pdfBytes as a buffer: write it to a file or return it from your application. Playwright also documents page.emulateMedia({ media: 'screen' }) for screen styling, dimensions with units such as px, in, cm, and mm, printBackground, and a scale range of 0.1 to 2.
Puppeteer or Playwright?
Both documented APIs can navigate to a URL and produce a PDF. The cited API documentation establishes those capabilities but does not establish a universal speed or fidelity winner. Actual behavior depends on the browser version, page content, and deployment environment.
Recommended Free Tools
| Consideration | Puppeteer | Playwright |
|---|---|---|
| Navigation and output | page.goto(); page.pdf() can write to a path or return bytes when no path is supplied. |
page.goto(); page.pdf() returns a PDF buffer. |
| Readiness example | The official guide uses waitUntil: 'networkidle2'. |
The example above uses waitUntil: 'domcontentloaded'; choose a condition suited to the page. |
| Media behavior | PDF output uses print media by default; call emulateMediaType('screen') for screen styling. |
Supports page.emulateMedia({ media: 'screen' }). |
| Print settings | Paper size, dimensions, orientation, margins, scaling, backgrounds, headers and footers, and CSS page-size preference are documented. | Paper formats and dimensions with units, scaling, and backgrounds are documented. |
| Browser engines, hosting, and operating cost | Depends on selected browser version and deployment environment; the cited documentation does not establish comparative performance or cost. | Depends on selected browser version and deployment environment; the cited documentation does not establish comparative performance or cost. |
Save the PDF or return it from an HTTP endpoint
For a local file, provide path to Puppeteer’s page.pdf(), as in the first example. For an HTTP endpoint, omit path and use the returned bytes as the response body. Set an appropriate PDF content type in your web framework, and make sure the browser is closed even if navigation or PDF generation throws an error.
Rank #4
Keep destination handling separate from PDF generation in a server-facing application. Validate and restrict URLs before fetching them: an endpoint that accepts arbitrary destinations can otherwise be used to make server-side requests to places it should not access. Treat generated bytes as untrusted output until they have been stored or streamed through your normal safe handling path.
Timeouts, reliability, and deployment
Browser-based conversion performs page loading and print rendering for each request, so the target page’s response and complexity affect completion time. Set a navigation timeout appropriate to your service and a PDF-generation timeout in your application’s request handling. Puppeteer documents a 30,000 ms default timeout in its PDF options reference; configure timeouts deliberately rather than assuming every destination will finish within that interval.
Close every browser instance in a finally block so failures do not leave browser processes behind. In a service, also consider how browser processes are started and hosted, what concurrency your deployment can support, and how you will handle slow or unreachable destinations. The APIs themselves do not establish a universal performance benchmark or deployment cost; measure against your own pages and hosting environment.
Troubleshooting URL-to-PDF conversion
- The PDF is missing app-rendered content: navigation may have completed before the application rendered the content. Wait for a page-specific selector or readiness signal after
goto(). - Navigation never reaches network idle: long polling or streaming may keep requests active. Use a more appropriate navigation condition, then wait for the specific content you need.
- Background colors or images are absent: enable
printBackground: true. Also check whether the site’s print CSS hides those elements. - The PDF looks different from the browser window: Puppeteer uses print media by default. Use
page.emulateMediaType('screen')only when screen styling is the desired source; otherwise adjust the site’s print CSS. - Colors change in print output: print rendering modifies colors by default. Apply
-webkit-print-color-adjustwhere exact colors matter, and inspect the rendered result. - The content is clipped or scaled too small: check paper size, dimensions, margins, orientation,
preferCSSPageSize, andscale. Page CSS may define its own@pagerules. - Fonts appear wrong or incomplete: verify the page’s fonts have loaded before printing. Puppeteer’s documented
waitForFontsdefault istrue, but a page-specific readiness check may still be needed. - The browser remains running after an error: ensure browser closure is in a
finallyblock that covers navigation and PDF generation. - A request to your conversion endpoint can reach an unintended host: validate and restrict the destination URL before navigation. Do not expose an unrestricted URL-fetching endpoint.
Or skip the browser setup
If you need a screenshot rather than a PDF, ScreenshotNeo can return a screenshot from one GET request, with options including PNG, JPEG, WebP, or PDF. For a PDF, call its API like this:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
See the ScreenshotNeo documentation for the API details. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up free for ScreenshotNeo.
Frequently Asked Questions
Can Puppeteer save a PDF directly to a file?
Yes. Pass a filesystem path in the path option to page.pdf().
Does Puppeteer use print or screen styles for PDFs?
Print styles are used by default. Call page.emulateMediaType('screen') before PDF generation to use screen media.
Can Playwright return PDF data without writing a file?
Yes. Playwright’s page.pdf() returns a PDF buffer that your application can save or send.
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.

