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.
This minimal script reports whether top-level navigation succeeded and renders only after a successful load:
#1 Best Overall
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:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsphantomjs --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
- 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:
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:
Rank #3
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.
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:
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Rank #4
- 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.
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.
Best Value
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.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →| 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.
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.
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.

