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

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:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

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.

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

Make the output match the PhantomJS PDF

  1. Compare physical layout. Check paper size, orientation and each margin against a known PhantomJS file.
  2. Check media rules. Inspect @media print and @page. Use emulateMediaType('screen') only when the legacy output used screen styling.
  3. 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.
  4. Verify assets. Confirm custom fonts and external images are reachable from the browser process; missing assets can change pagination.
  5. Test long documents. Exercise page ranges, custom dimensions, forced page breaks, tables spanning pages and landscape output.
  6. Test cleanup. Force a navigation or print failure and verify the browser process still closes in finally.
  7. 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.

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

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.

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

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.Support on Ko-Fi

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.

One-call PDF example (see the ScreenshotNeo documentation for all options):

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
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.

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

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.

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.

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