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

Use PHP WebDriver’s DesiredCapabilities::htmlUnitWithJS() to request an HtmlUnit session with JavaScript enabled, then call takeScreenshot() to save the current view. This works only when the Selenium remote end you connect to accepts the HtmlUnit capability and implements the screenshot command; the PHP package does not install HtmlUnit or start Selenium for you.

What you need before writing PHP

  • PHP with Composer available on the machine running your script.
  • The Composer package php-webdriver/webdriver.
  • A running WebDriver remote end, such as the Selenium Server or another endpoint configured to accept browserName=htmlunit.
  • An endpoint path and port that match your installed Selenium version. http://localhost:4444 below is only an illustrative local address.

The project documents compatibility with Selenium Server 2.x, 3.x and 4.x, and with both W3C WebDriver and the older JsonWireProtocol. That documented range is not a guarantee that every capability combination behaves identically on every server release. Confirm the URL and routing path required by your deployment.

Install the PHP client

composer require php-webdriver/webdriver

Older tutorials may refer to facebook/php-webdriver. The project changed its package name to php-webdriver/webdriver beginning with library version 1.8.0, while the PHP namespaces remain under FacebookWebDriver.

How htmlUnitWithJS() works

DesiredCapabilities::htmlUnitWithJS() creates a capability object whose browser name is htmlunit and whose HtmlUnit-specific JavaScript setting is enabled. It requests a session; it does not download HtmlUnit, launch a server, or prove that the remote end can take screenshots.

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

The JavaScript setting is HtmlUnit-specific. In the PHP client source, attempting to apply that setting after selecting a different browser name results in an unsupported-operation exception. Use the factory when you specifically want an HtmlUnit session with JavaScript enabled.

Complete PHP example

The following script opens a page, asks the remote end for an HtmlUnit-with-JavaScript session, saves the current-view screenshot as a PNG, and always closes the session.

<?php

require_once __DIR__ . '/vendor/autoload.php';

use FacebookWebDriverRemoteDesiredCapabilities;
use FacebookWebDriverRemoteRemoteWebDriver;

$serverUrl = 'http://localhost:4444';
$driver = RemoteWebDriver::create(
    $serverUrl,
    DesiredCapabilities::htmlUnitWithJS()
);

try {
    $driver->get('https://example.com');
    $driver->takeScreenshot(__DIR__ . '/screenshot.png');
} finally {
    $driver->quit();
}

Run it from the directory containing vendor/. If the server uses a version-specific path instead of the root URL shown, replace $serverUrl with the path documented for that Selenium installation. A successful run writes screenshot.png beside the PHP file, provided the endpoint implements both the requested session and screenshot command.

Keep the session alive while diagnosing failures

For troubleshooting, temporarily move the screenshot and navigation calls inside a more verbose try block and log the exception message and stack trace. Restore the finally block before production use so abandoned sessions do not accumulate on the remote server.

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

Save screenshot data in memory

Passing a filename is optional. The documented no-argument form returns the screenshot data:

$driver->get('https://example.com');
$screenshotData = $driver->takeScreenshot();
file_put_contents(__DIR__ . '/screenshot.png', $screenshotData);

This is useful when you need to upload the bytes, attach them to a test report, or run your own image processing instead of writing directly from the WebDriver client.

Capture one element instead of the current view

Locate an element, then use the element screenshot method:

$element = $driver->findElement(
    FacebookWebDriverWebDriverBy::cssSelector('#main')
);
$element->takeElementScreenshot(__DIR__ . '/main.png');

As with the driver method, omit the path to retrieve the returned data and save or process it yourself. Element screenshot behavior still depends on the remote end’s implementation.

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

What “screenshot” means here

The PHP command reference describes driver screenshots as screenshots of the current view and element screenshots as screenshots of a selected element. Selenium’s general API describes screenshot output as base64-encoded PNG data and gives a best-effort scope: the entire page, then the current window, then the visible portion of the current frame, and finally the entire display containing the browser.

That general description is not proof that an HtmlUnit endpoint supports every scope. Do not assume that the resulting PNG is a full-page capture. If your requirement is a complete long page, a precise viewport, or browser-specific layout fidelity, test the exact endpoint and version you operate. Compare the output with a real Chrome or Firefox driver when visual accuracy matters.

HtmlUnit JavaScript and rendering limits

HtmlUnit simulates a configured browser rather than running the same rendering engine as Chrome or Firefox. Its documentation describes JavaScript execution when a page loads or when a handler is triggered and lists tested examples such as htmx 1.7.0, 1.8.4, 1.9.x and 2.0.x, and jQuery 1.8.2, 1.11.3 and 1.12.4.

Those entries are project-tested library examples, not a universal compatibility percentage. A site may still depend on APIs, CSS behavior, fonts, canvas output, WebGL, media, or browser security behavior that HtmlUnit does not reproduce. Use HtmlUnit when simulated, script-enabled page access is sufficient; use an actual browser driver when production-browser pixels are the acceptance criterion.

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

Choosing and validating the remote end

Check capability negotiation

At session creation, verify that the server accepts browserName=htmlunit and the JavaScript capability generated by htmlUnitWithJS(). A session-creation error usually means the endpoint does not provide that browser, the capability spelling is rejected, or the request reached the wrong server path.

Check screenshot support separately

A server can accept a session yet reject takeScreenshot. Run a minimal navigation-and-capture test before building a larger workflow. Also test element screenshots if your application needs them; support for one does not establish support for every screenshot scope.

Check version and deployment fit

Match the Composer client, Selenium Server or driver, protocol mode, and endpoint URL used in production. The PHP README’s broad Selenium compatibility statement should be read as documented project support, not as a promise for an unverified HtmlUnit pairing.

Common errors and fixes

“Could not start a new session”

  • Cause: the URL points to the wrong port or path, or the remote end does not accept the HtmlUnit capability.
  • Fix: confirm the server is running, copy its exact WebDriver endpoint, and inspect its session logs for the received capabilities.

Unsupported operation for JavaScript capability

  • Cause: HtmlUnit’s JavaScript setting was applied to a capability object whose browser name is not htmlunit.
  • Fix: create the object with DesiredCapabilities::htmlUnitWithJS() rather than changing a Chrome, Firefox, or other capability after the fact.

Session starts but screenshot fails

  • Cause: this remote end does not implement screenshot capture, or its implementation does not support the requested scope.
  • Fix: verify the endpoint’s command support, test takeScreenshot() immediately after navigation, and switch to an actual browser driver when the endpoint cannot provide the required image.

The file is missing or empty

  • Cause: the PHP process cannot write to the target directory, the script exits before the call, or returned data was not written correctly.
  • Fix: use an absolute writable path, check the return value of file_put_contents(), and log exceptions before the finally block quits the driver.

The page is blank or incomplete

  • Cause: navigation, scripts, asynchronous requests, or site-specific browser assumptions have not completed or are not supported by HtmlUnit.
  • Fix: inspect the loaded page and server logs, add an application-appropriate wait, and validate the same URL in a real browser driver if rendering fidelity is required.

Reliability and performance practices

  • Create one driver per controlled workflow and always call quit(); repeatedly creating abandoned sessions can exhaust the remote server.
  • Capture after navigation has reached the state your test needs. A screenshot call does not guarantee that every asynchronous request or animation has finished.
  • Use in-memory bytes when the next step is an upload or test assertion, avoiding an unnecessary temporary file.
  • Keep a small capability-and-screenshot smoke test in continuous integration so an endpoint upgrade cannot silently remove HtmlUnit or screenshot support.
  • Record the server URL, Selenium version, PHP client version, requested capability, and failure response when diagnosing intermittent behavior.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a dependable website image rather than an HtmlUnit experiment, ScreenshotNeo provides a single HTTP request for PNG, JPEG, WebP, or PDF output. Before capture it accepts the cookie or consent banner as a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each cleanup step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

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

See the ScreenshotNeo documentation for all options. A cURL request 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}`);

It supports full-page captures with lazy images loaded, CSS-selector element capture, dark mode, device presets and custom viewports, retina scale, PDF paper and page controls, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, selectable-TTL caching, signed image links, asynchronous webhooks, bulk capture of up to 100 URLs per call, a usage API, 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 shots; yearly billing provides two months free, and every feature is available on every plan. Create a free ScreenshotNeo account to start.

Which approach should you use?

Requirement PHP WebDriver with HtmlUnitWithJS ScreenshotNeo
Primary purpose Drive a WebDriver session from PHP Request a rendered image or PDF over HTTP
Infrastructure You operate a compatible remote end Use the hosted API or MCP server
Rendering model HtmlUnit simulation with its supported JavaScript behavior Configured capture options for page, element, device and document output
Failure billing Depends on your infrastructure; no API billing rule applies Failed loads, bot checks, blank pages, timeouts and cache hits are not billed

Frequently Asked Questions

Does the PHP package install HtmlUnit?

No. Composer installs the PHP WebDriver client. You must provide a remote end that accepts the HtmlUnit capability.

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

Is an HtmlUnit screenshot always full-page?

No. Screenshot scope is endpoint-dependent; test the exact server and version rather than assuming a full-page image.

Can I use this code with Chrome or Firefox?

Not with the HtmlUnit-specific factory. Use the capabilities appropriate to the browser and driver you deploy, and do not apply HtmlUnit’s JavaScript setting to another browser capability.

What image format does WebDriver return?

Selenium’s general screenshot API describes base64-encoded PNG data. The PHP client can save that data to a file or return it in memory.

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.

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.