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.

PhantomJS does execute JavaScript; it does not render pages with Chrome’s browser engine. PhantomJS uses WebKit, while Chrome uses Blink, so modern pages can behave or lay out differently even when both browsers run the page’s scripts. A second common cause is timing: a page-load callback can fire before an application has finished rendering asynchronous content. Check PhantomJS’s settings, wait for the specific content you need, and use headless Chrome when the required result is Chrome’s rendering.

Does PhantomJS run JavaScript?

Yes. PhantomJS can execute page JavaScript, and its documented webpage setting javascriptEnabled is enabled by default. A screenshot that appears to omit JavaScript-rendered content does not, by itself, show that PhantomJS cannot run scripts.

The distinction is between executing JavaScript and matching Chrome. Scripts run inside the browser engine and browser environment provided by the tool. PhantomJS renders with WebKit; Chrome renders with Blink. Those engines can differ in support for browser features and in the layout or behavior they produce. A page that depends on newer browser capabilities may therefore render differently in PhantomJS even after its scripts have run.

There is also a separate timing issue: JavaScript may still be fetching data, hydrating a page, or updating the interface after the browser reports that the initial page load has completed. Capturing at that point can produce an incomplete image without any JavaScript setting being disabled.

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

Why a PhantomJS screenshot can be blank or incomplete

The page is still rendering

A page.open callback indicates that the page-load operation has completed; it does not guarantee that every application-specific task has finished. A single-page application may render its main content after a network response or after client-side code initializes. If page.render runs first, the screenshot can show a blank shell, a loading state, or only part of the page.

WebKit and Blink behave differently

PhantomJS uses WebKit, and Chrome Headless uses Blink. Differences between those engines can affect newer JavaScript and browser features as well as CSS and final layout. When the expected content is present and ready but the image still differs, the rendering engine is a likely explanation—not a universal diagnosis. The result can depend on the page, the PhantomJS build, browser settings, and viewport.

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

A setting or resource load is interfering

Before opening the page, inspect the settings that influence the capture: javascriptEnabled, loadImages, userAgent, resourceTimeout, and webSecurityEnabled. PhantomJS documents these settings as applying during the initial page.open call. JavaScript and image loading are documented as enabled by default, but a script, wrapper, or modified build may change those defaults.

Diagnose the capture in order

  1. Confirm the URL and load result. Log the requested URL and the status passed to the page.open callback. Continue only when the open operation reports success; a failed load cannot be repaired by waiting for a selector.
  2. Set and inspect page options before opening. Check JavaScript, image loading, user agent, resource timeout, and web-security configuration. The documented settings take effect for the initial open, so changing them after the page has loaded is not a reliable way to alter that navigation.
  3. Wait for the actual content. Identify a selector that only appears when the page has reached the state you need, then wait for it before rendering. A content-based condition is more reliable than choosing a short fixed delay. If the page never reaches that state, report a timeout rather than silently saving a misleading screenshot.
  4. Compare like with like. Capture the same URL at the same viewport in PhantomJS and current headless Chrome, using equivalent readiness conditions. If the content is ready but the output differs, engine behavior is a plausible cause.
  5. Choose the browser for the acceptance criterion. Use Chrome automation when the image must match Chrome. Keep PhantomJS when reproducing a legacy WebKit environment is the goal, and retain its version and settings as part of the test conditions.

Wait for JavaScript content before rendering in PhantomJS

This example waits for a known selector instead of assuming that page-load completion means the application is ready. Save it as capture.js and run it with the PhantomJS executable available in your environment, for example phantomjs capture.js https://example.com. Replace #app-ready with a selector that reflects the content required in your screenshot.

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

var url = system.args[1];
var readySelector = '#app-ready';
var output = 'phantom-shot.png';
var timeoutMs = 15000;
var pollMs = 200;

if (!url) {
  console.log('Usage: phantomjs capture.js <url>');
  phantom.exit(2);
}

// Configure these before page.open. Adjust only when the capture requires it.
page.settings.javascriptEnabled = true;
page.settings.loadImages = true;
page.settings.resourceTimeout = 30000;

page.viewportSize = { width: 1280, height: 900 };

page.onResourceTimeout = function (request) {
  console.log('Resource timed out: ' + request.url);
};

page.open(url, function (status) {
  console.log('page.open status: ' + status);
  if (status !== 'success') {
    console.log('Could not load the requested page.');
    phantom.exit(1);
    return;
  }

  var started = Date.now();
  var timer = setInterval(function () {
    var ready = page.evaluate(function (selector) {
      return !!document.querySelector(selector);
    }, readySelector);

    if (ready) {
      clearInterval(timer);
      page.render(output);
      console.log('Saved ' + output + ' after ' + (Date.now() - started) + ' ms');
      phantom.exit(0);
      return;
    }

    if (Date.now() - started >= timeoutMs) {
      clearInterval(timer);
      console.log('Timed out waiting for selector: ' + readySelector);
      phantom.exit(1);
    }
  }, pollMs);
});

The selector check runs in the page context and only tests for the element’s presence. If an element appears before it has useful content, wait for a more specific selector or test the element’s text or state with a page-context expression suited to the application. If the application has no reliable DOM marker, use an explicitly chosen delay as a fallback, while recognizing that a fixed delay can be both wasteful and too short on a slow run.

Capture the page with headless Chrome

When your requirement is Chrome’s output, use Chrome-based screenshot automation rather than trying to make PhantomJS imitate Blink. Current Chrome documentation supports headless operation and screenshot capture, but command-line flags can evolve; check the options for the Chrome version installed on the machine running the job.

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

For a basic viewport screenshot, a commonly used command is:

chrome --headless --screenshot=chrome-shot.png --window-size=1280,900 https://example.com

Use the Chrome executable name and any required environment-specific options for your installation. A basic command-line screenshot is not a substitute for an application readiness condition when a site renders content asynchronously. For a selector-based wait, use browser automation that exposes a wait-for-selector operation, such as Puppeteer:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage({
      viewport: { width: 1280, height: 900 }
    });

    await page.goto('https://example.com', {
      waitUntil: 'networkidle0',
      timeout: 60000
    });
    await page.waitForSelector('#app-ready', { timeout: 15000 });
    await page.screenshot({ path: 'chrome-shot.png', fullPage: true });
  } finally {
    await browser.close();
  }
})();

Install and pin Puppeteer according to your project’s dependency policy, and verify which Chrome or Chromium build the automation launches. Network quiet can be useful, but a page that maintains long-lived connections or polls continuously may never become network-idle. In those cases, waiting for the application’s meaningful selector is the better readiness condition. For a long page, choose viewport versus full-page capture deliberately; they produce different output dimensions and may trigger additional lazy-loaded content.

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

What to check when results still differ

  • JavaScript and assets: Confirm scripts are enabled and inspect resource timeouts or failed requests. If images are part of the expected result, ensure image loading is enabled and that capture happens after relevant assets arrive.
  • Readiness condition: Verify that the selector is specific to the desired rendered state, not just a generic container that exists in the initial HTML. Add a bounded timeout and log its outcome.
  • Viewport: Set the same width and height in both browsers. Responsive breakpoints can change navigation, columns, and even which content is visible.
  • User agent and security settings: Check whether a custom user agent changes the page served to PhantomJS. Review web-security settings only when needed; changing them can change page behavior and should not be used as a generic rendering fix.
  • Browser identity: Record the PhantomJS version/build and Chrome version. Old PhantomJS documentation describes release 2.1.1 command-line behavior and may not cover forks or modified builds; Chrome flags should be checked against the deployed version.
  • Legacy versus current output: Decide whether the desired reference is a historical PhantomJS/WebKit result or a current Chrome result. Those are different targets, and matching one does not establish that the other is defective.

Common PhantomJS screenshot problems and fixes

Symptom Likely cause What to do
Blank or mostly empty screenshot The page failed to open, scripts or resources did not load, or rendering occurred before application content appeared. Check the page.open status, inspect resource timeouts, confirm JavaScript is enabled, and wait for the expected selector before rendering.
Static parts appear, but dynamic content is missing The load callback fired before asynchronous application work finished. Wait for a content-specific selector or state. Avoid treating the load event alone as proof that the application is ready.
Images are absent Image loading may be disabled, a resource may have timed out, or the screenshot may have been taken too early. Check loadImages, resource timeout logs, and readiness timing; ensure the required images have loaded before capture.
PhantomJS output differs from Chrome after the page is ready WebKit and Blink may handle features or layout differently. Compare identical URLs, viewport sizes, and readiness criteria. If Chrome fidelity is required, capture with headless Chrome.
The wait never completes The selector is wrong, absent in the served page, or only appears under a different page state. Inspect the DOM and application state, correct the selector, and keep a timeout so the job fails visibly instead of hanging.

Or skip the browser setup

For a one-request screenshot, ScreenshotNeo accepts a URL and returns an image or PDF. The API can remove cookie/consent banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents use screenshot tools, and its free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Each cleanup step can be turned off if you need it.

Example cURL request, using the documented endpoint and a placeholder API key:

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

See the ScreenshotNeo API documentation for request options. This approach is useful when you do not need a locally managed browser process; it does not make a PhantomJS capture match Chrome, because the capture target and rendering environment are different. For Chrome-specific fidelity, retain the headless Chrome workflow above. Learn about ScreenshotNeo or sign up for the free plan.

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

Which approach fits the job?

Goal Approach
Reproduce an existing legacy PhantomJS result Keep the PhantomJS build and settings fixed, and wait for an application-specific ready condition.
Match current Chrome rendering Use headless Chrome with the same viewport and a readiness condition appropriate to the page.
Get screenshots without managing a browser installation Use a screenshot API such as ScreenshotNeo; choose it for the API workflow, not as a guarantee of Chrome-identical rendering.

The first question is not whether PhantomJS can run JavaScript—it can—but whether its WebKit environment, settings, and capture timing meet the screenshot’s acceptance criteria. Fix timing and configuration first; if the target is Chrome’s current rendering, capture in Chrome.

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.