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.

Short answer: use PhantomJS’s page.open() to load a web page, set page.paperSize when you need controlled dimensions, and call page.render('output.pdf') after the load callback reports success. That creates a PDF from the rendered page. It does not download an existing PDF response unchanged; saving an already-generated PDF is a separate HTTP or file-download operation.

PhantomJS 2.1 is the project’s latest stable release. Its development is suspended, and the GitHub repository has been archived read-only since May 30, 2023. Treat the examples below as legacy-maintenance guidance: test every target site, and do not assume modern JavaScript or CSS will render as it does in a current browser.

Render a web page as a PDF

The basic workflow is deliberately small: create a WebPage object, navigate to the URL, wait for the navigation callback, and render only after a successful load.

Minimal PhantomJS script

var page = require('webpage').create();

page.paperSize = {
  format: 'A4',
  orientation: 'portrait',
  margin: '1cm'
};

page.open('https://example.com', function (status) {
  if (status !== 'success') {
    console.log('Unable to load page');
    phantom.exit(1);
    return;
  }

  page.render('output.pdf');
  phantom.exit();
});

Save this as render.js, then run phantomjs render.js. The illustration follows the documented API order; adapt the URL, output path and layout to your page. The filename extension selects the output format, so the .pdf suffix is significant.

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.

Why the callback matters

page.open() reports success or fail. A failed navigation should stop the script rather than produce a misleading blank or partial file. A successful navigation means the page load operation completed, not necessarily that every application-driven request has finished. If the page fills itself with data after navigation, add a site-specific readiness check before rendering.

Control PDF dimensions and layout

Set page.paperSize before calling page.render() whenever the PDF must have predictable paper, orientation or margins. If you leave it unset, the webpage determines the size.

Named paper formats

PhantomJS supports A3, A4, A5, Legal, Letter and Tabloid. Orientation is portrait or landscape, with portrait as the default.

page.paperSize = {
  format: 'Letter',
  orientation: 'landscape',
  margin: {
    top: '12mm',
    left: '12mm',
    bottom: '15mm',
    right: '12mm'
  }
};

Explicit dimensions and units

Instead of a named format, provide width and height. Supported units are mm, cm, in and px; a value without a unit is interpreted as pixels.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
page.paperSize = {
  width: '210mm',
  height: '297mm',
  margin: '8mm'
};

A single margin value applies to all sides. An object lets you set top, left, bottom and right independently. Margins default to zero.

Repeating headers and footers

The paper-size API also supports a header or footer with a defined height and callback-generated contents. Use these for page numbers, report titles or dates when the same element must repeat on every page. Keep the callback output simple and verify it against multi-page documents; legacy layout behavior can vary with the page’s CSS.

Rank #2
Sale

Do not use image quality for PDF text

The optional quality argument to page.render() applies to JPEG and PNG output. It does not improve PDF text or vector output. For PDFs, adjust paper dimensions, orientation, margins and the page’s print CSS instead.

Render HTML that is already in memory

When your script already has the document string, use page.setContent(html, baseUrl) rather than making a second network navigation. This loads the supplied HTML and sets the current URL without making an HTTP request.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
var page = require('webpage').create();
var html = '' +
           '

Invoice

Amount due: $120

' + ''; page.setContent(html, 'https://example.com/invoices/'); page.paperSize = { format: 'A4', orientation: 'portrait', margin: '1cm' }; page.render('invoice.pdf'); phantom.exit();

The second argument is a meaningful base URL for resolving relative images, stylesheets and other resources. That is practical implementation guidance: make the base match the location those resources would have used, then confirm that the resulting PDF contains them.

Make asynchronous pages ready before rendering

Many sites return an initial document and populate it later with JavaScript. The page.open() callback alone does not establish that every client-side request, chart or component is ready. A common legacy pattern is to poll for a DOM marker and render only when it appears.

var page = require('webpage').create();
var ready = false;

page.open('https://example.com/report', function (status) {
  if (status !== 'success') {
    console.log('Navigation failed');
    phantom.exit(1);
    return;
  }

  window.setInterval(function () {
    ready = page.evaluate(function () {
      return !!document.querySelector('.report-ready');
    });

    if (ready) {
      page.render('report.pdf');
      phantom.exit();
    }
  }, 250);
});

Replace .report-ready with a marker your application adds after the required data is present. Also add a maximum wait in production so a missing marker cannot leave a worker running forever. If the page has no reliable marker, use a bounded delay and inspect the output carefully.

Set a solid background when the PDF is transparent

The official PhantomJS FAQ warns that a page without a defined background can render transparently. Set a background on the document before rendering when your output must be opaque.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
page.evaluate(function () {
  document.body.style.backgroundColor = '#ffffff';
});
page.render('opaque.pdf');

Check the target site’s CSS as well. A page-level background, a component background and an image with transparency can produce different results, so confirm the actual PDF rather than assuming white output.

Rendering versus downloading an existing PDF

These operations have different inputs and outputs:

Goal PhantomJS operation What you receive
Convert a webpage to PDF page.open(), then page.render('file.pdf') A new PDF generated from the page’s rendered layout
Save HTML already in memory page.setContent(html, baseUrl), then page.render() A new PDF generated from supplied HTML
Save a URL that already returns a PDF Regular HTTP/file-download handling The server’s PDF response, subject to redirects, headers and authentication

page.render() is documented as writing the current page’s rendering to a filename. It is not documented as a binary downloader for an existing PDF response. For the latter, use an HTTP client and validate status codes, redirects, authentication and response headers separately.

# Example of retrieving an existing PDF response
curl -L --fail --output existing.pdf 
  'https://example.com/files/report.pdf'

The -L option follows redirects and --fail treats HTTP errors as failures. Add the authentication headers or cookies required by the service. Do not feed an existing PDF URL to page.render() and expect the original bytes to be preserved; rendering would be a different task.

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

Official example and a maintainability warning

PhantomJS’s examples include rasterize.js under “Rendering/rasterization”; it demonstrates rasterizing a page to an image or PDF. Use that example for an end-to-end reference and the API documentation for exact option behavior.

The project’s README states, “Important: PhantomJS development is suspended until further notice.” Because the browser engine is legacy and the repository is archived read-only, modern sites may show missing fonts, broken scripts, unsupported CSS, bot checks or different pagination. For an existing PhantomJS workflow, pin the runtime, keep representative fixtures and compare generated PDFs after changes. For a new, reliability-sensitive system, evaluate a maintained browser automation stack before committing to this engine.

Troubleshooting PhantomJS PDF output

The output file is missing or empty

  • Confirm that the process can write to the destination directory and that the path is not a read-only or nonexistent location.
  • Log the status passed to page.open(); render only when it is success.
  • Keep phantom.exit() after page.render(), not before it.

The PDF is blank or missing application data

  • Check whether the page populates content after navigation.
  • Wait for a DOM readiness marker or use a bounded delay, then inspect console and resource errors.
  • Verify that required scripts and API endpoints are reachable from the PhantomJS environment.

Images, fonts or styles do not appear

  • Use an appropriate base URL with setContent() so relative resources resolve.
  • Check for mixed-content, certificate, cross-origin or authentication failures.
  • Remember that unsupported modern CSS or JavaScript may not have a straightforward workaround in the legacy engine.

Pages are clipped or split badly

  • Choose the correct named format or explicit dimensions.
  • Try landscape orientation for wide tables.
  • Adjust all four margins and inspect print-specific CSS, fixed-position elements and very wide containers.

The background is transparent

Define a page or body background color before rendering and verify that child elements do not intentionally remain transparent.

The script never exits

A readiness poll may be waiting for a selector that never appears. Add a deadline, log the last observed state and exit with a nonzero status when the deadline is reached.

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

Performance, reliability and cost considerations

Rendering time is determined by navigation, scripts, resource downloads, fonts and page complexity. Reuse a stable script shape, avoid rendering before readiness, and keep a bounded timeout around every asynchronous wait. For repeatable output, control the viewport and paper settings, freeze volatile data where possible, and test pages with representative content rather than a single empty fixture.

PhantomJS does not make a failed navigation reliable by retrying it for you. If your application retries, distinguish a transient network failure from a deterministic compatibility failure and cap the number of attempts. Store logs with the URL, status and output path so a bad PDF can be traced to its input conditions.

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 provides a single-call website screenshot and PDF API when maintaining a PhantomJS runtime is unnecessary. It accepts the cookie or consent banner like a visitor, then removes more than 60 known consent platforms, newsletter popups and chat widgets before capture; each cleanup step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the page verdict and billing result in X-Page-Verdict and X-Billed headers.

For PDF options and all request parameters, see the ScreenshotNeo documentation. A GET request can return a PDF (or PNG, JPEG or WebP depending on the request):

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

The same request in Python:

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)

And in 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}`);
if (!res.ok) throw new Error(`ScreenshotNeo request failed: ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('shot.webp', data);

ScreenshotNeo includes full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets plus custom viewports, retina scale, PDF paper size, margins, landscape and page ranges, custom CSS and JavaScript, pre-capture clicks, hidden selectors, selector/delay/network-idle waits, request and resource blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, image resizing, configurable-TTL caching, signed public-image links, asynchronous jobs with signed webhooks, bulk capture for 100 URLs per call, a usage API and an OpenAPI specification. Its parameter names are compatible with those used by other screenshot APIs, which can simplify migration. An MCP server exposes take_screenshot, get_page_info and capture_pdf to 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 shots; yearly billing provides two months free, and every feature is available on every plan. Start with the free ScreenshotNeo account.

Frequently Asked Questions

Does PhantomJS preserve the original bytes of a PDF URL?

No. page.render() creates a new PDF from the current page; use an HTTP client when the URL already serves the PDF file you need.

What should I set when a report is wider than A4 portrait?

Use a named format such as Letter or A3 with orientation: 'landscape', or provide explicit width and height, then tune the four margins.

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

Why can a successful page load still produce incomplete content?

The navigation callback covers the page-load operation, while client-side data may arrive afterward. Wait for an application-specific readiness marker or a bounded delay before rendering.

Is PhantomJS still maintained?

No. The project says development is suspended, and its repository has been archived read-only since May 30, 2023.

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.