Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Take the screenshot in your test framework’s failure hook while the WebDriver session is still alive, save it as a uniquely named PNG, and publish that file with the CI report. If the test throws an exception, capture first and then re-raise the original exception so the screenshot never hides the real failure.
The reliable sequence
A Selenium screenshot is a capture of the browser’s current window. It does not require external screen-recording software or capture hardware. The critical order is:
- Run the test until the assertion or exception occurs.
- In the framework’s failure callback, listener, rule, extension, or teardown finalizer, call the WebDriver screenshot method.
- Write a deterministic PNG filename containing the test or scenario name plus a UTC timestamp or retry index.
- Attach or publish the resulting file as a CI artifact.
- Preserve and report the original assertion or exception even if screenshot writing fails.
- Only after the hook has run, quit and discard the driver.
Calling driver.quit() first leaves no browser session from which to capture the failed state.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchChoose a file or an in-memory attachment
| Method | Result | Use it when | Failure signal |
|---|---|---|---|
save_screenshot(path) |
Writes a PNG file and returns a Boolean | Your CI system collects files from an artifacts directory | False indicates file I/O failure |
get_screenshot_as_file(path) |
Writes a PNG file and returns a Boolean | You prefer the alternate Selenium file API | False indicates file I/O failure |
get_screenshot_as_png() |
Returns binary PNG bytes | Your report library accepts byte attachments directly | Handle the driver exception in your failure hook |
get_screenshot_as_base64() |
Returns a Base64-encoded screenshot | You embed the image in an HTML report | Handle the driver exception in your failure hook |
The file APIs are intended for PNG output. Selenium warns when a filename does not end in .png; use that extension even when your test name contains another suffix.
#1 Best Overall
Python: a failure-safe screenshot helper
The following helper works with Selenium’s Python bindings. It creates the destination directory, uses a UTC timestamp to avoid collisions, and treats a failed write as a secondary diagnostic rather than replacing the test error.
from pathlib import Path
from datetime import datetime, timezone
def capture_failure(driver, test_name: str, output_dir: str = "artifacts") -> Path | None:
out = Path(output_dir)
out.mkdir(parents=True, exist_ok=True)
stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
path = out / f"{test_name}-{stamp}.png"
try:
ok = driver.save_screenshot(str(path))
return path if ok else None
except Exception:
return None
This annotation uses the union syntax available in Python 3.10 and later. If your project supports an older Python version, replace it with Optional[Path] and import Optional from typing.
Capture inside an exception boundary
For a small test runner or a custom harness, put the helper directly around the test body. The bare raise keeps the original traceback as the primary failure.
Recommended Free Tools
def run_case(driver, test_name, test_body):
try:
test_body()
except Exception as original_error:
image = capture_failure(driver, test_name)
if image is None:
print(f"Screenshot capture failed for {test_name}")
raise
Do not write code that raises a new “screenshot failed” exception from this block. Log that condition separately, then let the assertion or browser error determine the test result.
Use the framework’s failure callback
In a full test suite, the preferred integration point is the framework callback that receives the failed test or scenario. Pass the still-active driver and a stable identifier such as the test node ID. Frameworks differ in naming, but the logic is the same:
Rank #2
def on_test_failure(driver, test_identifier, original_exception):
image_path = capture_failure(driver, test_identifier)
if image_path:
publish_to_report(image_path) # framework-specific
else:
log_capture_failure(test_identifier)
raise original_exception
When your framework supplies a retry number, include it in the filename. Otherwise, a UTC timestamp prevents two attempts from overwriting one another. Sanitize identifiers before using them as path components if names can contain slashes, backslashes, or operating-system reserved characters.
Attaching bytes or Base64 to a report
File artifacts are simplest for CI, but an HTML or test-reporting library may accept memory objects. In that case, call get_screenshot_as_png() and attach the returned bytes with the report’s PNG MIME type. For an HTML template that expects a data URL, call get_screenshot_as_base64() and prepend the appropriate image prefix required by that template.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteTake the in-memory capture in the same failure callback as the file capture. A report attachment does not make a closed or discarded WebDriver session usable again.
Java and Selenide projects
If your suite is written in Java, install the equivalent listener, rule, extension, or teardown-finalizer supplied by your test framework and request the screenshot before the driver is closed. Keep the test identifier and retry index in the output name, check the API’s success result where available, and leave the original assertion as the reported failure.
Projects that already use Selenide can use its built-in failure handling: Selenide takes screenshots automatically on every failed test, stores them in a configurable reports folder, and provides JUnit and TestNG listener or rule integrations. A raw Selenium project does not receive that behavior automatically; implement the equivalent listener or extension yourself.
Rank #3
Make screenshots useful in CI
Use deterministic, collision-resistant names
- Include the test or scenario identifier.
- Add a UTC timestamp such as
20260929T142530Z, or include the retry number. - Keep the final extension as
.png. - Write all captures beneath one known directory, for example
artifacts/.
Publish the directory
Configure your CI job to upload the artifact directory even when the test command exits non-zero. Most CI systems skip later steps after a failure unless an “always run” or equivalent condition is set. Uploading only on success is a common reason teams cannot find the screenshot of the failure they need.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Keep the original failure visible
A screenshot can show the state at the point of failure, but it is not a substitute for the assertion message, stack trace, browser logs, or network diagnostics. Record capture errors as secondary log lines. This separation lets a permissions problem in the artifacts directory remain distinct from the failed test.
Common problems and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| The file is missing and the test still fails | The destination directory does not exist or is not writable | Create it with Path.mkdir(parents=True, exist_ok=True); check the CI workspace permissions; inspect the Boolean return. |
| The screenshot hook reports success but no artifact appears | The CI job does not upload artifacts after a failed step | Configure artifact publication to run on failure and point it at the exact output directory. |
| Every retry overwrites the previous image | The filename contains only the test name | Add a retry index or UTC timestamp. |
| Selenium warns about the filename | The path does not end in .png |
Use a PNG extension for the file APIs. |
| The hook raises a second exception | Capture errors are allowed to replace the assertion | Catch and log capture errors, then re-raise the original test exception. |
| The hook says the driver is unavailable | A teardown step or fixture already quit the driver | Move capture into the failure callback before driver disposal; do not rely on a later global teardown. |
| The image shows an earlier page | The failure occurred before navigation or the browser was redirected | Capture at the failure point and include the test’s URL, assertion message, and logs alongside the image. |
| A blank or partial PNG is produced | The browser session ended during a crash or timeout | Keep the capture attempt best-effort, preserve the original timeout or crash error, and retain other CI diagnostics. |
Performance, reliability, and retention
A screenshot is an additional browser command and file operation on the failure path. Restricting capture to failed tests avoids slowing every successful case. If a suite can fail in parallel, use per-worker subdirectories or globally unique names. For large suites, define a retention policy in CI so historical images do not consume unlimited artifact storage.
Capture exactly once per failed attempt unless your debugging policy requires more. A single image taken after the assertion generally gives a clearer signal than several captures scattered through teardown. If the browser is already unresponsive, the screenshot call may fail; the helper must therefore remain non-fatal.
Or skip the browser setup
When you need a clean snapshot of a URL rather than the exact in-memory state of a failed WebDriver session, ScreenshotNeo provides a one-request screenshot API. It is complementary to Selenium: Selenium captures the live test browser, while ScreenshotNeo loads a URL independently.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Rank #4
Before capture, ScreenshotNeo accepts the cookie or consent banner like 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.
The API supports PNG, JPEG, WebP, and PDF output. Options include full-page capture with lazy images loaded, CSS-selector element capture, dark mode, 12 device presets or any viewport, retina scale, PDF paper size/margins/landscape/page ranges, HTML/CSS-to-image, custom JavaScript, click-before-capture, hidden selectors, waits for a selector/delay/network idle, blocking ads/trackers/requests/resource types, custom headers/cookies/user agent/Authorization, timezone and geolocation, transparent backgrounds, resizing, cache TTL, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. Existing parameter names used by other screenshot APIs also work, easing migration. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.
See the ScreenshotNeo API documentation for request options.
cURL
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}`);
ScreenshotNeo includes every feature on every plan. The current plans are:
| Plan | Price | Included shots |
|---|---|---|
| Free | $0 | 1,000 per month; no card |
| Starter | $5 | 3,000 |
| Growth | $15 | 15,000 |
| Pro | $39 | 60,000 |
| Scale | $99 | 250,000 |
| Business | $249 | 1,000,000 |
Yearly billing provides two months free. You can sign up for 1,000 free screenshots a month with no card and use the API or MCP server when a URL-level capture is the right diagnostic.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.FAQ
Can ScreenshotNeo reproduce the exact DOM state from a failed Selenium test?
Not automatically. It loads the URL in its own capture session. To reproduce protected content, provide the necessary headers, cookies, user agent, or Authorization values supported by the API; browser memory, unsaved form data, and JavaScript state from Selenium are not transferred by the URL alone.
Best Value
When is Base64 preferable to a PNG artifact?
Use Base64 when the report renderer expects an embeddable string and you want the image displayed inline. Use binary PNG bytes for report APIs that accept byte attachments, or a file when your CI system archives directories.
What should remain the primary CI failure?
The assertion, timeout, or browser exception that caused the test to fail. Screenshot capture is diagnostic evidence; a write error must be logged separately rather than replacing that original result.
Frequently Asked Questions
Can ScreenshotNeo reproduce the exact DOM state from a failed Selenium test?
Not automatically. It loads the URL in its own capture session. Headers, cookies, user-agent, or Authorization values can be supplied when needed, but Selenium’s in-memory form data and JavaScript state are not transferred by a URL alone.
When is Base64 preferable to a PNG artifact?
Use Base64 when your report renderer expects an inline image string; use binary PNG bytes for byte-attachment APIs or a file for CI artifact archives.
What should remain the primary CI failure?
The original assertion, timeout, or browser exception. Screenshot errors should be logged separately.
Quick Recap
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.

