Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use Puppeteer when you need Node.js to render a live webpage or supplied HTML in a browser and save the result as a PDF. For a webpage, navigate to its URL; for HTML, load that markup into a page first. Puppeteer’s page.pdf() uses print CSS by default and returns PDF bytes, which you can save to a file or send elsewhere. This guide covers both inputs, print layout, output handling, and common failure points.

Choose the right input workflow

There are two related jobs: rendering a webpage that is already available at a URL, and rendering HTML content your application already has. Both ultimately use a browser page and Puppeteer’s PDF method, but the page-loading step differs.

  • Use a URL when the page is hosted and should render with its own scripts, stylesheets, images, and browser behavior.
  • Use HTML content when your app generates the markup, such as an invoice or report. The markup must be loaded into a browser page before PDF generation; its referenced CSS, fonts, and images must also be reachable if they are external.

Puppeteer is a concrete browser-automation route, not a claim that it is universally faster or better than alternatives. Playwright also documents PDF generation. Both APIs use print CSS media by default; Puppeteer’s PDF guide additionally says font loading is awaited by default. See the Puppeteer PDF generation guide.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Install Puppeteer and convert a webpage URL

In a Node.js project, install Puppeteer:

npm install puppeteer

Save this as webpage-to-pdf.mjs and run it with node webpage-to-pdf.mjs:

import puppeteer from 'puppeteer';

const url = process.argv[2] ?? 'https://example.com';
const outputPath = process.argv[3] ?? 'page.pdf';

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,
  });
  console.log(`Saved PDF to ${outputPath}`);
} finally {
  await browser.close();
}

For example, node webpage-to-pdf.mjs https://example.com example.pdf navigates to the supplied URL and writes the file. The official guide illustrates launching a browser, navigating with waitUntil: 'networkidle2', setting a path, and closing the browser. That wait condition is an example, not a guarantee that every site is ready when network activity becomes idle. Pages that load content after an API call, user interaction, or application-specific signal may need an explicit readiness check.

What each operation does

  1. puppeteer.launch() starts a browser instance controlled by Puppeteer.
  2. browser.newPage() creates the tab used for rendering.
  3. page.goto(url, options) navigates to the live page and waits according to the chosen readiness condition.
  4. page.pdf(options) renders the page as a PDF. With path set, Puppeteer writes the output file.
  5. The finally block closes the browser whether the operation succeeds or throws, preventing a failed navigation or write from skipping cleanup.

Convert HTML content rather than a URL

HTML still needs to be rendered in a browser page before calling page.pdf(). Puppeteer’s API reference documents page content operations; consult the current Page.pdf() reference and the page API for the exact content-loading method supported by your installed version. The general sequence is: create a page, load your HTML into it using that version’s documented content API, wait for any required assets or application work, then call page.pdf().

For self-contained HTML, inline the CSS and data where practical. If the HTML references relative paths, make sure the browser has a meaningful base URL or use absolute URLs; otherwise stylesheets, images, and fonts can fail to load. If the markup includes remote assets, network readiness alone may not mean those assets have rendered correctly. Verify the resulting PDF rather than assuming the HTML string guarantees a complete document.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Control print styling, page size, and output

Puppeteer generates PDFs with the print CSS media type by default. This means print-specific rules such as @media print apply, and screen-only styling may not appear as expected. To render with screen styling instead, call page.emulateMediaType('screen') before page.pdf(). The equivalent Playwright API uses page.emulateMedia() before PDF generation; see the Playwright Page API.

Useful PDF options

Need Approach
Save directly to disk Set Puppeteer’s path option, for example path: 'report.pdf'.
Return bytes to application code Call page.pdf() without relying on a file path; the API returns a Uint8Array.
Set a page format or dimensions Use the documented PDF options such as format, or set width and height as appropriate. Check current option details in the Puppeteer PDFOptions reference.
Use CSS @page dimensions as the authority Set preferCSSPageSize: true; Puppeteer documents that CSS page size then takes priority over width, height, or format settings.
Add a footer Use footerTemplate with the PDF display-header/footer options described in the PDF options reference.
Retain background colors and graphics Enable printBackground. Print rendering may still alter colors unless the CSS requests exact color adjustment.

Browsers modify colors for printing by default. If exact colors matter, Puppeteer points to the CSS property -webkit-print-color-adjust; for example, a print stylesheet can use * { -webkit-print-color-adjust: exact; }. Test this against the browser and document design you deploy, since print styles affect the final appearance.

Return the PDF from a Node.js endpoint

Because page.pdf() returns a Uint8Array, you can pass its bytes to an HTTP response rather than writing a permanent file. The essential pattern is to generate the PDF, set a PDF content type, and send the bytes. In a web server, still close the browser in a finally block, and ensure a response is not sent twice if navigation or rendering throws.

For a recurring service, decide deliberately whether a browser is launched per request or managed by a longer-lived worker. Browser lifecycle, concurrency limits, memory, process isolation, and deployment packaging depend on the hosting environment; the cited API documentation does not establish one universal production or serverless recipe. Validate the browser installation and resource limits in the actual runtime before relying on a deployment pattern.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Wait for the right page state

A PDF can be technically generated yet incomplete if the page was captured before its content was ready. The official Puppeteer guide uses networkidle2 as an example navigation wait. It is useful for pages that settle, but not a substitute for knowing how the target application signals completion.

  • For a static page, a navigation completion condition may be sufficient.
  • For a client-rendered report, wait for a known element or application-ready state before printing.
  • For pages with web fonts, Puppeteer’s PDF guide states that PDF generation waits for fonts by default; confirm that the intended font actually loaded rather than silently falling back.
  • For long pages, test page breaks and print-specific CSS. Screen layout does not always translate into the desired paper layout.

Troubleshooting common PDF problems

The PDF is blank or missing dynamic content

The page may have been printed before client-side rendering completed, or the target URL may redirect to an error, login, or bot-check page. Wait for an application-specific selector or ready signal, inspect the loaded page, and verify that the URL is accessible in the browser session Puppeteer created.

Styles, images, or fonts are missing

Check browser console and network failures, relative asset paths, access controls, and whether remote resources are reachable from the runtime. For HTML strings, external relative URLs may resolve differently than they do on the site where the markup originated. Use absolute URLs or provide an appropriate base context.

Colors or backgrounds differ from the screen

PDF generation uses print media by default, so inspect @media print rules and enable background printing if needed. If color fidelity is important, apply -webkit-print-color-adjust in print CSS and verify the saved PDF in a PDF viewer.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The output ignores CSS page size

When the stylesheet’s @page size should control paper dimensions, set preferCSSPageSize: true. Avoid conflicting explicit dimensions unless you intend the PDF option values to take precedence.

Browser processes remain after an error

Put browser.close() in a finally block, as in the URL example. This ensures cleanup after navigation, PDF generation, or file-writing failures.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If you need a screenshot of a webpage rather than a locally controlled PDF layout, ScreenshotNeo offers a one-request API. It is a website screenshot API and MCP server, not a replacement for every PDF workflow; its API can return a PDF as well as PNG, JPEG, or WebP. See the ScreenshotNeo website and API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Replace YOUR_API_KEY with your key and change the target URL. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot; bot checks, blank pages, and failed loads are not billed. An MCP server lets AI agents use screenshot tools, and the Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. For PDF output, set the documented format option rather than saving the response with a misleading image extension. Sign up for ScreenshotNeo free: 1,000 screenshots a month, no card required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Sources and scope

The method details above are based on the official Puppeteer Page.pdf() method, PDF generation guide, and PDFOptions interface, plus Microsoft’s Playwright Page API. These sources document API behavior, not comparative speed, performance benchmarks, or a universal deployment configuration.

Frequently Asked Questions

Can I use Playwright instead of Puppeteer for PDF generation?

Yes. Playwright documents `page.pdf()` and its print-media default. Its media-emulation method is `page.emulateMedia()`, rather than Puppeteer’s `page.emulateMediaType()`.

Does Puppeteer return PDF data or only save a file?

Its PDF method returns a `Uint8Array`; you can also provide a `path` option to write the output to a file.

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.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.