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.

Yes—you can debug a PhantomJS script in a graphical interface. Start PhantomJS with its legacy remote Web Inspector, open the inspector portal in Safari, Chrome, or Chromium, set breakpoints in the script, and run the paused program with __run(). PhantomJS remains headless; the browser window is a separate inspector UI. The procedure is documented, but it is a legacy workflow: the PhantomJS project says, “Important: PhantomJS development is suspended until further notice,” and the original remote-debugging notes described Linux-only support.

What the PhantomJS GUI debugger actually is

PhantomJS does not open a normal browser window for your automation code. Its QtWebKit browser runs headlessly. The graphical part is a remote Web Inspector served by PhantomJS and viewed in another browser on the same machine.

The inspector can pause your PhantomJS automation script, show source files, inspect variables, and evaluate JavaScript in its console. JavaScript belonging to the web page you load is a separate debugging target, so page-code debugging may require a second inspector tab.

Because development is suspended, do not assume that a current Chrome or Safari release will interoperate with every PhantomJS build. Treat the following as the documented, historical method and keep the endpoint local while experimenting.

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

Prerequisites and safe setup

  • A working PhantomJS executable and a script such as test.js.
  • An available local TCP port. The examples use 9000; choose another if it is occupied.
  • Safari, Chrome, or Chromium on the same computer as PhantomJS.
  • A development environment where the debugger port is not exposed to an untrusted network. The documentation describes the endpoint but does not establish a secure remote-authentication mechanism.

The old release notes state that remote debugging was Linux-only when introduced. That is a historical support statement, not a guarantee for current builds or operating systems.

Debug a PhantomJS script step by step

  1. Launch PhantomJS with the remote debugger

    From a terminal, run:

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

    Replace 9000 with your chosen free port and test.js with your script path. PhantomJS exposes the inspector portal while the script is waiting to run.

  2. Open the inspector portal

    On the same machine, navigate to http://127.0.0.1:9000 in Safari, Chrome, or Chromium. The portal lists inspector targets. Select the entry for your script; some builds display it as about:blank.

    Rank #2
    Sale

    If the portal link is blank or does not navigate correctly, use the documented direct URL:

    Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
    http://127.0.0.1:9000//webkit/inspector/inspector.html?page=1
  3. Set a breakpoint

    Open the Scripts tab, locate the script URL, and click the line number where execution should pause. A line breakpoint stops before that line runs. The inspector also has debugger-statement and exception breakpoint concepts, although features can differ in PhantomJS’s older embedded WebKit inspector.

  4. Start the paused program

    In the inspector’s Console, run:

    __run()

    Execution begins and stops at your breakpoint. Inspect values, step through statements, and evaluate expressions using the controls provided by that inspector build.

  5. Optionally start immediately

    To skip the initial manual console command, launch with:

    phantomjs --remote-debugger-port=9000 --remote-debugger-autorun=yes test.js

    Use this when you want the script to begin as soon as the inspector is ready. Manual __run() is preferable when you need to set breakpoints before any application code executes.

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

Debug JavaScript inside the page you load

There are two execution contexts:

Context What it contains Inspector target
PhantomJS script Your automation code, such as page.open, callbacks, and control flow The script target selected first
Page JavaScript Code running in the website loaded by PhantomJS A separate page target in the portal

To stop in both contexts, follow the two-inspector procedure described by the PhantomJS troubleshooting guide:

  1. Put a debugger; statement in the PhantomJS script immediately before the page evaluation call.
  2. Put another debugger; statement inside the function that will run in the page, for example the function passed to page.evaluateAsync(...).
  3. Start PhantomJS with --remote-debugger-port=9000.
  4. Open the first inspector target (the automation script) and run __run().
  5. Open a second inspector tab by selecting the page target from the portal.
  6. Continue execution in the first inspector. When the evaluated page function reaches its debugger; statement, execution pauses in the second inspector.

The second tab matters: a breakpoint in the PhantomJS context cannot display local variables from the page’s JavaScript context.

Breakpoints, stepping, and useful evidence

Choose a breakpoint that proves the failure

  • Place the first breakpoint before navigation or evaluation if you need to verify arguments and callback order.
  • Place a second breakpoint immediately after an asynchronous callback to inspect the returned status or data.
  • Use a debugger; statement when the source URL is generated dynamically or the inspector cannot resolve a stable line.
  • Enable exception breakpoints only if your inspector build exposes them; older embedded WebKit versions may not match modern DevTools controls.

Inspect asynchronous behavior

When a breakpoint is hit, check whether the callback belongs to the script target or the page target. A page evaluation may finish later than the surrounding PhantomJS function, so stepping in the wrong inspector can make a correct program look stalled.

Troubleshooting the legacy workflow

Symptom Likely cause Fix
phantomjs cannot start The executable is missing, not executable, or not on PATH. Run the binary by its full path and verify it starts without debugger options before troubleshooting the inspector.
Port bind error Another process already uses port 9000. Choose a free port, for example phantomjs --remote-debugger-port=9010 test.js, then open the matching URL.
Portal does not load PhantomJS exited, the port is wrong, or the browser is not connecting to the same machine. Keep the terminal process running, confirm the exact port, and use 127.0.0.1 rather than a hostname while testing.
Target list is empty The script ended before the portal was opened, or the selected target has not been created. Use a breakpoint early in the script, relaunch PhantomJS, and open the portal immediately.
Inspector entry is blank The portal link is incompatible with your browser or old inspector build. Try http://127.0.0.1:9000//webkit/inspector/inspector.html?page=1 directly.
Breakpoint never hits Wrong target, source not loaded, or execution already passed the line. Select the script target, set the breakpoint before __run(), and confirm the displayed script URL matches the file being executed.
Page breakpoint never hits You set it in the automation inspector instead of the page inspector. Open the second portal entry for the page and continue the first inspector until the page’s debugger; statement runs.
Navigation or TLS behaves unexpectedly The failure is in resource loading rather than JavaScript control flow. Log requests with page.onResourceRequested and inspect the requested URLs, status behavior, and network/TLS conditions.

Headless operation versus the GUI

PhantomJS 1.4 and earlier required an X server. Starting with 1.5, PhantomJS was pure headless and did not require X11 or Xvfb. That statement concerns running PhantomJS itself; it does not mean the separate inspector browser can run without a graphical environment.

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

If the remote inspector cannot be made usable in your environment, the official REPL is a smaller-scope fallback. Interactive mode has been available since PhantomJS 1.5 and evaluates typed lines immediately. It is useful for checking expressions and APIs, but it is not a replacement for source breakpoints, stepping, or page-target inspection.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Reliability and compatibility expectations

  • Pin the PhantomJS binary and the browser used as the inspector when reproducing an old debugging session.
  • Prefer a local loopback address and a disposable development script; the documented workflow does not establish authentication for the inspector endpoint.
  • Expect differences between WebKit inspector versions. A control documented for modern WebKit or Chromium is not proof that the same control exists in PhantomJS.
  • Use the script-context/page-context split when diagnosing asynchronous page evaluation; otherwise you may inspect the wrong call stack.
  • Plan a migration for long-lived projects. The PhantomJS project’s own site says development is suspended, so new browser features and compatibility fixes should not be expected.

Or skip the browser setup

If your goal is a clean image or PDF of a page rather than interactive debugging, ScreenshotNeo provides a one-request screenshot API and an MCP server for AI clients. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; failed loads, bot checks, blank pages, timeouts, and cache hits are not billed. Every response identifies the page verdict and billing status in headers.

See the complete parameter list in the ScreenshotNeo documentation. A cURL request:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://phantomjs.org -o shot.webp

Python:

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://phantomjs.org"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js:

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://phantomjs.org' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo includes full-page and element capture, device and viewport controls, dark mode, retina scale, custom CSS and JavaScript, waits, request blocking, cookies and headers, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous webhooks, bulk capture, and PDF options. Its MCP tools—take_screenshot, get_page_info, and capture_pdf—let Claude, Cursor, and other MCP clients operate it. The free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

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

Quick decision checklist

  • Need to pause PhantomJS automation code? Use the first inspector target and __run().
  • Need to pause website code? Add a second debugger; and use a second inspector target.
  • Need automatic startup? Add --remote-debugger-autorun=yes.
  • Need a quick expression check? Use the REPL, understanding that it is not a GUI debugger.
  • Need current browser compatibility or maintained tooling? Treat this PhantomJS workflow as legacy because development is suspended.

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.