ScreenshotNeo

BlogHow-to

Save Screenshots During Selenium Tests

Capture Selenium screenshots on demand or only when tests fail, save them safely, and preserve useful evidence in CI.

By the ScreenshotNeo team1 October 20267 min read

Direct answer: In Python Selenium, call driver.save_screenshot("path/to/screenshot.png") to save the current browser window as a PNG. The method returns True when the file write succeeds and False after an I/O error, so check the result. Create the destination directory first and keep the WebDriver session open until failure evidence has been captured.

Minimal Python example

from pathlib import Path
from selenium import webdriver

output_dir = Path("artifacts/screenshots")
output_dir.mkdir(parents=True, exist_ok=True)

with webdriver.Chrome() as driver:
    driver.get("https://example.com")
    saved = driver.save_screenshot(str(output_dir / "example-page.png"))
    if not saved:
        raise OSError("Selenium could not save the screenshot")

save_screenshot writes a PNG file and returns a Boolean. Selenium’s Python WebDriver API documents the call as saving the current window to a PNG image file. Use a full path and a filename ending in .png. See the Selenium Python WebDriver API.

Choose the screenshot type

Need API Result
Evidence for the whole visible browser window driver.save_screenshot(path) PNG file and Boolean success value
Same file operation through the alternate API driver.get_screenshot_as_file(path) PNG file and Boolean success value
One DOM element element.screenshot(path) PNG file for that element and Boolean success value
Process the image in Python driver.get_screenshot_as_png() PNG bytes
Embed the image in HTML or send text over an API driver.get_screenshot_as_base64() Base64-encoded image string

The whole-window method is useful when context spans several regions. An element screenshot keeps evidence focused on a control or component. Selenium’s WebElement API documents element screenshots as PNG files.

Save a specific element

from pathlib import Path
from selenium import webdriver
from selenium.webdriver.common.by import By

output_dir = Path("artifacts/screenshots")
output_dir.mkdir(parents=True, exist_ok=True)

with webdriver.Chrome() as driver:
    driver.get("https://example.com")
    heading = driver.find_element(By.CSS_SELECTOR, "h1")
    saved = heading.screenshot(str(output_dir / "heading.png"))
    if not saved:
        raise OSError("Selenium could not save the element screenshot")

Locate the element after the page has reached the state you want to document. If the selector matches nothing, Selenium raises a lookup exception before the screenshot call.

Keep the image in memory

from selenium import webdriver
from pathlib import Path

with webdriver.Chrome() as driver:
    driver.get("https://example.com")
    png_bytes = driver.get_screenshot_as_png()
    Path("artifacts/in-memory-copy.png").write_bytes(png_bytes)

    base64_image = driver.get_screenshot_as_base64()
    html = f'test screenshot'
    Path("artifacts/report.html").write_text(html, encoding="utf-8")

Use the byte method when an uploader, report generator or image processor accepts binary data. Use Base64 when the destination expects text. These methods do not create files by themselves.

Capture only when a test fails

Capturing every step can create many artifacts. A common design is to capture the current window in failure handling, while the driver is still alive, and give each file a unique name.

from datetime import datetime, timezone
from pathlib import Path
from selenium import webdriver


def capture_failure(driver, test_name: str) -> Path:
    directory = Path("artifacts/screenshots")
    directory.mkdir(parents=True, exist_ok=True)
    stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
    safe_name = "".join(c if c.isalnum() or c in "._-" else "_" for c in test_name)
    path = directory / f"{safe_name}-{stamp}.png"
    if not driver.save_screenshot(str(path)):
        raise OSError(f"Could not save screenshot to {path}")
    return path


driver = webdriver.Chrome()
try:
    driver.get("https://example.com")
    # test steps go here
except Exception:
    capture_failure(driver, "homepage_test")
    raise
finally:
    driver.quit()

The naming scheme and failure hook are framework and CI choices, not Selenium guarantees. With pytest, unittest, or another runner, call the same helper from that framework’s failure lifecycle. Configure the runner or CI system separately to retain the directory as an artifact.

Make captures useful and repeatable

Set the viewport deliberately

driver.set_window_size(1440, 900)

Selenium documents window dimensions in pixels. A fixed size helps control framing, but identical pixels are not guaranteed across browsers, operating systems, fonts, device scale factors or headless environments.

Wait for the state you want to prove

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

wait = WebDriverWait(driver, 10)
wait.until(lambda d: d.find_element(By.CSS_SELECTOR, "[data-loaded='true']"))
driver.save_screenshot("artifacts/screenshots/loaded.png")

Prefer an explicit condition tied to the page state over an arbitrary sleep. If the screenshot is evidence of a failed action, capture immediately after the assertion or exception while the relevant page remains visible.

Use unique paths

  • Include the test name, browser or viewport, and a timestamp or run identifier.
  • Create directories before the call.
  • Do not let parallel tests write the same filename.
  • Use PNG for the Selenium file APIs documented here.

CI and remote-driver considerations

A screenshot path belongs to the machine where the WebDriver client writes the file. In a remote or containerized run, that may be a temporary worker rather than your laptop. Upload or copy the artifact before the job ends, and make sure the failure hook runs before teardown closes the driver. If teardown has already closed the session, the driver-bound screenshot API cannot obtain another image.

Keep artifact retention aligned with your debugging needs. Store only failure captures when disk usage matters, and avoid overwriting files from concurrent jobs. These retention and upload policies are CI-specific implementation choices.

Common errors and fixes

Symptom Cause Fix
save_screenshot returns False Python encountered an I/O error while opening or writing the path. Create the directory, use a writable full path, check available space, and fail the test instead of ignoring the Boolean.
File is missing after a passing test The path was relative to an unexpected working directory or the artifact was not retained by CI. Log the resolved path, prefer an absolute path, and configure CI artifact upload.
FileNotFoundError or similar directory error The parent directory does not exist. Call Path(path).parent.mkdir(parents=True, exist_ok=True) before saving.
NoSuchElementException for an element capture The selector did not match at capture time. Wait for the element, verify the selector, and capture the whole window if the element is intentionally absent.
Screenshot shows an old or incomplete state The capture ran before the relevant navigation, animation or data load finished. Wait for a specific condition or selector and capture after the state transition.
No image after a failure Failure handling ran after driver.quit() or the session crashed. Capture in the exception or test-failure hook before teardown; preserve the original exception if capture itself fails.
Different pixels between runs Viewport, browser, OS, fonts, device scale or dynamic content changed. Control the window size and environment, and treat pixel identity as an aim rather than a Selenium guarantee.

Performance, reliability and cost

  • Performance: A screenshot adds image encoding and file I/O to the test. Capture on failure when routine runs do not need visual evidence; capture checkpoints when the image is part of the test result.
  • Reliability: Check the Boolean return value, keep the session alive, use unique writable paths, and verify that CI preserves the directory.
  • Storage: PNG files can accumulate quickly in long suites. Limit routine captures, compress or retain only selected artifacts according to your CI policy.
  • Cost: Selenium itself does not define a screenshot charge. Any cost comes from the machines, storage and CI retention you choose.

Or skip the browser setup

If you need a clean image of a URL rather than evidence tied to an existing Selenium session, ScreenshotNeo provides a single HTTP request. Its API accepts the URL and returns PNG, JPEG, WebP or PDF output.

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}`);

See the ScreenshotNeo API documentation for request options. Before capture, cookie and consent banners, newsletter popups and chat widgets can be removed. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers report the page verdict and billing status. ScreenshotNeo also provides an MCP server so Claude, Cursor and other MCP clients can take screenshots, plus full-page capture, element selectors, custom CSS and JavaScript, waits, device presets, cookies, headers, geolocation, PDF output and other options.

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Does Selenium save JPEG or WebP with save_screenshot?

The Python file-saving APIs documented here save PNG files. Use the returned PNG bytes with an image library if another format is required.

Can I take a screenshot after quitting the driver?

No. The screenshot methods belong to the active WebDriver session, so capture before quit().

Should every test step create an image?

Only when that evidence is useful. Failure-only capture reduces artifacts; selected checkpoints help diagnose state transitions.

What does a False result mean?

The file operation encountered an I/O error. Treat it as a failed artifact operation and inspect the path, permissions and available storage.

Is a Selenium screenshot a full-page capture?

The standard window call captures the current browser window. Full-page behavior depends on browser and driver capabilities; use an element or a dedicated capture service when you need a page-length image.