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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

PhantomJS usually produces no useful image for one of four reasons: navigation failed, a page script threw an error, the screenshot was taken before asynchronous content was ready, or the page has no opaque background and the result is transparent. Start by checking the executable and page.open status, then log requests and JavaScript errors. Configure timeouts and JavaScript before opening the URL, wait for a page-specific readiness condition, and set a background when you need an opaque image.

PhantomJS is archived and its documentation is legacy guidance, so verify behavior against the version installed on your machine and the site you are capturing. The project repository is read-only and was archived on May 30, 2023.

Use a diagnostic render instead of guessing

Run the version check first:

phantomjs --version

Make sure the command resolves to the installation you expect. Multiple binaries on PATH can make a script appear to change behavior when only the executable changed.

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.

This minimal script reports whether top-level navigation succeeded and renders only after a successful load:

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

page.open('http://example.com', function (status) {
  console.log('Status: ' + status);
  if (status === 'success') {
    page.render('example.png');
  }
  phantom.exit();
});

The callback reports success or fail. A fail status means you should investigate connectivity, TLS, proxy, DNS, or a blocked dependency before interpreting the image. Always call phantom.exit(); the PhantomJS quick-start documentation warns that the process otherwise will not terminate.

Why page.open fails

Network, DNS, or proxy problems

Log every requested resource while diagnosing. This reveals whether the document, stylesheet, image, script, or third-party request is failing:

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

page.onResourceRequested = function (request) {
  console.log('Request ' + JSON.stringify(request, undefined, 4));
};

page.onResourceError = function (error) {
  console.log('Resource error: ' + JSON.stringify(error, undefined, 4));
};

page.open('https://example.com', function (status) {
  console.log('Status: ' + status);
  if (status === 'success') {
    page.render('example.png');
  }
  phantom.exit();
});

Confirm that the host is reachable from the same machine and user account that runs PhantomJS. In the Windows proxy case described by the legacy troubleshooting guide, --proxy-type=none is a possible workaround:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
phantomjs --proxy-type=none capture.js

Use that only when a proxy is actually the cause; removing a required corporate proxy will create a different failure.

HTTPS and TLS incompatibility

If HTTP works but HTTPS fails, inspect the SSL libraries used by the PhantomJS build, usually OpenSSL. Old binaries may not negotiate the protocols or certificate chains required by a modern site. Check the installed library dependencies and compare behavior with a URL whose certificate is known to work. Do not treat a successful HTTP test as proof that the HTTPS target is reachable.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

SELinux or process restrictions

The troubleshooting documentation identifies SELinux as a possible reason PhantomJS cannot operate. Review the audit log and policy for the account launching PhantomJS. Test in an approved context rather than disabling security controls globally.

Capture JavaScript errors

A page can navigate successfully while its own scripts fail. Add an error handler and print the stack:

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

page.onError = function (msg, trace) {
  console.log(msg);
  trace.forEach(function (item) {
    console.log('  ', item.file, ':', item.line);
  });
};

page.open('https://example.com', function (status) {
  console.log('Status: ' + status);
  if (status === 'success') {
    page.render('example.png');
  }
  phantom.exit();
});

Look for missing APIs, syntax errors, blocked scripts, and exceptions thrown by application code. PhantomJS uses an old WebKit engine, so pages built for current browsers may rely on JavaScript or Web APIs it does not implement. A successful status only describes the top-level navigation; it does not certify that every widget or third-party asset ran.

Wait until dynamic content is actually ready

The load callback is a useful starting point, not a universal “everything is finished” signal. Single-page applications, deferred images, charts, and API-fed components may populate after the callback. Choose a condition tied to the content you need, such as a result element acquiring text or a loading marker disappearing.

PhantomJS does not provide a universal wait duration that is correct for every site. A polling loop is safer than an arbitrary sleep:

var page = require('webpage').create();
var system = require('system');
var target = system.args[1] || 'https://example.com';
var deadline = Date.now() + 15000;

page.open(target, function (status) {
  if (status !== 'success') {
    console.log('Status: ' + status);
    phantom.exit(1);
    return;
  }
  waitForReady();
});

function waitForReady() {
  var ready = page.evaluate(function () {
    var node = document.querySelector('[data-render-ready], .results');
    return !!node && node.textContent.trim().length > 0;
  });
  if (ready) {
    page.render('example.png');
    phantom.exit();
  } else if (Date.now() < deadline) {
    setTimeout(waitForReady, 250);
  } else {
    console.log('Timed out waiting for the page-specific readiness condition');
    phantom.exit(1);
  }
}

Replace the selector and condition with one that your application controls. If no stable marker exists, add one to the page, or wait for a known state while accepting that a timeout remains possible.

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

Fix a blank or transparent screenshot

Distinguish blank from transparent

Open the image with a viewer that shows transparency over a checkerboard. If page content is visible but the surrounding pixels are transparent, the result may be expected: PhantomJS leaves the background to the page, and the FAQ states that a page with no background remains transparent.

Set an opaque color before rendering when required:

page.evaluate(function () {
  document.body.style.backgroundColor = '#ffffff';
  document.documentElement.style.backgroundColor = '#ffffff';
});
page.render('opaque.png');

If the image is entirely blank, return to the status, resource, and JavaScript logs. A missing stylesheet can make content appear misplaced; a failed script can leave an empty application shell; a capture taken too early can contain only a loading container.

Important PhantomJS settings

Keep JavaScript enabled

page.settings.javascriptEnabled defaults to true. If another part of your script disabled it, restore the setting before page.open:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
var page = require('webpage').create();
page.settings.javascriptEnabled = true;
page.open('https://example.com', function (status) {
  console.log(status);
  phantom.exit();
});

Set resource timeouts before navigation

page.settings.resourceTimeout controls when an individual resource request stops trying. Configure it before the initial page.open call and observe expirations with onResourceTimeout:

var page = require('webpage').create();
page.settings.resourceTimeout = 30000;
page.onResourceTimeout = function (request) {
  console.log('Timed out: ' + JSON.stringify(request));
};
page.open('https://example.com', function (status) {
  console.log('Status: ' + status);
  phantom.exit();
});

A longer timeout can help a slow dependency, but it cannot fix an unreachable host and can make failures take longer. Keep a script-level deadline as well when running batch jobs.

Remote debugging when logs are not enough

Launch PhantomJS with its documented remote debugger port:

phantomjs --remote-debugger-port=9000 capture.js

Use a WebKit-based browser to inspect the script and page. This can expose DOM state, console errors, and the point at which rendering diverges from expectation. Restrict debugger access to a trusted local interface or protected network; do not expose a debugging port publicly.

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

Symptom-to-fix checklist

Symptom Likely cause First action
page.open returns fail DNS, network, proxy, TLS, policy, or an unavailable URL Print status, log resources, then test connectivity and SSL libraries
Status is success, image has only a shell Asynchronous application content was not ready Poll for a page-specific selector or readiness marker
Image shows transparent outside content No page background was set Set document and body background colors before rendering
Scripts do not run javascriptEnabled was disabled or code is incompatible with old WebKit Enable JavaScript and inspect page.onError
One resource never finishes Slow or blocked dependency Set resourceTimeout, inspect onResourceTimeout, and fix the dependency
Works on one machine only Different PhantomJS binary, libraries, proxy, or security policy Compare phantomjs --version, dependencies, proxy settings, and SELinux logs

Operational limits and a safer modern workflow

PhantomJS is no longer maintained, and its archived status means fixes for current browser APIs, certificates, and anti-bot behavior should not be expected. Keep it only when you control the legacy environment and can pin the executable and its dependencies. For new automation, use a maintained browser stack or a screenshot service that can handle modern pages; validate any replacement against your own target URLs because no current head-to-head comparison is established here.

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 GET request for a PNG, JPEG, WebP, or PDF. It accepts cookie and consent banners as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing state in X-Page-Verdict and X-Billed headers. It also offers an MCP server for AI agents, including Claude, Cursor, and other MCP clients, with take_screenshot, get_page_info, and capture_pdf.

See the complete parameter list in the ScreenshotNeo documentation. A basic cURL capture is:

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}`);

Every plan includes the full feature set: full-page capture with lazy images loaded, CSS-selector element shots, device presets and custom viewports, dark mode, retina scale, PDF controls, custom CSS and JavaScript, clicks, selector or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, selectable cache TTLs, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Existing parameter names used by other screenshot APIs are accepted to ease migration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Plan Included shots Price
Free 1,000 per month $0; no card
Starter 3,000 $5
Growth 15,000 $15
Pro 60,000 $39
Scale 250,000 $99
Business 1,000,000 $249

Yearly billing gives two months free. Start with 1,000 free screenshots a month with no card, then move to a paid plan starting at $5 for 3,000 shots when needed.

FAQ

Why does PhantomJS return a blank screenshot even though the URL opens?

Top-level navigation can succeed while scripts, styles, images, or asynchronous data fail. Compare the load status with resource and JavaScript logs, then wait for the content-specific readiness condition.

How do I know whether an image is transparent?

View it over a checkerboard background or inspect its alpha channel. If the page never set a background, transparency is the documented behavior; set an explicit color before rendering.

Can increasing the timeout fix every failed capture?

No. It helps only when a resource is slow. DNS failures, blocked requests, TLS incompatibility, JavaScript exceptions, and security-policy restrictions require their respective fixes.

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.

What should I do if two PhantomJS installations behave differently?

Run phantomjs --version from the exact shell or service account that performs the capture, locate each binary, and compare their libraries, proxy configuration, and security policy.

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.