ScreenshotNeo

BlogHow-to

How to Fix a Selenium Screenshot File That Is Empty in Headless Chrome

Trace an empty headless Chrome screenshot to capture, file writing, or a later overwrite with a step-by-step Selenium diagnostic.

By the ScreenshotNeo team4 October 20267 min read

An empty Selenium screenshot file can come from three different stages: Chrome returned no image bytes, Selenium could not write the bytes to the requested path, or another step later truncated or replaced the file. Check the screenshot byte count, the save method’s boolean result, the file size, and the browser window dimensions to locate the failure. Headless mode alone does not mean screenshot capture is unsupported: Selenium’s official examples show headless Chrome screenshots, and Chrome’s headless documentation demonstrates capture with explicit window dimensions.

Use an absolute path to an existing writable directory and a filename ending in .png. Then compare an in-memory capture with the file Selenium writes. The official documentation does not identify one universal cause or a required delay that fixes every empty file, so use the evidence from your session.

1. Run a diagnostic that separates capture from saving

Run this after navigation has completed and before any cleanup or teardown code. It checks the browser response, Selenium’s save result, and the resulting file size.

from pathlib import Path

path = Path("/absolute/path/screenshot.png")
path.parent.mkdir(parents=True, exist_ok=True)

png = driver.get_screenshot_as_png()
print("PNG bytes:", len(png))

saved = driver.save_screenshot(str(path))
print("save_screenshot returned:", saved)
print("file bytes:", path.stat().st_size if path.exists() else "file missing")

assert len(png) > 0, "WebDriver returned no PNG bytes"
assert saved, f"Selenium could not save screenshot to {path}"
assert path.exists() and path.stat().st_size > 0, "Screenshot file is missing or empty"

get_screenshot_as_png() returns the image as bytes. The file methods return a boolean; False indicates an I/O error. A True return means the save call completed, but the method documentation does not guarantee that the payload was nonempty. Selenium’s Python implementation obtains the screenshot data and then opens the destination in binary-write mode; this makes comparing bytes and file output a useful way to isolate the stage that failed. See the Selenium Chromium WebDriver API and Selenium Python implementation.

2. Read the result and narrow down the cause

In-memory PNG bytes Save result and file Likely area to investigate
Zero Any Capture/session state, navigation, or window dimensions. The issue occurs before ordinary file writing.
More than zero False or file missing Destination path, permissions, filesystem state, or an I/O error.
More than zero True, but file is empty Compare the bytes written directly with Selenium’s path and check for a subsequent truncation or replacement.
More than zero True, file has data, but image viewer rejects it Confirm the extension and inspect whether the saved data is actually a valid PNG; do not infer validity from a nonzero size alone.

This table is a diagnostic inference from the documented APIs and file-writing behavior, not a claim that each symptom has only one possible cause.

3. Verify the path and write the captured bytes directly

Give Selenium a full path whose parent directory exists and is writable by the process running the test. Use .png. The documented API recommends a full path, and Selenium’s current Python implementation warns when the filename does not end in .png.

from pathlib import Path

path = Path("/absolute/path/screenshot.png")
png = driver.get_screenshot_as_png()

if not png:
    raise RuntimeError("WebDriver returned an empty screenshot")

path.parent.mkdir(parents=True, exist_ok=True)
with path.open("wb") as screenshot_file:
    screenshot_file.write(png)

print("Wrote", len(png), "bytes to", path)

If this direct write creates a nonempty file, compare the original destination string, working directory, user permissions, and the lifetime of the file. Relative paths are resolved from the process’s current working directory, which may differ between an interactive shell, IDE, test runner, and CI job.

4. Check the live browser and viewport

Before capture, make sure the WebDriver session is still active, navigation reached the intended page, and the current window has positive dimensions. A screenshot call made after driver.quit(), against a failed navigation, or with an unexpected viewport cannot be diagnosed by changing the output filename alone.

print("Current URL:", driver.current_url)
print("Window size:", driver.get_window_size())

size = driver.get_window_size()
if size["width"] <= 0 or size["height"] <= 0:
    driver.set_window_size(1365, 900)

png = driver.get_screenshot_as_png()
print("PNG bytes after checking viewport:", len(png))

Chrome’s headless screenshot guidance uses an explicit --window-size setting. This is a useful way to make the viewport intentional and repeatable; the documentation does not say that a zero-size window is the cause of every empty screenshot. See Chrome headless documentation and Selenium’s Chrome examples.

5. Minimal complete headless Chrome example

This standalone example creates a headless Chrome session, navigates, sets a viewport, checks the captured bytes, saves a PNG, and reports its size. Install Selenium and make Chrome and a compatible driver available to your environment before running it.

from pathlib import Path
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

output = Path("/absolute/path/screenshot.png")
output.parent.mkdir(parents=True, exist_ok=True)

options = Options()
options.add_argument("--headless")
options.add_argument("--window-size=1365,900")

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://example.com")

    png = driver.get_screenshot_as_png()
    if not png:
        raise RuntimeError("Chrome returned no screenshot bytes")

    saved = driver.save_screenshot(str(output))
    if not saved:
        raise OSError(f"Selenium could not save the screenshot to {output}")

    file_size = output.stat().st_size
    if file_size == 0:
        raise RuntimeError("Screenshot file is empty after save")

    print(f"Saved {file_size} bytes to {output}")
finally:
    driver.quit()

Use Selenium’s browser setup guidance for the environment-specific Chrome and driver setup. The sources here do not establish a compatibility matrix or a version-specific fix for this symptom.

6. Common errors and fixes

Symptom Common cause What to do
save_screenshot() returns False File I/O failed, often because the directory is missing or not writable. Use an absolute path, create the parent directory, and check the process user’s write permissions.
Screenshot API raises a WebDriver/session error The session ended, Chrome exited, or the driver reference is no longer usable. Capture before quit() and inspect the earlier browser or navigation error in the logs.
Screenshot is blank or has unexpected dimensions The page or viewport state differs from what the capture step expects. Check current_url, wait for the actual page condition your application requires, and set an explicit positive viewport.
File is initially nonempty, then becomes empty or disappears Test teardown, cleanup, or another process may overwrite, truncate, or remove it. Log the file size immediately after saving and search later test steps for writes, cleanup, or reuse of the same path.
File has bytes but the image cannot be opened A nonzero byte count alone does not prove valid PNG content, or the file may have another format under a PNG suffix. Write the bytes returned by get_screenshot_as_png() unchanged to a fresh .png path; inspect how downstream code handles the file.

A fixed sleep is not a general solution for an empty file. If the page needs time to reach a particular state, wait for a condition meaningful to that page, and still check the screenshot bytes and save result.

7. Performance, reliability, and cost considerations

  • Capture only when needed. Screenshot collection adds browser work and file I/O to a test run. Avoid duplicate captures unless they help diagnose a failure.
  • Use deterministic output paths. Include a test or run identifier when parallel workers might write the same filename. This prevents one worker’s output from being mistaken for another’s.
  • Keep evidence from failures. Log the current URL, viewport dimensions, byte count, save result, and file size near the capture call. Preserve the browser log and test stage that precedes the failure.
  • Do not treat a successful boolean as proof of a good image. Check that the file exists and has bytes, and validate image content if the downstream workflow requires it.
  • Control storage deliberately. Test suites that retain screenshots can accumulate files; define retention and cleanup so cleanup does not race with consumers.
  • Cost depends on your environment. Selenium and headless Chrome run in infrastructure you provide. Account for the compute and storage used by your test or capture workers; no universal cost figure follows from the documented screenshot APIs.

Or skip the browser setup

If your goal is to capture a website rather than exercise a Selenium workflow, ScreenshotNeo is a website screenshot API and MCP server. One GET request returns a PNG, JPEG, WebP, or PDF. It can accept cookie and consent banners as a visitor and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and the response identifies the page verdict and billing status in headers. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

For a one-call PNG capture, see the ScreenshotNeo API documentation:

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

The free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan. Sign up for free and get 1,000 screenshots a month with no card.

FAQ

Does headless Chrome disable Selenium screenshots?

No. Selenium’s official browser examples and Chrome’s headless documentation both demonstrate screenshot capture. Diagnose the session and returned data rather than assuming headless mode is the cause.

Does True from save_screenshot() prove the PNG is valid?

No. It reports the outcome of the save operation. Check the in-memory byte count and resulting file, and validate the image if another tool will consume it.

Should I add a delay before every screenshot?

No universal delay is documented for this problem. Wait for a page-specific condition when needed, then inspect the capture bytes and output file.

Can I use get_screenshot_as_base64() to debug?

Yes. Selenium also exposes base64 screenshot data. The PNG-bytes method is convenient when you want to write the capture directly to a local binary file.