ScreenshotNeo

BlogComparisons

PhantomJS vs Selenium for Screenshots of Dynamic Web Pages

Compare PhantomJS and Selenium for dynamic-page screenshots, with runnable examples, practical trade-offs, troubleshooting, and a managed alternative.

By the ScreenshotNeo team4 October 202610 min read

Short answer: Choose Selenium for a new screenshot workflow. Its WebDriver project supports automation across major browsers and remains actively documented. PhantomJS can render screenshots with a headless WebKit browser, but its development is suspended and its GitHub repository is archived. Keep PhantomJS mainly for maintaining legacy scripts or reproducing an older rendering environment. This recommendation follows project status and architecture; it is not based on a comparative performance test.

Both tools can load a page and capture an image. The practical difference is whether you need the historical, bundled PhantomJS browser or Selenium’s ability to automate a browser implementation you choose. For dynamic pages, either way, your script must wait for the specific content you need before capturing.

1. Comparison at a glance

Question PhantomJS Selenium
What is it? A scriptable headless browser based on QtWebKit. A browser automation project centered on WebDriver.
Project status Development is suspended; the GitHub repository is archived and read-only. Actively documented WebDriver ecosystem with support for automation across major browsers.
Browser choice Uses its bundled WebKit-based browser. Automates a selected browser implementation, such as Chrome, Firefox, or Safari, depending on your environment.
Screenshot controls Its guide documents viewport dimensions and a clip rectangle. WebDriver provides screenshot capture for the active browsing context; browser and binding APIs determine available details.
Setup and operations Historically straightforward as a bundled headless browser, but legacy dependencies can be difficult to maintain. Requires a compatible browser and driver environment. Selenium Manager can help with browser and driver management; Grid can distribute sessions.
Best fit Existing scripts that must be preserved, or deliberate reproduction of an old rendering environment. New workflows where browser choice, continued documentation, or browser-specific rendering matters.

The sources establish project design and status, not universal rendering accuracy or speed. Test the target site in the browser engine that matters to your users.

2. When to use each

Choose Selenium when

  • You are starting a new screenshot automation workflow.
  • You need to automate a particular browser implementation or compare behavior across browsers.
  • Your page relies on current browser behavior, modern JavaScript, or browser-specific rendering.
  • You want to use Selenium’s documented browser and driver management options, or scale sessions with Grid.

Keep PhantomJS when

  • You already have a stable script and the cost of migration is greater than the value of changing it.
  • You specifically need output from its historical WebKit-based environment for comparison or regression reproduction.
  • You can accept a suspended project and own the maintenance of its runtime and dependencies.

Do not assume that Selenium always looks more accurate or that PhantomJS always fails on modern sites. Those are site- and browser-dependent questions. Capture a representative page at the intended viewport, wait for its asynchronous content, and compare the actual output.

3. Selenium: runnable Python screenshot example

This example uses Selenium’s Python binding and Chrome. Install Selenium and make Chrome available in the environment. Selenium Manager may assist with browser-driver management, but the machine still needs a usable browser installation and network or cached driver availability as applicable.

python -m pip install selenium
from pathlib import Path
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait

url = "https://example.com"
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument("--window-size=1440,1000")

driver = webdriver.Chrome(options=options)
try:
    driver.set_window_size(1440, 1000)
    driver.get(url)

    # Replace this condition with a selector that represents the content
    # your page needs before it is ready to capture.
    WebDriverWait(driver, 20).until(
        lambda browser: browser.execute_script(
            "return document.readyState"
        ) == "complete"
    )

    Path("shot.png").write_bytes(driver.get_screenshot_as_png())
finally:
    driver.quit()

document.readyState == "complete" only indicates that the document load lifecycle reached that state. It does not guarantee that a client-rendered chart, API response, animation, lazy image, or font has finished. Replace the generic wait with a meaningful page condition, for example waiting for a result container to appear or a loading indicator to disappear.

Capture a specific element

When only one component matters, wait for it and capture its element. This avoids saving the surrounding page and makes the desired region explicit.

from selenium.webdriver.common.by import By

chart = WebDriverWait(driver, 20).until(
    lambda browser: browser.find_element(By.CSS_SELECTOR, "#chart")
)
chart.screenshot("chart.png")

Element screenshots can be affected by the element’s visibility, size, scrolling position, and browser behavior. If the element is below the fold, Selenium may scroll it into view as part of the operation. Check the result when sticky headers or overlays matter.

Full-page screenshots

The basic WebDriver screenshot captures the current browsing context, typically the visible viewport. Full-page capture is not a uniform cross-browser WebDriver behavior. If you need an entire long page, check the chosen browser and Selenium binding’s supported approach, or capture and stitch viewport segments. Segment stitching must account for sticky elements, lazy-loaded content, and page layout changes between scrolls.

4. PhantomJS: legacy JavaScript screenshot example

PhantomJS’s official guide demonstrates loading a page, setting a viewport, and saving a rendered image. This example reflects its legacy API and is for an existing PhantomJS 2.1-era environment, not a recommendation to deploy a new dependency.

var page = require('webpage').create();
page.viewportSize = { width: 1440, height: 1000 };

page.open('https://example.com', function (status) {
  if (status !== 'success') {
    console.error('Could not load the page');
    phantom.exit(1);
    return;
  }

  // A fixed delay is only an example. Prefer a page-specific readiness
  // condition when maintaining a real dynamic-page capture.
  window.setTimeout(function () {
    page.render('shot.png');
    phantom.exit();
  }, 2000);
});

PhantomJS also documents clipping through a clip rectangle. The page’s viewport and clip rectangle serve different purposes: the viewport sets the browser’s rendering dimensions, while the clip rectangle limits the output region. For exact options and legacy behavior, refer to the [PhantomJS capture documentation](https://phantomjs.org/screen-capture.html) and [quick start](https://phantomjs.org/quick-start.html).

5. Make dynamic-page captures reliable

A page can finish its initial navigation while still changing. Build screenshot readiness around the content being captured rather than relying on one arbitrary delay.

  1. Set the viewport first. Responsive layout, breakpoints, and image selection can change with width and height.
  2. Navigate to the final URL. Account for redirects and authentication if the page requires them.
  3. Wait for a page-specific signal. Examples include a result selector appearing, a loading indicator disappearing, or a known application state becoming available.
  4. Handle late assets. If images or fonts matter, wait for them explicitly where the page permits. Lazy-loaded content may require scrolling it into view.
  5. Capture and inspect representative output. Check clipping, overlays, animation, and whether the expected data is present.
  6. Always close the browser session. Use a cleanup block so failures do not leave browser processes behind.

Network-idle checks can help, but they are not universally reliable: analytics, polling, and streaming connections may keep requests open, while delayed work can begin after apparent idle. A selector or application-specific readiness signal is usually more meaningful.

6. Browser setup and configuration choices

Browser and driver management

Selenium is an automation interface, not a browser bundled into one fixed rendering engine. Install or provide the browser you intend to automate. Selenium documentation describes Selenium Manager for browser and driver management; Grid is available when browser sessions need to be distributed. In CI or containers, pin and document the browser environment when reproducibility matters.

Viewport and output

  • Viewport: Set width and height before navigation or capture so responsive rendering uses the intended layout.
  • Format: The Python example writes the PNG bytes returned by WebDriver. Select a conversion step if your workflow needs JPEG or WebP.
  • Region: Use an element screenshot where supported for component capture; use a browser-specific full-page method or viewport segmentation for long pages.
  • State: Set up authentication, cookies, locale, and test data before capture if they affect the page.
  • Animation: If a moving element makes output unstable, use application or browser-specific controls to reach a stable state before saving.

PhantomJS capture controls

PhantomJS’s documented capture flow exposes viewport sizing and a clip rectangle. Its archived status means the exact runtime and available behavior should be treated as legacy-specific. Preserve the version and environment needed by an existing script rather than assuming current browser compatibility.

7. Troubleshooting

Symptom Likely cause What to do
Screenshot shows a loading state or missing content Navigation completed before application data or client rendering was ready. Wait for a page-specific selector or state. Increase the timeout only if the page legitimately needs more time.
Blank, incomplete, or error page Navigation failed, the site returned an error, or the browser could not reach the target. Check the final URL, network access, redirects, authentication, and browser logs; capture only after confirming a successful page state.
Element screenshot fails The selector did not match, the element is hidden, or it has no usable dimensions. Wait for the correct selector, confirm it is visible and sized, and ensure the page is in the expected state.
Output has the wrong layout Viewport dimensions were set too late or differ from the target device. Set the viewport before navigation and use consistent dimensions for every run.
WebDriver cannot start a browser Browser or driver is missing, incompatible, or unavailable in the runtime. Install/provide the browser, review Selenium Manager’s resolution, and check environment permissions and executable paths.
PhantomJS behaves differently from a current browser It renders with its legacy WebKit-based browser and is no longer under active development. Keep it only when reproducing that legacy output is required; migrate new work to a maintained browser automation workflow.
Flaky output across runs Timing, animations, changing data, lazy loading, or external content varies. Use deterministic fixtures where possible, wait for application readiness, disable or finish animations, and control viewport and browser versions.
Browser processes accumulate Cleanup was skipped after an exception. Put driver shutdown in a finally block and set sensible job-level timeouts.

8. Performance, reliability, and cost

The research sources provide no comparative benchmark, so there is no defensible universal speed claim for PhantomJS versus Selenium. Actual time depends on the page, browser startup, assets, waits, and capture size. Measure your own representative workload if throughput determines the design.

  • Performance: Reusing a managed browser session across a batch can avoid repeated startup overhead, but isolate page state between captures and close sessions reliably. Limit parallel sessions to the CPU and memory available.
  • Reliability: Pin browser versions for stable visual output where appropriate, wait on page-specific readiness, record failures, and retry only transient failures. Do not retry deterministic selector or authentication errors indefinitely.
  • Reproducibility: Record the browser, viewport, target URL, and relevant page state with each artifact. Rendering can change as sites and browser versions change.
  • Cost: Self-hosted automation consumes compute, storage, and maintenance time. Selenium Grid can distribute browser sessions, but it adds infrastructure to operate. PhantomJS has no current maintenance path for new browser changes; account for the cost of owning its legacy environment.

9. ScreenshotNeo: an alternative to try first

For a new workflow where you want an API rather than operating browser and driver processes, try ScreenshotNeo first. It returns a screenshot or PDF from one GET request, and its MCP server gives AI agents tools to capture screenshots and inspect pages. Cookie and consent banners, newsletter popups, and chat widgets are removed before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, with page verdict and billing information in response headers.

Or skip the browser setup

Use the documented [ScreenshotNeo API options](https://screenshotneo.com/docs/) to control capture behavior. The minimal calls below save a screenshot of the target URL:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
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)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie banners, popups, and chat widgets are removed before the shot.
  • Bot checks, blank pages, and failed loads are never billed.
  • An MCP server lets AI agents use screenshot, page-info, and PDF tools.
  • 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000.

See the API documentation for the full set of capture options. Start with 1,000 free screenshots a month, no card required.

10. Frequently asked questions

Is PhantomJS still maintained?

No. Its official site says development is suspended, and its GitHub repository is archived and read-only.

Can Selenium take screenshots without opening a visible browser window?

Yes. The Python example uses Chrome’s headless option; the exact configuration depends on the browser and runtime.

Does Selenium capture an entire long page?

The basic screenshot captures the current browsing context, generally the viewport. Full-page behavior varies by browser and binding, so confirm the supported method for your chosen setup.

Which tool is faster?

The cited documentation does not establish a comparative speed result. Benchmark the specific pages, browser versions, and concurrency you expect to run.

Should an existing PhantomJS script be migrated immediately?

Not automatically. If it is stable and reproducing its legacy rendering is useful, keeping it may be reasonable. For new work or browser behavior that needs ongoing support, Selenium is the more defensible default.

Sources