A PhantomJS process usually “hangs” for one of three reasons: the script never calls phantom.exit(), a page or individual request never reaches a completion callback, or errors are occurring silently. Confirm the executable and version, add explicit shutdown on every terminal path, instrument page and resource callbacks, then investigate HTTPS, proxy, SELinux, and page JavaScript issues. PhantomJS 2.1.1 documentation is legacy, and the upstream project is archived, so migrate when ongoing browser compatibility matters.
First, identify which kind of hang you have
Run the same command with a known script and note whether the terminal remains occupied after the intended work is complete, or whether the page itself never reports completion. These are different failures:
- Process-lifecycle hang: rendering or inspection finished, but no code terminated PhantomJS.
- Page-lifecycle hang:
page.openhas not produced a final status because navigation or a callback path is still pending. - Request hang: one image, script, font, API call, or other resource is slow or unreachable.
- Script-error hang: a page or PhantomJS exception stopped the expected flow, while logging remained silent.
- Transport or host problem: HTTPS libraries, a Windows proxy, or SELinux interferes with loading.
Keep the target URL, operating system, PhantomJS version, command line, and terminal output together while troubleshooting. The exact cause cannot be inferred without those details.
1. Confirm the binary and invocation
Check which executable your shell resolves and record its version:
#1 Best Overall
- Includes Raspberry Pi 5 with 2.4Ghz 64-bit quad-core CPU (8GB RAM)
- Includes 128GB Micro SD Card pre-loaded with 64-bit Raspberry Pi OS, USB MicroSD Card Reader
- CanaKit Turbine Black Case for the Raspberry Pi 5
- CanaKit Low Noise Bearing System Fan
- Mega Heat Sink - Black Anodized
phantomjs --version
which phantomjs # macOS/Linux
where phantomjs # Windows
Conflicting installations can make the terminal run a different binary from the one you tested. The documented invocation is phantomjs [options] somescript.js [arg1 ...]; PhantomJS runs headlessly. Add --debug=true when you need more CLI diagnostics. See the command-line reference.
2. Guarantee an explicit exit
PhantomJS does not terminate merely because a callback has returned. The official quick start warns that you must call phantom.exit, otherwise the process is not terminated. Put termination in both success and failure paths, but only after asynchronous work such as rendering has completed.
var page = require('webpage').create();
var address = system.args[1] || 'https://example.com';
page.open(address, function (status) {
if (status === 'success') {
page.render('page.png');
phantom.exit(0);
} else {
console.log('Open failed: ' + status);
phantom.exit(1);
}
});
Do not call phantom.exit() immediately after page.open(); that can stop the browser before the callback or render operation runs. If your script has several asynchronous branches, route each intended terminal outcome through one completion function so that exactly one exit occurs.
References: Quick Start and render().
3. Instrument navigation and every requested resource
Log the navigation result and the requests around it. Configure resourceTimeout before the initial page.open; its unit is milliseconds and it applies to an individual requested resource, not to the whole script or JavaScript execution.
Recommended Free Tools
var system = require('system');
var page = require('webpage').create();
var address = system.args[1] || 'https://example.com';
page.settings.resourceTimeout = 10000; // per-resource limit, milliseconds
page.onResourceRequested = function (request) {
console.log('Request: ' + request.url);
};
page.onResourceTimeout = function (request) {
console.log('Resource timeout: ' + request.url +
' (' + request.errorString + ')');
};
page.onResourceError = function (error) {
console.log('Resource error: ' + error.url +
' (' + error.errorString + ')');
};
page.onError = function (message, trace) {
console.log('Page JavaScript error: ' + message);
if (trace && trace.length) {
console.log(trace.map(function (t) {
return ' ' + t.file + ':' + t.line;
}).join('n'));
}
};
page.onConsoleMessage = function (message) {
console.log('Page console: ' + message);
};
page.open(address, function (status) {
console.log('Page status: ' + status);
phantom.exit(status === 'success' ? 0 : 1);
});
onLoadFinished reports success or fail; the callback supplied to page.open follows that lifecycle. A timeout callback identifies the request and error details, while onResourceError records failed resources. These hooks are documented at open(), onLoadFinished, onResourceRequested, onResourceTimeout, and onResourceError.
Rank #2
- Includes Raspberry Pi 4 4GB Model B with 1.5GHz 64-bit quad-core CPU (4GB RAM)
- Includes Pre-Loaded 32GB EVO+ Micro SD Card (Class 10), USB MicroSD Card Reader
- CanaKit Premium High-Gloss Raspberry Pi 4 Case with Integrated Fan Mount, CanaKit Low Noise Bearing System Fan
- CanaKit 3.5A USB-C Raspberry Pi 4 Power Supply (US Plug) with Noise Filter, Set of Heat Sinks, Display Cable - 6 foot (Supports up to 4K60p)
- CanaKit USB-C PiSwitch (On/Off Power Switch for Raspberry Pi 4)
A resource timeout does not stop an infinite loop in your own PhantomJS code, impose a universal wall-clock deadline, or retroactively change an already-started initial navigation. If you need a job-level deadline, enforce it outside PhantomJS with your process supervisor and terminate the process deliberately.
4. Expose exceptions that otherwise look like a freeze
Page JavaScript
page.onError reports exceptions thrown by scripts inside the loaded site. Add page.onConsoleMessage when you need the site’s own console output; page console messages are not printed by default.
PhantomJS execution errors
Use a global handler for errors in your PhantomJS script itself:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsphantom.onError = function (message, trace) {
console.log('PhantomJS error: ' + message);
if (trace) {
trace.forEach(function (t) {
console.log(' at ' + t.file + ':' + t.line);
});
}
phantom.exit(1);
};
Install this handler early, before opening the page, so a syntax or runtime failure cannot leave the process waiting with no explanation. The official troubleshooting guide describes remote debugging with --remote-debugger-port=9000; connect with a WebKit-based browser such as Chrome, Chromium, or Safari to inspect execution interactively.
5. Check HTTPS, proxy, and host security
HTTPS fails but HTTP works
The troubleshooting guidance points first to the SSL libraries, usually OpenSSL. Verify that the libraries required by your PhantomJS build are installed and discoverable by the operating system, then retest the same URL. A successful HTTP request does not prove that the HTTPS trust and TLS stack is functional.
Windows is extremely slow
The default Windows proxy can introduce massive latency. If request logs show delays rather than immediate failures, test a run with:
phantomjs --proxy-type=none script.js https://example.com
Use this only when bypassing the configured proxy is appropriate for your network; corporate environments may require the proxy for access.
PC 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 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteSELinux blocks the process
SELinux is another environment-specific possibility. Inspect denial logs first and compare a failing run with the policy context. The PhantomJS troubleshooting page references a custom-policy workaround, but changing enforcement rules without examining your system’s denials can create a security problem.
6. Use logs to locate the layer that stalls
| Observed evidence | Likely layer | Next action |
|---|---|---|
| No “Page status” line and one URL repeats or remains open | Navigation or resource | Inspect request, timeout, and resource-error logs; set a per-resource timeout before page.open. |
| “Page status: success” appears, then the process remains | Process lifecycle | Find the missing terminal phantom.exit() or an outstanding asynchronous branch. |
Status is fail |
Navigation/transport | Check the failed URL, HTTPS libraries, proxy settings, and host access. |
| Page error appears | Site JavaScript | Fix or work around the offending page code; determine whether the requested output is still valid. |
| Nothing is logged | Wrong binary, early crash, or missing handlers | Verify phantomjs --version, use --debug=true, and install handlers before navigation. |
7. Decide whether to keep patching PhantomJS
The upstream repository is archived and read-only (archived May 30, 2023). Its README says development is suspended, and the wiki describes the 2.x branch as deprecated and unmaintained. Existing jobs can often be stabilized with explicit exits and diagnostics, but no ongoing browser-compatibility fixes should be expected. Migration is the safer long-term choice when the target site changes, modern TLS is required, or failures must be supported in production. The best replacement depends on your language, rendering features, and deployment constraints; the available evidence does not establish one universal successor.
Or skip the browser setup:
For a maintained screenshot endpoint, ScreenshotNeo accepts one GET request and returns PNG, JPEG, WebP, or PDF. 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. Bot checks, CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.
See the complete parameter reference in the ScreenshotNeo documentation. A direct call looks like this:
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Repair Windows errors before they cause bigger problemsFix Now →Rank #4
- Broadcom BCM2711, quad-core Cortex-A72 (ARM v8) 64-bit SoC @ 1. 5GHz
- 2. 4 GHz and 5. 0 GHz IEEE 802. 11b/g/n/ac wireless LAN, Bluetooth 5. 0, BLE
- 2 × USB 3. 0 ports, 2 x USB 2. 0 Ports
- 2 × micro HDMI ports supproting up to 4Kp60 video resolution
- Micro SD card slot for loading operating system and data storage
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Equivalent 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)
Equivalent 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}`);
ScreenshotNeo includes full-page and element capture, device presets or custom viewports, retina scale, dark mode, PDF controls, custom CSS and JavaScript, selector waits, delays or network-idle waits, request blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen-TTL caching, signed links, asynchronous webhooks, bulk capture of up to 100 URLs per call, usage reporting, and an OpenAPI specification. Parameter names used by other screenshot APIs also work, easing migration.
The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Common errors and recovery steps
“It works manually but hangs in automation”
Compare the exact binary path, environment variables, proxy, and user permissions. Log the version and run with --debug=true; multiple installations are a frequent source of contradictory results.
A single third-party asset never finishes
Use onResourceRequested to identify it, then onResourceTimeout and onResourceError to capture the failure. Decide whether the asset is necessary; blocking or ignoring a nonessential tracker may let the page complete, while a required API call needs a network or application fix.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
The callback says fail immediately
Check the URL, DNS, certificate/TLS libraries, proxy, and firewall from the same host. Test HTTP versus HTTPS to separate transport problems from page behavior.
Best Value
- Includes Raspberry Pi 5 16GB with 2.4Ghz 64-bit quad-core CPU (16GB RAM)
- Includes 128GB Micro SD Card pre-loaded with 64-bit Raspberry Pi OS, USB MicroSD Card Reader
- CanaKit Turbine Black Case for the Raspberry Pi 5
- CanaKit Low Noise Bearing System Fan
- Mega Heat Sink - Black Anodized
The process exits too early
Move phantom.exit() into the final callback after rendering or data extraction. An exit placed immediately after an asynchronous call can produce an incomplete file or no output.
Logs stop after a page exception
Keep both page.onError and phantom.onError installed. Print stack information and return a nonzero exit code so a scheduler marks the job failed instead of waiting indefinitely.
FAQ
Does resourceTimeout limit total runtime?
No. It limits each requested resource and must be set before the initial page.open. It is not a whole-process deadline.
Free tools Windows power users keep installed
One-click scans. No signup required.
Why can a successful page still leave PhantomJS running?
A successful load only reports navigation status. The script still needs an explicit phantom.exit() after all intended asynchronous work.
Is PhantomJS officially maintained?
No. The repository is archived, development is suspended, and the 2.x branch is deprecated and unmaintained. Stabilize legacy jobs if necessary, but plan a migration for continued compatibility.
Frequently Asked Questions
Can I diagnose a hang without changing the target website?
Yes. Add lifecycle and resource callbacks, enable CLI debug output, and compare HTTP and HTTPS from the same host. These steps observe the run without modifying the page.
What should a nonzero exit code mean in a scheduled job?
Return zero only after the required capture or extraction succeeds; return one (or another documented nonzero code) for navigation failure, uncaught errors, or an intentionally timed-out required resource.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Quick Recap
Why does ScreenshotNeo avoid some PhantomJS setup problems?
It performs the capture remotely, removes supported consent banners, popups, and chat widgets before the shot, and does not bill bot checks, blank pages, timeouts, failed loads, or cache hits.
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.

