Use Playwright’s page.pdf() method to turn a rendered page into a PDF. It returns a PDF buffer; add path to save directly to a file. Playwright uses print CSS media by default, so choose print or screen styling before exporting, then set paper size, margins, backgrounds, colors, and optional headers or footers.
Prerequisites and a minimal project
Install Node.js and a Playwright project. The following commands create a JavaScript project, install Playwright, and download its browsers:
mkdir playwright-pdf && cd playwright-pdfnpm init -ynpm install playwrightnpx playwright install
Playwright supports Chromium, WebKit, and Firefox for browser automation. The page.pdf() Page API is the export method; the separate Playwright PDF Export MCP capability is limited to Chromium.
Generate your first PDF
Create pdf.js with this complete script:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle' });
await page.pdf({ path: 'page.pdf' });
await browser.close();
})();
Run node pdf.js. The resulting page.pdf is written in the current directory. If you omit path, page.pdf() returns a buffer instead:
#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
const pdfBuffer = await page.pdf();
require('fs').writeFileSync('page.pdf', pdfBuffer);
Wait for the page state your document actually needs. networkidle helps with pages that fetch data after navigation, but it is not a guarantee that every chart, image, or font is ready. For application pages, wait for a specific selector or an application-ready signal as well.
Choose print CSS or screen CSS
Print media (the default)
By default, page.pdf() renders with print CSS media. Rules inside @media print apply, while screen-only layouts may be hidden or rearranged.
await page.goto('https://example.com/report', { waitUntil: 'domcontentloaded' });
await page.pdf({ path: 'report-print.pdf', format: 'A4' });
Screen media
To export the screen version, emulate screen media before calling page.pdf():
await page.emulateMedia({ media: 'screen' });
await page.pdf({ path: 'report-screen.pdf', format: 'A4' });
Media emulation changes CSS evaluation; it does not change the fact that the output is a PDF. Check both versions when your site has separate print and screen layouts.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Control paper size, dimensions, margins, and scale
Use a named format such as A4 or Letter, or provide explicit width and height. Dimensions and margins accept px, in, cm, and mm; a number without a unit is treated as pixels. If both a format and dimensions are supplied, format takes priority.
await page.pdf({
path: 'invoice.pdf',
format: 'A4',
margin: {
top: '18mm',
right: '16mm',
bottom: '20mm',
left: '16mm'
},
scale: 1
});
The default format is Letter, margins default to zero, and scale defaults to 1. Scale must be between 0.1 and 2. Scaling changes the rendered content size; it is not a substitute for fixing an overflowing layout.
Let CSS @page own the size
If your stylesheet defines the paper dimensions, opt into CSS precedence:
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⁴
await page.pdf({
path: 'booklet.pdf',
preferCSSPageSize: true,
printBackground: true
});
With the documented default of false, Playwright scales content to fit the API-selected paper. Set preferCSSPageSize: true when the document’s @page rules should control size instead.
Recommended Free Tools
@page {
size: 210mm 297mm;
margin: 15mm 12mm;
}
@media print {
.screen-only { display: none; }
}
Backgrounds and accurate colors
Background graphics are disabled by default. Enable them explicitly:
await page.pdf({
path: 'branded-report.pdf',
format: 'A4',
printBackground: true
});
Browsers may adjust colors for print. If exact brand colors matter, request color accuracy in your print stylesheet:
@media print {
* {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}
Inspect the generated file with the browser build and CSS used in production. Color-adjust is a request to preserve colors, not a promise that every PDF viewer will display them identically.
Add headers, footers, and page numbers
Set displayHeaderFooter: true and provide HTML templates. Playwright replaces these classes with print metadata:
date— print datetitle— document titleurl— page URLpageNumber— current pagetotalPages— total page count
await page.pdf({
path: 'report-with-footer.pdf',
format: 'A4',
displayHeaderFooter: true,
headerTemplate: '<div style="font-size:9px;width:100%;text-align:center;"><span class="title"></span></div>',
footerTemplate: '<div style="font-size:9px;width:100%;text-align:center;">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>',
margin: { top: '20mm', bottom: '20mm' }
});
Templates are isolated from the page: page styles are not visible inside them, and scripts in the templates are not evaluated. Put inline styles in the template and reserve enough top or bottom margin so content does not overlap the header or footer.
Useful options for reports and long documents
Select only certain pages
Use pageRanges for ranges such as 1-5, 8, 11-13:
await page.pdf({ path: 'extract.pdf', pageRanges: '1-5, 8, 11-13' });
Wait for application content
await page.goto('https://example.com/dashboard', { waitUntil: 'domcontentloaded' });
await page.waitForSelector('[data-report-ready]');
await page.pdf({ path: 'dashboard.pdf', printBackground: true });
For animations, freeze or disable them in print CSS. For lazy-loaded images, scroll or trigger the application’s loading behavior before export, then wait for image completion.
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.
Produce a buffer in an HTTP response
const pdf = await page.pdf({ format: 'A4' });
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'attachment; filename="report.pdf"');
res.send(pdf);
A complete production-oriented example
const { chromium } = require('playwright');
async function exportReport(url, output = 'report.pdf') {
const browser = await chromium.launch();
try {
const page = await browser.newPage({
viewport: { width: 1440, height: 900 },
deviceScaleFactor: 1
});
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60_000 });
await page.waitForSelector('[data-report-ready]', { timeout: 30_000 });
await page.evaluate(() => document.fonts.ready);
await page.pdf({
path: output,
format: 'A4',
printBackground: true,
preferCSSPageSize: true,
margin: { top: '22mm', right: '15mm', bottom: '22mm', left: '15mm' },
displayHeaderFooter: true,
headerTemplate: '<div style="font-size:8px;width:100%;padding:0 15mm;"><span class="title"></span></div>',
footerTemplate: '<div style="font-size:8px;width:100%;text-align:right;padding:0 15mm;"><span class="pageNumber"></span>/<span class="totalPages"></span></div>'
});
} finally {
await browser.close();
}
}
exportReport('https://example.com/report').catch(err => {
console.error(err);
process.exitCode = 1;
});
Troubleshooting common failures
The PDF is blank or missing data
- Cause: export ran before client-side rendering finished. Fix: wait for a stable selector, API completion marker, fonts, and images rather than relying only on navigation.
- Cause: content is hidden by print CSS. Fix: inspect
@media printrules or callpage.emulateMedia({ media: 'screen' }).
Colors or backgrounds disappear
Set printBackground: true. Add -webkit-print-color-adjust: exact when precise colors are required, and verify that the element is not hidden by print styles.
Content is clipped or overlaps the footer
Check the paper format, CSS @page, and margins. If CSS should control the paper, set preferCSSPageSize: true. Increase header or footer margins and avoid fixed-height containers that cannot expand across pages.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesHeaders or footers show no values
Confirm displayHeaderFooter: true and use the documented class names exactly. Put styles inline because page styles do not apply inside templates; do not depend on JavaScript in a template.
Navigation or export times out
Increase the relevant timeout only after identifying the slow operation. Wait for a specific readiness condition instead of networkidle when analytics, WebSockets, or long polling keep the network busy. Ensure the target is reachable from the machine running the browser and that required authentication, cookies, or headers are present.
Fonts or images differ from the website
Wait for document.fonts.ready, confirm assets load from the capture environment, and use absolute or accessible URLs. A PDF generated in CI can differ if fonts, browser versions, or network responses differ from development.
The browser will not launch in CI
Install the Playwright browser binaries with npx playwright install during the image build. Keep browser and Playwright package versions aligned, and capture launch logs before changing sandbox settings; disabling security features should be a deliberate infrastructure decision.
Free tools Windows power users keep installed
One-click scans. No signup required.
Performance, reliability, and cost considerations
- Reuse a browser process for multiple pages or jobs, but isolate unrelated documents in separate pages and close pages when finished.
- Use a readiness selector instead of an unnecessarily long fixed delay. Fixed delays make fast jobs slower and still may fail on slower pages.
- Keep PDFs deterministic: pin the Playwright version, browser build, fonts, locale, timezone, and test data where reproducibility matters.
- Set navigation and selector timeouts, handle failures with
try/finally, and record the URL, browser version, and export options with each job. - Large, image-heavy pages consume memory. Export only needed page ranges, reduce source image dimensions, or split very large documents into jobs.
- PDF generation is local browser work: account for browser CPU, memory, startup time, and the bandwidth needed to load the page and its assets.
Or skip the browser setup
If you need a hosted website capture rather than a Playwright process you maintain, ScreenshotNeo returns a PNG, JPEG, WebP, or PDF from one request. Its PDF options include paper size, margins, landscape mode, and page ranges.
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
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 authentication and PDF parameters. Equivalent examples:
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)
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(`${res.status} ${await res.text()}`);
require('fs').writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Sign up free for ScreenshotNeo.
FAQ
Does page.pdf() work with Firefox and WebKit?
Playwright supports those automation engines, but the PDF export method and its documented behavior should be checked against the Playwright version and browser engine you deploy. The dedicated PDF Export MCP capability is specifically Chromium-only.
Can I add arbitrary JavaScript to a header template?
No. Scripts in header and footer templates are not evaluated. Render the value in the page itself or pass static HTML and the documented metadata classes.
Why does my CSS @page size seem ignored?
The API defaults to fitting content to its selected paper size. Set preferCSSPageSize: true when the stylesheet’s page size should take precedence.
Frequently Asked Questions
Can I generate a PDF without writing it to disk?
Yes. Omit the path option; page.pdf() returns a PDF buffer that you can upload or send in an HTTP response.
What is the simplest way to export only pages 2 and 4?
Pass pageRanges: '2, 4' in the PDF options.
Are PDF backgrounds enabled automatically?
No. Set printBackground: true to include background graphics.
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.

