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

Use await page.pdf() for bytes and pass path when you want Puppeteer to write a file. In the documented Puppeteer 25.12.0 API, page.pdf() resolves to a Uint8Array. If another Node.js API specifically requires a Buffer, wrap that result with Buffer.from(). A separate page.createPDFStream() method returns a readable stream for stream-oriented consumers.

Choose the output form your next step needs

There are three distinct ways to obtain the generated PDF. Select one before writing your capture code:

Need Puppeteer API Result Use it when
Bytes in memory await page.pdf(options) Uint8Array Your code will upload, hash, inspect, or otherwise process the PDF without first creating a file.
Node.js Buffer Buffer.from(await page.pdf(options)) Buffer A library or function checks specifically for a Node.js Buffer.
File on disk await page.pdf({ path: 'output.pdf' }) A PDF file at the supplied path The intended hand-off is a filename or an on-disk artifact.
Readable stream await page.createPDFStream(options) ReadableStream<Uint8Array> The consumer accepts a stream and you do not need to assemble the entire document first.

The documented return type is Uint8Array, not a Puppeteer-specific or guaranteed Node.js Buffer. The Buffer conversion is ordinary Node.js byte conversion. The documentation also does not promise that a call made with path simultaneously returns usable PDF bytes, so do not design around both outputs from one invocation without checking the version you have installed.

Get a PDF as a Uint8Array or Buffer

When the next operation consumes data in memory, omit path. This complete Node.js example opens a page, creates print output, converts the bytes to a Buffer, and writes that Buffer with Node’s file system API:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
import puppeteer from 'puppeteer';
import { writeFile } from 'node:fs/promises';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.goto('https://example.com');

  // Puppeteer returns Uint8Array in the documented API.
  const pdfBytes = await page.pdf({
    format: 'A4',
    printBackground: true
  });

  // Convert only when the receiving API expects a Node.js Buffer.
  const pdfBuffer = Buffer.from(pdfBytes);
  await writeFile('output.pdf', pdfBuffer);
} finally {
  await browser.close();
}

If no Buffer-specific consumer is involved, keep pdfBytes as the Uint8Array. It already contains the complete PDF and can be passed to an API that accepts typed-array data. Await the call before using the value; the promise resolves only after PDF generation completes.

Return bytes from a function

export async function renderPdfBuffer(url) {
  const browser = await puppeteer.launch();
  try {
    const page = await browser.newPage();
    await page.goto(url);
    const bytes = await page.pdf({ format: 'A4' });
    return Buffer.from(bytes);
  } finally {
    await browser.close();
  }
}

const buffer = await renderPdfBuffer('https://example.com');
// Send buffer to an object store, HTTP response, queue, or another service.

Keeping browser shutdown in a finally block prevents a failed navigation or PDF render from leaving the browser process running.

Save the PDF directly to a file

Supply path when the desired result is a file:

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.pdf({
    path: 'output.pdf',
    format: 'A4',
    printBackground: true
  });
} finally {
  await browser.close();
}

path is optional. If you use a relative path such as output.pdf, Puppeteer resolves it from the Node.js process’s current working directory, not necessarily from the directory containing your source file. Use an absolute path when a worker, test runner, container, or service may start in a different directory. Ensure the parent directory exists and is writable before calling page.pdf().

Use the path form when a downstream job expects a filename, when the document is too inconvenient to retain in application state, or when you want Puppeteer to perform the write. Use the byte form instead when you must upload or transform the result immediately.

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.

Use a PDF stream when the consumer supports one

page.createPDFStream(options) resolves to a ReadableStream<Uint8Array>. It is an alternative interface, not a documented promise of lower memory use or faster rendering. Choose it because the receiving component accepts a stream, then measure your own workload if memory or latency matters.

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
const stream = await page.createPDFStream({
  format: 'A4',
  printBackground: true
});

const reader = stream.getReader();
const chunks = [];
try {
  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    chunks.push(Buffer.from(value));
  }
} finally {
  reader.releaseLock();
}

const pdfBuffer = Buffer.concat(chunks);

If your destination already accepts a web ReadableStream, pass stream directly and omit the chunk collection. If it requires a Buffer or a file, collecting the chunks as shown gives you the same kind of hand-off as the regular byte-returning method.

Control page size, media, backgrounds, and timing

The PDF API renders with print CSS media by default. Select screen media first when the document must follow screen styles instead:

await page.emulateMediaType('screen');
const bytes = await page.pdf({
  format: 'A4',
  printBackground: true
});

The documented Puppeteer 25.12.0 options include these defaults and controls. Verify the reference for the Puppeteer version installed in your project because signatures and defaults are version-specific.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Option Documented behavior Typical reason to set it
format Defaults to letter. Set A4 or another supported paper format for your audience or workflow.
printBackground Defaults to false. Set true when colored panels, backgrounds, or images are part of the intended design.
preferCSSPageSize Defaults to false. Set it when the page’s CSS @page size should take precedence over the selected paper format.
waitForFonts Defaults to true. Keep the default when font loading must finish before layout is captured.
timeout Defaults to 30,000 milliseconds. Increase it for legitimately slow pages; investigate the page or environment instead of masking repeated failures.
margin Controls top, right, bottom, and left margins. Reserve printable space or match a document template.
landscape Changes page orientation. Use it for wide tables, dashboards, or landscape reports.
pageRanges Restricts output to selected pages. Export only the pages needed by a downstream process.
scale Controls rendered scale. Adjust fit when content is too large or too small for the chosen page.
omitBackground Controls omission of the page background. Use only when a transparent or background-free result is intentional.

For a predictable result, decide media type, paper size, margins, background handling, and page range together. A page designed exclusively with screen CSS can look unexpectedly different if you leave print media enabled; conversely, forcing screen media can ignore print-specific rules.

A reliable capture sequence

  1. Create and manage one browser lifecycle. Launch the browser, create a page, and always close the browser in finally.
  2. Navigate to the target. Use the URL your application is authorized to access. If the page loads data asynchronously, wait for the condition your page requires before calling pdf().
  3. Select media and layout. Set screen media only when needed, then choose format, margins, orientation, page ranges, scale, and background behavior.
  4. Await the PDF operation. Keep the resolved Uint8Array, convert it to a Buffer only for a Buffer-oriented consumer, or provide path for direct file output.
  5. Validate the hand-off. Check that the expected file exists or that the byte array is non-empty before uploading or returning it.

Troubleshooting common failures

The receiving library rejects the result as the wrong type

Cause: page.pdf() returns Uint8Array in the documented API, while the library checks for Buffer specifically.
Fix: use const buffer = Buffer.from(await page.pdf(options)). Do not describe the original Puppeteer result as a Buffer.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

No file appears after a successful-looking run

Cause: the relative path was resolved from the process’s current working directory, or the parent directory is missing or not writable.
Fix: log the process working directory, use an absolute destination during diagnosis, create the parent directory, and check write permissions.

The PDF has the wrong colors or layout

Cause: PDF generation uses print media by default and backgrounds are disabled by default.
Fix: call page.emulateMediaType('screen') when screen CSS is required and set printBackground: true when backgrounds belong in the output.

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

Fonts or late content are missing

Cause: capture happened before the page finished the work that determines layout, or a font failed to load.
Fix: wait for the page-specific readiness condition before calling pdf(); retain the documented waitForFonts: true default unless you have a reason to change it.

The operation times out

Cause: the PDF operation exceeded its documented 30,000-millisecond default timeout, often because the page or environment is slow.
Fix: identify slow navigation, scripts, fonts, or resources first. Increase the PDF timeout only when the longer duration is expected and acceptable.

A stream cannot be passed to the next API

Cause: the destination expects a Buffer or file rather than a web ReadableStream.
Fix: use page.pdf() and convert its bytes, or read the stream’s chunks and combine them with Buffer.concat().

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft

Performance, reliability, and cost decisions

  • Memory: the byte and Buffer approaches keep the complete document in application memory. A stream gives a different interface, but the reviewed API documentation makes no comparative memory or speed guarantee.
  • Determinism: fixed paper settings, explicit media selection, and a page-readiness condition reduce differences between runs. Keep the Puppeteer version pinned and verify options against that installed version.
  • Failure handling: close the browser in finally, distinguish navigation failures from PDF failures in logs, and validate output before publishing it.
  • Cost: local Puppeteer rendering has the infrastructure and browser-process costs of your own runtime. The Puppeteer API documentation does not provide a per-PDF service price; budget CPU, memory, storage, and execution time from measurements in your environment.
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 only need a clean PDF of a URL, ScreenshotNeo exposes a single request instead of requiring you to manage a browser. Before capture it accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the page verdict and billing status in X-Page-Verdict and X-Billed headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients.

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

See the ScreenshotNeo API documentation for the current parameters. The PDF request can be made with cURL:

curl -G 'https://api.screenshotneo.com/v1/shot' -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o page.pdf

The same endpoint is usable from Python:

import requests

r = requests.get(
    'https://api.screenshotneo.com/v1/shot',
    params={'access_key': 'YOUR_API_KEY', 'url': 'https://example.com'},
    timeout=90,
)
r.raise_for_status()
open('page.pdf', 'wb').write(r.content)

And from Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`ScreenshotNeo returned ${res.status}`);
const bytes = Buffer.from(await res.arrayBuffer());
await Bun.write('page.pdf', bytes);

ScreenshotNeo also supports full-page capture, element selection, custom CSS and JavaScript, click and wait actions, device and viewport settings, PDF paper size, margins, landscape mode, page ranges, headers and cookies, geolocation and timezone, caching, signed links, asynchronous jobs, webhooks, bulk capture, usage reporting, and an OpenAPI specification. Every feature is included on every plan. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots, with yearly billing providing two months free.

Create a free ScreenshotNeo account to try the 1,000 monthly screenshots without a card.

FAQ

Can I rely on a relative PDF path in a scheduled job?

Only if the job’s current working directory is controlled. For scheduled workers and containers, prefer an absolute path or construct one from a known application directory.

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

Should I call page.pdf() twice to get both bytes and a file?

There is no documented guarantee that a call using path also returns usable bytes. Generate the bytes once and write them yourself when you need both outcomes, or verify the exact behavior of your installed Puppeteer version before depending on a second call.

Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

When is createPDFStream() the right interface?

Use it when the next component accepts a web readable stream. It is an interface choice, not a documented performance ranking; benchmark your actual documents if throughput or memory determines the design.

Frequently Asked Questions

Can I rely on a relative PDF path in a scheduled job?

Only if the job’s current working directory is controlled. For scheduled workers and containers, prefer an absolute path or construct one from a known application directory.

Should I call page.pdf() twice to get both bytes and a file?

There is no documented guarantee that a call using path also returns usable bytes. Generate the bytes once and write them yourself when you need both outcomes, or verify the exact behavior of your installed Puppeteer version before depending on a second call.

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

When is createPDFStream() the right interface?

Use it when the next component accepts a web readable stream. It is an interface choice, not a documented performance ranking; benchmark your actual documents if throughput or memory determines the design.

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.