To capture a PDF that a website downloads, wait for the network response before clicking the download control, identify the matching response, verify its HTTP status, and read its body after the request completes. In Puppeteer, this is different from page.pdf(): a download response is a file returned by the site, while page.pdf() renders the current page into a new PDF.
Choose the right PDF workflow first
There are two different jobs that are often described as “capturing a PDF.” Select the one that matches your requirement:
| Goal | Puppeteer approach | What you receive |
|---|---|---|
| Save the PDF generated by the website’s download button | Wait for a matching network response, then call response.buffer() |
The server-provided PDF bytes |
| Create a PDF from the page currently rendered in the browser | Call page.pdf() |
A newly generated PDF returned as a Uint8Array |
This article covers the first workflow. The generated-PDF alternative is explained later because its media and print settings are different.
Capture a server-provided PDF download
Install Puppeteer and start a browser
The example below uses the current Puppeteer API style (the API reference consulted displayed version 25.12.0). Pin and verify the version used by your project because browser and headless behavior can change between releases.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errors#1 Best Overall
- INNOVATIVE CARTRIDGE-FREE PRINTING — No more dealing with lots of tiny ink cartridges; With this wireless document and photo printer each ink bottle set is equivalent to about 90 individual cartridges²
- LESS FREQUENT INK REPLACEMENT — Replacement ink bottles don't have to be changed nearly as often as ink cartridges¹; When you choose this combination printer, scanner and copier you can print up to 4,500 pages black/7,500 color³
- COLOR PRINTING — Up to 2 years of ink in the box4 (and with every replacement ink set) for fewer out-of-ink frustrations
- ZERO CARTRIDGE WASTE — By using an Epson EcoTank printer you can help reduce the amount of cartridge waste ending up in landfills
- HOME PRINTER DESIGNED FOR RELIABILITY — The Epson EcoTank ET-2800 All-in-One Supertank Color Printer creates vivid, detailed prints and documents thanks to Micro Piezo Heat-Free Technology; Fire off 10 ISO pages per minute1 to easily finish large jobs
npm install puppeteer
Create capture-pdf.js. Replace the selector and URL-fragment predicate with values from the site you automate.
const puppeteer = require('puppeteer');
const fs = require('node:fs/promises');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com/invoice/123', {
waitUntil: 'domcontentloaded',
timeout: 60_000
});
// Register the waiter BEFORE clicking. A fast response can otherwise be missed.
const responsePromise = page.waitForResponse(response => {
const headers = response.headers();
const contentType = (headers['content-type'] || '').toLowerCase();
return response.url().includes('/download') &&
contentType.includes('application/pdf');
}, { timeout: 60_000 });
await page.click('button.download');
const response = await responsePromise;
if (!response.ok()) {
throw new Error(`PDF request failed: HTTP ${response.status()} ${response.statusText()}`);
}
const pdfBytes = await response.buffer();
await fs.writeFile('invoice-123.pdf', pdfBytes);
console.log(`Saved ${pdfBytes.length} bytes from ${response.url()}`);
} finally {
await browser.close();
}
})();
page.waitForResponse() resolves when the response status and headers are available. The subsequent response.buffer() reads the body, so your code receives the actual file. The URL fragment and content type in the predicate are examples, not universal conventions.
Use a predicate that identifies the intended request
Prefer stable evidence from the target site:
- A distinctive endpoint fragment such as
/invoices/123/pdf. - An expected query parameter or file name.
- A response header such as
content-type: application/pdf.
Some servers omit or mislabel Content-Type. If that happens, match the known endpoint and validate the status and bytes yourself. A signed download URL may differ from the URL visible before the click; inspect the final response URL rather than assuming the first request URL is the file URL.
Handle redirects and status codes correctly
A redirect response completes its request and causes a new request to the redirected URL. A matcher that only recognizes the pre-redirect URL can miss the final file. Match a stable path, inspect the resolved response URL, or observe all responses until one satisfies your file criteria.
An HTTP error is still a response. A 404 or 503 can satisfy a URL predicate, so always test response.ok() (or check the status explicitly) before saving the body. A request that reached requestfinished is complete, but completion does not mean success.
Use response events when you need more control
waitForResponse() is convenient for one expected file. An event listener is useful when a click can produce several requests or when you need diagnostics.
Rank #2
- CARTRIDGE-FREE PRINTING — Print lab-quality photos, graphics and creative projects; Get vibrant colors and sharp text with Epson's high-accuracy printhead and Claria ET Premium 6-color inks
- INK BOTTLES — Save on photos1 and creative projects with affordable in-house printing; All-in-one printer allows you to print 4" x 6" photos for about 4 cents each vs. 40 cents with traditional ink cartridges1
- LESS FREQUENT INK REPLACEMENT — Replacement ink bottles don't have to be changed nearly as often as ink cartridges¹; Printer, scanner and copier lets you print up to 6,200 color pages³
- PRINT FOR LONGER — Up to 2 years of ink in the box² (and with every replacement ink set) for fewer out-of-ink frustrations with this wireless printer
- ZERO CARTRIDGE WASTE — Epson EcoTank printer helps reduce the amount of cartridge waste ending up in landfills; Cartridge-free printer uses high-yield ink bottles; Each replacement ink bottle set is equivalent to about 100 individual ink cartridges⁴
const matches = response => {
const type = (response.headers()['content-type'] || '').toLowerCase();
return response.url().includes('/download') && type.includes('application/pdf');
};
const pdfPromise = new Promise((resolve, reject) => {
const onResponse = async response => {
if (!matches(response)) return;
page.off('response', onResponse);
try {
if (!response.ok()) {
reject(new Error(`Download returned HTTP ${response.status()}`));
return;
}
resolve(await response.buffer());
} catch (error) {
reject(error);
}
};
page.on('response', onResponse);
setTimeout(() => {
page.off('response', onResponse);
reject(new Error('Timed out waiting for the PDF response'));
}, 60_000);
});
await page.click('button.download');
const bytes = await pdfPromise;
Remove the listener as soon as it handles the intended response. Otherwise, later navigations or downloads can trigger stale handlers and duplicate work.
Understand Puppeteer’s request lifecycle
request: Puppeteer reports that a request was issued.response: status and headers are available; the body may still be downloading.requestfinished: the response body has downloaded and the request is complete.requestfailed: the request failed at the network level and does not finish normally.
For a PDF capture, waiting for the matching response gives you the object to inspect. Reading the body with response.buffer() ensures your storage code receives the completed bytes. If you instrument events, distinguish an HTTP error (a response with a status) from a network failure (a failed request).
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 matchPC 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 & 11When the download is started by navigation
Some controls navigate to a PDF URL instead of issuing an XHR or fetch request. The same response-matching principle applies, but direct navigation to a PDF document has a documented limitation in Puppeteer’s headless shell mode. If a direct PDF navigation fails unexpectedly, check which headless mode your launch configuration uses. Do not infer from that limitation that every PDF response triggered inside an ordinary page is unobservable.
For downloads that leave the page in place, waiting only for navigation is the wrong synchronization point. Wait for the file response instead. If the control opens a new tab, listen for the target/page creation and install the response waiter on that page before repeating the click sequence.
Downloaded PDF versus page.pdf()
Use page.pdf() when your application must print the current DOM, not when it must preserve a file returned by the site.
const puppeteer = require('puppeteer');
const fs = require('node:fs/promises');
(async () => {
const browser = await puppeteer.launch({ headless: true });
try {
const page = await browser.newPage();
await page.goto('https://example.com/report', { waitUntil: 'networkidle0' });
await page.emulateMediaType('screen'); // omit for the default print media
const bytes = await page.pdf({ format: 'A4', printBackground: true });
await fs.writeFile('rendered-report.pdf', bytes);
} finally {
await browser.close();
}
})();
The method returns a Promise<Uint8Array>. PDFs use print CSS by default; call page.emulateMediaType('screen') to generate with screen media. Browser printing can modify colors; CSS such as -webkit-print-color-adjust is relevant when exact colors matter. These settings do not change a server-provided download.
Rank #3
- SET IT UP ONCE AND PRINT WITH CONFIDENCE. No complicated maintenance. Just easy, reliable printing you can count on.
- INK FOR YEARS. NOT MONTHS. Up to 2 years of ink included. Get thousands of pages of cartridge-free printing. More pages, less hassle
- KEEPS PRINTING WELL AFTER COMPETITORS HAVE QUIT. No complex maintenance. Sharper text, richer colors.[2] Only with HP Smart Tank
- PREMIUM SUPPORT - Strong technical expertise to solve issues faster
- THE LAST PRINTER YOU'LL EVER NEED. Enjoy years of refillable, cartridge-free printing.
Authentication, headers, and protected files
Perform login and session setup on the same page before installing the waiter. Cookies established by that session are then sent with the download request. For a token-based application, configure the page or browser context according to the site’s authentication design, and never log credentials or signed URLs. If the endpoint requires a separate API call, verify that the request predicate includes the authenticated URL and that the response status is not a login redirect.
Reliability and performance practices
- Install the waiter immediately before the action that causes the request.
- Set a timeout appropriate to the file size and server; handle timeout errors as a distinct failure.
- Use one browser instance for multiple pages when safe, but isolate unrelated jobs in separate pages or contexts.
- Stream or persist the buffer promptly for large files instead of retaining many PDFs in memory.
- Record the final URL, status, content type, and byte count for diagnostics, while redacting credentials and private query parameters.
- Make retries deliberate. A retry after a 503 may help; repeating a request that creates a one-time signed URL may require obtaining a fresh page or link.
Troubleshooting common failures
“Timed out waiting for response”
The selector may not have clicked, the endpoint predicate may be too strict, the control may open another page, or the request may be a navigation rather than an in-page fetch. Confirm the click target, temporarily log response URLs and status codes, and broaden the predicate to a known endpoint before tightening it again.
The response is 404, 401, or 503
The event fired because an HTTP response exists; it is not proof of a successful file. Check login state, cookies, authorization, URL parameters, and server availability. Treat non-2xx statuses as failures and do not save them as PDFs.
The content type is missing or incorrect
Some servers return a generic type or rely on a signed URL. Match the stable endpoint or query pattern, then validate the status and inspect the initial bytes or file-handling policy before accepting the body.
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 →A redirect causes the match to fail
Redirects create a new request. Match the final URL pattern or a stable path shared by both stages, and log every candidate response while diagnosing.
The file is empty or truncated
Do not consume the body at the response event and assume it is complete. Await response.buffer(); if using event instrumentation, distinguish requestfinished from response. Also check whether an intermediary returned an error page with a successful transport status.
Rank #4
- Wireless Bluetooth Printer: Portable thermal printer compatible with iPhone, Android phones, iPad and tablet computers via Bluetooth. For smartphones, please download the "Nada Print" App. You can also connect to laptops and computers for printing using a USB-C cable. (Note: Laptops and computers can only be connected via USB and require the installation of a driver first. Bluetooth connection is not supported.)
- No-ink printing: Only supports US Letter and A4 size thermal paper.(Doesn't support regular paper) The no-ink portable thermal printer uses direct thermal technology, requiring no ink, toner or ribbons, making it environmentally friendly, cost-effective and time-saving. The thermal printer package comes with a roll of US Letter thermal printing paper. Note: When installing the paper, remember to switch the paper size switch on APP
- Clear Print: NDYIN N80 portable thermal printer adopts high-definition printing technology, with a 203DPI resolution to provide you with clear printing results. This mobile printer is compatible with roll paper, folded paper and tattoo transfer paper, supporting printing from your mobile phone PDF, Word, pictures and web pages anytime and anywhere. It is recommended to use our NDYIN thermal paper to achieve good printing quality
- Portable wireless printer for travel: The thermal printer is equipped with a built-in 1500mAh rechargeable battery, which can print 160 sheets of 8.5" x 11" thermal paper after being fully charged. It weighs only 1.5 pounds and is compact in size. This ink-free portable printer can be easily carried in a backpack or briefcase! It is perfect for business travel, cars, small offices, construction sites, schools and homes. You can print documents, contracts, invoices and boarding passes anytime and anywhere
- The N80 thermal printer has a wide range of uses. The package includes the N80 printer, a roll of US Letter paper(7m/roll), a user manual, a guide card, a type-C soft cable and a type C adapter. Note: The charging adapter is not included. Special thermal paper is required for use; ordinary paper cannot be used. This ink-free portable thermal printer is suitable for various scenarios such as home, school, travel, office, and outdoor, meeting the printing needs of different groups of people. This tattoo template printer is also compatible with tattoo transfer paper, making it an ideal choice for tattoo art
Direct PDF navigation fails in headless mode
Check whether you launched Puppeteer’s headless shell mode, which has a documented limitation for navigation to PDF documents. Observe a PDF response triggered within an HTML page, or use a supported headless mode for the navigation workflow.
Or skip the browser setup
If your goal is a clean image or PDF capture rather than preserving a site’s exact download response, ScreenshotNeo provides a single HTTP request. It accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response reports the page verdict and billing result 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.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
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 options such as PDF paper size, margins, page ranges, full-page lazy-image loading, CSS selectors, custom JavaScript, request blocking, cookies, headers, geolocation, caching, signed links, asynchronous jobs, and bulk capture. The free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Sign up free for ScreenshotNeo.
Quick decision checklist
- Need the exact file the site serves? Use
waitForResponse(), validate status, and readresponse.buffer(). - Need a PDF of the rendered page? Use
page.pdf()and configure media and print styling. - Could the request redirect, require authentication, or return an HTTP error? Match the final response and check every status.
- Could a headless-shell PDF navigation be involved? Check the documented mode limitation before changing unrelated code.
Frequently Asked Questions
Does Puppeteer’s download behavior require saving through the browser’s download directory?
Not for this pattern. The PDF is read directly from the matched HTTP response with response.buffer(), then your application decides where to store it.
Can I use the same response waiter for multiple PDF downloads?
Create a separate waiter for each action and use a predicate that distinguishes each endpoint or identifier. Reusing an unresolved waiter can associate a later response with the wrong click.
What should I log when diagnosing a failed capture?
Log the candidate response URL, status, content type, and byte count, while removing credentials, cookies, and private signed-query values from logs.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →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.

