Use Puppeteer’s page.pdf() as the programmable replacement for a PhantomJS readPdf() wrapper. It gives you navigation, authentication, DOM interaction, waits, print settings, headers and footers in JavaScript. For a URL-only shell job, Chrome’s headless --print-to-pdf flag is the closer equivalent. In both cases, expect rendering differences because Chromium and PhantomJS use different browser engines.
Choose the replacement first
| Situation | Best fit | Why |
|---|---|---|
| A Node.js application needs login, cookies, selectors, JavaScript actions or per-page options | Puppeteer | It exposes browser and page APIs, then writes a PDF with page.pdf(). |
| A script only needs to print a public URL | Chrome headless CLI | One command can load a URL and write a PDF without application code. |
| Your platform supplies Chrome and you do not want Puppeteer to download one | puppeteer-core |
You provide an installed Chrome/Chromium executable or channel explicitly. |
| You need a hosted HTTP endpoint rather than browser installation | ScreenshotNeo | It returns a screenshot or PDF from one request, removes common consent and overlay clutter, and charges only for clean captures. |
The old callback named readPdf() is not a standard PhantomJS API. Treat it as your application’s wrapper: retain its input and completion contract, but replace the implementation with a Promise-based browser call. Always close the browser in finally so a failed navigation does not leave orphaned processes.
Core migration: Puppeteer
Install the package in a Node.js project:
npm install puppeteer
When installation scripts are allowed, puppeteer downloads a compatible Chrome for Testing. Use puppeteer-core instead when your deployment manages Chrome itself; it does not download a browser, so you must configure an executable path or channel and verify that the runtime can launch it.
This complete replacement waits for the page, prints backgrounds, honors CSS page size, and cleans up on every path:
#1 Best Overall
import puppeteer from 'puppeteer';
export async function readPdf(url, outputPath = 'output.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,
preferCSSPageSize: true,
margin: {
top: '12mm',
right: '12mm',
bottom: '12mm',
left: '12mm'
}
});
return outputPath;
} finally {
await browser.close();
}
}
await readPdf('https://example.com');
Page.pdf() generates using the print CSS media type and waits for fonts by default. Keep that behavior unless you have a deliberate reason to change it. If the PhantomJS document depended on screen styles, set the media type before printing:
await page.emulateMediaType('screen');
await page.pdf({ path: 'output.pdf', printBackground: true });
For authenticated pages, establish the session before page.pdf():
await page.setCookie({
name: 'session',
value: process.env.SESSION_COOKIE,
domain: 'example.com',
path: '/'
});
await page.goto('https://example.com/invoices/42', { waitUntil: 'networkidle2' });
await page.pdf({ path: 'invoice.pdf', format: 'A4' });
You can also log in through the UI, set extra HTTP headers, or wait for application data:
await page.setExtraHTTPHeaders({ Authorization: `Bearer ${process.env.TOKEN}` });
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.waitForSelector('#report-ready', { timeout: 30000 });
await page.waitForNetworkIdle({ idleTime: 500, timeout: 30000 });
Map PhantomJS paperSize to Puppeteer
PhantomJS accepts standard paper formats, custom dimensions, margins, orientation, and repeating header/footer content. Puppeteer exposes the corresponding controls directly:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
| PhantomJS concept | Puppeteer option | Migration note |
|---|---|---|
| A3, A4, A5, Legal, Letter, Tabloid | format |
Use a named format such as 'A4' or 'Letter'. |
| Custom width and height | width, height |
Supply values with mm, cm, in or px. |
| Margins | margin.top, right, bottom, left |
Use explicit units, for example '12mm'. |
| Portrait or landscape | landscape: true |
Omit or set false for portrait. |
Document-defined @page size |
preferCSSPageSize: true |
Lets print CSS control the paper size instead of a forced format. |
| Background graphics | printBackground: true |
Enable it when the old PDF included colored backgrounds or images. |
| Repeating header/footer | displayHeaderFooter: true, headerTemplate, footerTemplate |
Templates are HTML fragments; test them separately from body content. |
Do not set both a conflicting fixed format and a CSS page size without deciding which should win. If your stylesheet contains @page { size: ... }, preferCSSPageSize: true is usually the intended migration.
Headers and footers
await page.pdf({
path: 'report.pdf',
format: 'A4',
displayHeaderFooter: true,
headerTemplate: '<div style="font-size:8px;width:100%;text-align:center">Quarterly report</div>',
footerTemplate: '<div style="font-size:8px;width:100%;text-align:center">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>'
});
Chrome’s command-line header/footer suppression and Puppeteer’s template controls are different mechanisms. Validate whichever path you deploy rather than assuming a PhantomJS header will look identical.
Rank #2
Chrome headless: the direct command-line equivalent
For a public URL, run:
chrome --headless --print-to-pdf=output.pdf https://example.com
To remove Chrome’s generated header and footer:
chrome --headless --print-to-pdf=output.pdf --no-pdf-header-footer https://example.com
Pages with long timers or animations may need bounded waiting:
chrome --headless --timeout=5000 --print-to-pdf=output.pdf https://example.com
chrome --headless --virtual-time-budget=42000 --print-to-pdf=output.pdf https://example.com
--timeout limits the wait; --virtual-time-budget advances virtual time so timers and animations can complete. These flags do not replace application-specific readiness checks, login, cookie setup or DOM interaction, which is why Puppeteer is preferable for those workflows.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteMake the output match the PhantomJS PDF
- Compare physical layout. Check paper size, orientation and each margin against a known PhantomJS file.
- Check media rules. Inspect
@media printand@page. UseemulateMediaType('screen')only when the legacy output used screen styling. - Wait for content. Navigation completion is not necessarily application readiness. Wait for fonts, images, a report-ready selector and any data request your page makes.
- Verify assets. Confirm custom fonts and external images are reachable from the browser process; missing assets can change pagination.
- Test long documents. Exercise page ranges, custom dimensions, forced page breaks, tables spanning pages and landscape output.
- Test cleanup. Force a navigation or print failure and verify the browser process still closes in
finally. - Pin versions. Record the Puppeteer and Chrome versions used in production and review upgrades because rendering and defaults change.
Common migration failures and fixes
Chrome will not launch
Cause: the binary is absent, the container blocks its sandbox, or puppeteer-core has no executable path. Fix: install a supported Chrome/Chromium runtime, configure the explicit path or channel, and test launch permissions in the same container or CI user.
The PDF is blank or missing late content
Cause: printing started before client-side rendering, fonts or images finished. Fix: use an appropriate navigation wait, then wait for a stable selector and, where necessary, network idle or a bounded application-specific delay.
Styles look wrong
Cause: page.pdf() uses print media by default, while PhantomJS may have captured screen styles. Fix: inspect print CSS and call page.emulateMediaType('screen') when that is the required behavior; enable printBackground for backgrounds.
Page size or margins changed
Cause: a fixed format overrides the intended CSS size, units were omitted, or orientation was not mapped. Fix: map every value explicitly and use preferCSSPageSize when @page is authoritative.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Rank #3
Fonts or images disappear
Cause: blocked external resources, incorrect authentication, certificate errors or a URL that is reachable from your laptop but not from CI. Fix: check browser logs and response status, provide cookies or headers before navigation, and make assets available to the runtime.
Headers or footers are duplicated
Cause: Chrome’s defaults, CLI flags and Puppeteer templates were mixed. Fix: choose one control path, disable CLI headers with --no-pdf-header-footer when appropriate, and test templates independently.
The process hangs or leaks
Cause: an exception bypassed browser shutdown or a page contains never-ending connections. Fix: wrap the entire operation in try/finally, use bounded waits, and avoid treating indefinite network activity as readiness.
Performance, reliability and operating cost
A persistent browser can amortize startup when generating many PDFs, but isolate pages and clear cookies or storage between jobs when documents contain private data. Limit concurrency to the CPU and memory available in the worker; too many simultaneous Chromium pages commonly cause contention and timeouts. For deterministic output, pin browser versions, embed or reliably serve fonts, and keep page-ready signals explicit.
Chrome and Puppeteer do not provide PhantomJS compatibility guarantees. Re-test after upgrades, especially pagination, font metrics, print CSS and JavaScript-generated content. Capture failures with the URL, browser version, navigation error, console messages and a screenshot or HTML diagnostic so a missing resource is distinguishable from a layout regression.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Or skip the browser setup
ScreenshotNeo is a hosted screenshot API and MCP server. It can return PNG, JPEG, WebP or PDF, accept cookies, headers, user agents and authorization, wait for selectors or network idle, run custom JavaScript, click or hide elements, set paper size and margins, and capture up to 100 URLs in one bulk call. Before capture it accepts cookie/consent banners and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be disabled.
Only clean shots are billed. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits cost nothing, and response headers identify the page verdict and whether it was billed. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.
Rank #4
One-call PDF example (see the ScreenshotNeo documentation for all options):
Recommended Free Tools
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account to try the hosted path.
FAQ
Is Puppeteer itself a PDF engine?
It automates Chrome (and Firefox) and asks the browser to print the page. The browser’s print CSS, fonts and rendering engine determine the final PDF.
Can I keep the old readPdf() function name?
Yes. Keep the public wrapper and callback or Promise contract used by your application, replacing only its PhantomJS internals.
When should I choose puppeteer-core?
Choose it when your image or host already installs and updates Chrome. It is not a browser download and requires an explicit executable path or channel.
Can Chrome CLI log in to a private site?
Not conveniently. Cookie injection, login flows and DOM actions are substantially easier and more controllable with Puppeteer.
Frequently Asked Questions
Does Puppeteer support custom PDF page ranges?
Yes. Pass the ranges supported by your installed Puppeteer version in the PDF options, then test them against long documents because pagination can change with browser updates.
Why does a PhantomJS PDF have different line breaks in Chromium?
Different engines use different font metrics, layout algorithms and print implementations. Match fonts and CSS first, then accept that exact pixel or line-break identity may require document-specific adjustments.
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.

