ScreenshotNeo

BlogHow-to

Fix Selenium Java Screenshots That Are Black When Chrome Runs Headlessly

Diagnose black screenshots from headless Chrome in Selenium Java by checking browser versions, launch options, viewport, and the active browsing context.

By the ScreenshotNeo team4 October 20267 min read

A black screenshot from headless Chrome does not point to one universal Selenium bug. Start by checking that Chrome and ChromeDriver have matching major versions, set headless mode and viewport dimensions deliberately, and verify that Selenium is capturing the intended page in the intended browser window. Then compare repeatable headless and headful runs with the same versions, page, and test steps.

This guide uses Selenium Java to collect evidence and isolate the cause. The checks are diagnostic steps, not guaranteed fixes: if they do not explain the result, record the environment and output before drawing conclusions.

1. Check Chrome, ChromeDriver, and Selenium versions

First record the versions actually used by the test. Selenium’s Chrome documentation says Chrome and ChromeDriver must match at the major-version level. A mismatch is a concrete compatibility issue to rule out before investigating image-processing theories.

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class ChromeVersionInfo {
    public static void main(String[] args) {
        ChromeOptions options = new ChromeOptions();
        WebDriver driver = new ChromeDriver(options);
        try {
            Capabilities caps = ((ChromeDriver) driver).getCapabilities();
            System.out.println("Browser: " + caps.getBrowserName());
            System.out.println("Browser version: " + caps.getBrowserVersion());
            System.out.println("ChromeDriver: " + caps.getCapability("chrome");
        } finally {
            driver.quit();
        }
    }
}

The final capability line above is not portable across Selenium versions and can be absent; use the browser version and your driver installation or startup logs to identify ChromeDriver precisely. A more portable minimal diagnostic is to record Selenium’s dependency version from your build and the Chrome/ChromeDriver versions from the environment that launches the test. For example, inspect the browser binary with google-chrome --version where that command is available, and enable your driver manager’s or CI image’s version logging.

For Selenium’s Java Chrome setup and version guidance, see Selenium’s Chrome documentation.

2. Set headless mode and viewport explicitly

Use a deliberate ChromeOptions configuration instead of relying on an inherited or outdated set of arguments. Selenium documents --headless=new as a commonly used Chrome argument. Confirm the supported behavior for the Chrome version installed in your environment; do not assume an old headless flag or copied workaround applies to every version.

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class HeadlessSetup {
    public static WebDriver createDriver() {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--headless=new");
        options.addArguments("--window-size=1920,1080");
        return new ChromeDriver(options);
    }
}

Choose a viewport that matches the test’s needs and keep it constant while diagnosing. Chrome’s headless command-line guidance pairs screenshot capture with --window-size; controlling dimensions makes comparisons repeatable, but does not prove that a particular size will fix black pixels.

Modern Chrome describes headless and headful modes as unified and says Headless shares code with Chrome. So a black image should be investigated in the context of the actual page, rendering, browsing context, and environment rather than automatically blamed on a wholly separate browser engine. Starting at Chrome 132.0.6793.0, the old Headless implementation is available only as the standalone chrome-headless-shell binary. See Chrome Headless mode.

3. Capture the intended page and window

Selenium captures the current browsing context. Before saving a screenshot, log the current URL and window handle, and make sure the test has switched to the expected tab or window. A valid PNG can still show the wrong page if the driver is on an unexpected context.

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class CaptureDiagnostic {
    public static void main(String[] args) throws Exception {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--headless=new", "--window-size=1920,1080");
        WebDriver driver = new ChromeDriver(options);
        try {
            driver.get("https://example.com");
            System.out.println("URL: " + driver.getCurrentUrl());
            System.out.println("Window: " + driver.getWindowHandle());
            File png = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
            Files.copy(png.toPath(), Path.of("selenium-shot.png"));
        } finally {
            driver.quit();
        }
    }
}

Replace the example URL with the page under investigation. Open the saved PNG independently and check its pixel dimensions. Selenium’s screenshot operation returns an image for the current browsing context; its Java documentation shows the TakesScreenshot pattern. See Selenium’s windows and tabs documentation.

4. Make the capture point repeatable

If the page is still loading or painting when the capture runs, compare screenshots taken at consistent points in the page lifecycle. This is an experiment to run against your application, not a source-established explanation for every black screenshot.

  1. Navigate to the same URL and wait for a page-specific element that indicates the content is present.
  2. Capture immediately after that condition, then capture again after a fixed delay.
  3. Compare both PNGs and record the URL, window handle, and dimensions.
  4. Keep the page, browser versions, viewport, and test actions unchanged between runs.

Do not add arbitrary delays as a permanent fix without evidence. A page-specific wait is easier to reason about and usually makes the test’s expected state explicit.

5. Compare headless and headful runs

Run the same test with headless mode enabled and disabled, keeping Chrome, ChromeDriver, Selenium, page, test steps, and viewport as consistent as possible. If headful works and headless does not, that narrows the investigation; it does not establish the root cause by itself.

Check Record Why it helps
Versions Selenium dependency, Chrome version, ChromeDriver version Rules out an obvious major-version mismatch.
Launch setup Exact ChromeOptions arguments and binary path Makes configuration differences visible.
Page and context Current URL, selected window handle, page type Confirms what Selenium captured.
Viewport and output Requested size, PNG dimensions, independently opened image Separates capture-target issues from image inspection issues.
Environment OS, container or CI details, relevant display setup Allows another developer to reproduce the conditions.

6. Troubleshoot common outcomes

Symptom What to check Next action
Chrome fails to start or the session cannot be created Chrome/ChromeDriver major versions and startup logs Install a compatible driver and browser pair, then repeat the capture.
Screenshot is valid but entirely black Current URL, active window, exact arguments, page state, and headful comparison Change one variable at a time and save each output for comparison.
Image has unexpected dimensions Requested window size and actual PNG dimensions Set an explicit viewport and rerun with the same dimensions.
Screenshot shows a browser or error page Current URL and whether navigation reached the intended page Investigate navigation, access restrictions, or the environment before treating this as a rendering failure.
Only one tab or popup is captured Selected window handle at capture time Switch to the intended handle and verify its URL before taking the screenshot.
Results vary between runs Page state, timing, versions, viewport, and environment changes Make these inputs repeatable; compare captures at a page-specific readiness condition.

The available documentation does not establish one universal defect behind black screenshots. If these checks do not resolve it, collect the details below rather than presenting an unverified workaround as a fix.

  • Chrome, ChromeDriver, and Selenium versions.
  • Operating system and CI/container details.
  • Exact ChromeOptions arguments and browser binary path.
  • Viewport, current URL (redacted if needed), and selected window handle.
  • Whether the target is a normal page or a browser/error page.
  • PNG dimensions and a representative output image, if safe to share.
  • Whether the same test works headful with otherwise matching settings.

Or skip the browser setup

If your goal is to capture a website image rather than exercise a Selenium browser session, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns an image or PDF. The API accepts familiar parameter names used by other screenshot APIs, which can make switching simpler. See the ScreenshotNeo API documentation.

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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

Replace YOUR_API_KEY with your key. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot; each cleanup step can be turned off. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. Its MCP server gives AI agents tools to take screenshots, inspect page information, and capture PDFs. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Create a free account and get 1,000 screenshots a month with no card.

Performance, reliability, and cost

For Selenium, screenshot time and reliability depend on the browser startup, page load, and test environment. Keep diagnostic runs controlled so you can identify which change affects the result. No benchmark or universal runtime is established by the cited documentation.

For repeated website captures, ScreenshotNeo offers caching with a configurable TTL, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, and a usage API. Only clean shots are billed; cache hits and the listed failed or blocked outcomes cost nothing. Plans are Free (1,000/month), Starter ($5 for 3,000), Growth ($15 for 15,000), Pro ($39 for 60,000), Scale ($99 for 250,000), and Business ($249 for 1,000,000). Yearly billing gives two months free. Every feature is on every plan. Pick Selenium when the test must drive a browser as part of application testing; consider the API when you need a hosted website capture workflow.

FAQ

Does a black screenshot prove Chrome headless is broken?

No. The title alone does not identify the cause. Check versions, options, viewport, page state, and browsing context, then compare a controlled headful run.

Should I always use --headless=new?

Selenium lists it as a commonly used argument. Verify the right mode and arguments for the Chrome version in your environment.

Can I fix every black screenshot by increasing the viewport?

No. An explicit viewport makes the capture reproducible; it is not a guaranteed remedy.

When should I use a screenshot API instead of Selenium?

Use Selenium when browser interaction is part of the test. For capturing a website without managing a local browser session, try ScreenshotNeo’s API or MCP server.