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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use Selenium’s Java TakesScreenshot interface to save a screenshot, and attach a WebDriverListener with EventFiringDecorator to capture after navigations issued through the decorated driver. For reliable results, wait for a page-specific ready condition before saving: Selenium’s navigation wait does not guarantee that JavaScript-driven content has settled.

What “every new page” means in Selenium

There is no single callback that automatically detects every possible visual change in a web app. A listener observes WebDriver operations made through the decorated driver. Decide which events matter before implementing capture:

  • Direct document navigation: calls such as driver.get(url) and driver.navigate().to(url).
  • Browser navigation: back, forward, and refresh operations.
  • Click- or form-triggered navigation: a link or submit action may load another document, but it is not equivalent to calling get.
  • New tabs or windows: these use a separate window context; switch to the new handle before capturing it.
  • Single-page application (SPA) routes: changing the URL with client-side routing may not create a new document or invoke a document-navigation callback.

The implementation below captures direct URL loads with a listener and shows how to add other cases deliberately. If the requirement is “capture after every test step that reaches a new state,” a test-level helper that waits and captures after each step can be more dependable than trying to infer every state change from browser events.

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.

Capture a screenshot with Selenium Java

Selenium’s TakesScreenshot interface requests a screenshot from a driver or, where supported, an element. getScreenshotAs accepts an OutputType; use OutputType.FILE when you want a temporary image file to copy into your test artifacts. Capture support and the exact screenshot extent depend on the browser driver and implementation, so verify the output on the browser you run in CI. See the Selenium TakesScreenshot Java API.

Basic capture helper

This helper requests a PNG screenshot, then copies it to a caller-chosen path. The destination should be unique for each capture so later pages do not overwrite earlier artifacts.

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;

static Path saveScreenshot(WebDriver driver, Path destination) throws IOException {
    File temporaryImage = ((TakesScreenshot) driver)
            .getScreenshotAs(OutputType.FILE);
    Files.createDirectories(destination.getParent());
    return Files.copy(temporaryImage.toPath(), destination,
            StandardCopyOption.REPLACE_EXISTING);
}

Use a destination name containing a test identifier, page identifier, or sequence number. If two captures use the same path, the later copy replaces the earlier file. This example uses Java NIO for copying and directory creation; the Selenium API returns the temporary file.

Automatically capture direct URL loads

Selenium’s Java event API provides WebDriverListener callbacks and uses EventFiringDecorator to decorate the driver. An afterGet callback is a practical hook for calls to get. The listener needs a driver reference to perform the screenshot request; the simple pattern below stores the decorated driver when it is initialized.

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

Listener and driver setup

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverListener;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.events.EventFiringDecorator;

public class ScreenshotOnGet implements WebDriverListener {
    private WebDriver decoratedDriver;
    private int captureNumber = 0;

    public WebDriver attach(WebDriver rawDriver) {
        decoratedDriver = new EventFiringDecorator<>(this).decorate(rawDriver);
        return decoratedDriver;
    }

    @Override
    public void afterGet(WebDriver driver, String url) {
        capture("get");
    }

    private void capture(String event) {
        if (decoratedDriver == null) {
            return;
        }
        captureNumber++;
        String safeEvent = event.replaceAll("[^A-Za-z0-9_-]", "_");
        Path destination = Paths.get("target", "screenshots",
                String.format("%04d-%s-%s.png", captureNumber,
                        safeEvent, Instant.now().toEpochMilli()));
        try {
            saveScreenshot(decoratedDriver, destination);
        } catch (IOException | RuntimeException e) {
            // Choose a project-appropriate policy: log, fail the test, or both.
            System.err.println("Screenshot capture failed for " + destination + ": " + e);
        }
    }

    public static void main(String[] args) {
        WebDriver rawDriver = new ChromeDriver();
        ScreenshotOnGet listener = new ScreenshotOnGet();
        WebDriver driver = listener.attach(rawDriver);
        try {
            driver.get("https://example.com");
        } finally {
            driver.quit();
        }
    }

    private static java.nio.file.Path saveScreenshot(WebDriver driver,
                                                      java.nio.file.Path destination)
            throws IOException {
        java.io.File image = ((org.openqa.selenium.TakesScreenshot) driver)
                .getScreenshotAs(org.openqa.selenium.OutputType.FILE);
        java.nio.file.Files.createDirectories(destination.getParent());
        return java.nio.file.Files.copy(image.toPath(), destination,
                java.nio.file.StandardCopyOption.REPLACE_EXISTING);
    }
}

The example demonstrates the listener pattern, not a complete project build file: use the Selenium Java version already pinned by your project and confirm the decorator/listener API against that version. The listener’s callback runs after the observed call returns, but it does not itself wait for app-specific asynchronous work. If screenshots are required only after a page is ready, the next section’s explicit-wait pattern is preferable.

Use a test-level wait when readiness matters

Selenium’s default normal page-load strategy waits for document.readyState to become complete. The eager strategy waits for interactive; none does not block for document readiness. These settings control when URL navigation returns, not whether images, API requests, animations, or client-side rendering have finished. Click and form-submit navigation do not follow the same navigation-wait behavior. Choose a condition that reflects the page under test, such as a stable heading or a result panel.

import java.time.Duration;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(15));
driver.get("https://example.com/account");
wait.until(ExpectedConditions.visibilityOfElementLocated(
        By.cssSelector("main h1")));
saveScreenshot(driver, Paths.get("target", "screenshots", "account.png"));

Replace the selector with an element or application condition that means the page is genuinely ready for your test. A fixed sleep can be useful for a known animation delay, but it is usually less robust than waiting for a meaningful condition because it may be too short on a slow run and unnecessarily long on a fast one. Selenium’s page-load strategy behavior is documented in Browser Options: pageLoadStrategy.

Extend coverage beyond get

The sample listener captures only direct get calls. The Java listener API includes callbacks for multiple WebDriver operations, but the implementation must explicitly cover the operations relevant to your tests. Review the WebDriverListener Java API for callbacks supported by the Selenium version in use.

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

Navigation methods and clicks

For navigate().to, back, forward, refresh, link clicks, or form submission, decide whether the capture should happen immediately after the command or only after a destination-specific wait. Do not assume that a generic “after” callback means the page’s content is stable. For a flow where exact readiness matters, make the action, wait for the destination condition, then invoke the screenshot helper in the test. This preserves the test’s knowledge of what it expects and avoids capturing an intermediate state.

New tabs and windows

A screenshot applies to the current browser context. When an action opens a new tab or window, compare window handles, switch to the new handle, wait for its content, then capture. Selenium documents this workflow in Working with windows and tabs.

String original = driver.getWindowHandle();
int handlesBefore = driver.getWindowHandles().size();
// Perform the action that opens a tab or window.
wait.until(d -> d.getWindowHandles().size() > handlesBefore);
for (String handle : driver.getWindowHandles()) {
    if (!handle.equals(original)) {
        driver.switchTo().window(handle);
        break;
    }
}
wait.until(ExpectedConditions.visibilityOfElementLocated(
        By.cssSelector("main")));
saveScreenshot(driver, Paths.get("target", "screenshots", "new-window.png"));

SPA route changes

Client-side route changes can update the address and page content without a new document load. If those transitions count as “new pages” for your use case, instrument the application’s route-change signal or place the wait-and-capture call in the test after the route transition. A WebDriver navigation listener alone should not be treated as a detector for every SPA state update.

Choose the capture hook for your requirement

Approach Coverage Timing control Best fit
afterGet listener Direct get calls through the decorated driver Runs after the command; no page-specific wait built in Simple capture of URL loads
Additional listener callbacks Only the WebDriver operations you implement Callback timing; readiness still needs consideration Centralized capture across selected driver actions
Test-level wait and helper Any test flow you explicitly instrument Strongest control over destination condition Deterministic artifacts tied to test expectations
Application route hook plus test helper SPA transitions when explicitly connected Can capture after the app signals a route is ready Applications where route changes are the relevant “pages”
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Extent, artifacts, and reliability

Viewport versus full page

Do not assume that a driver screenshot is a full-page capture across all browsers and drivers. Selenium’s API notes that screenshot behavior can depend on implementation and W3C conformance. Validate the desired extent in the actual browser/driver combination used locally and in CI. If you need a particular element, Selenium’s screenshot API also describes element capture where supported; confirm the implementation accepts it before relying on that output.

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

Unique filenames and failure policy

  • Include a test name, page sequence, or timestamp so repeated captures do not collide.
  • Put screenshots in a test-artifact directory that your CI system preserves when a run fails.
  • Choose whether a screenshot failure should fail the test, be logged as a secondary failure, or be recorded separately. A listener that swallows every exception can hide a broken artifact pipeline.
  • Keep the original driver available for cleanup and ensure quit() runs even if navigation or capture fails.

Performance and cost

Screenshot generation and file copying add work to every instrumented page transition. Capturing after every command can make suites slower and produce large artifact sets, particularly when repeated actions do not represent distinct pages. Limit capture to the events that answer a debugging or audit need, and use predictable retention in CI. No measured runtime or storage overhead is provided, so benchmark your own suite and artifact pipeline rather than assuming a universal cost.

Troubleshooting

No screenshot appears

  • Cause: the operation was not routed through the decorated driver, or only afterGet is implemented while navigation used another method.
  • Fix: ensure tests use the returned decorated driver and add explicit handling for the operation in question, or capture from test code after the action.

The screenshot is blank, stale, or missing dynamic content

  • Cause: the callback ran before the application reached the state you intended to record.
  • Fix: wait for a page-specific selector or app condition before calling saveScreenshot. The URL navigation completing is not proof that client-side updates have settled.

Capture fails with a cast or unsupported-operation error

  • Cause: the active driver implementation may not support TakesScreenshot or the requested screenshot form.
  • Fix: check support for the actual driver/browser and requested target, then use a supported capture method or select a compatible driver.

Captures overwrite one another

  • Cause: each capture writes to the same destination name.
  • Fix: add a sequence number, test identifier, or timestamp, and create the destination directory before copying.

A new tab is not captured

  • Cause: the driver remained focused on the original window, or the capture ran before the new handle appeared.
  • Fix: wait for the handle count to change, switch to the new handle, wait for its content, then capture.

SPA pages are skipped

  • Cause: the transition changed application state without a new document navigation.
  • Fix: add an application route hook or take the screenshot after the test’s SPA-specific readiness condition.

Or skip the browser setup

If the goal is to obtain screenshots of URLs rather than attach artifacts to a Selenium test run, ScreenshotNeo provides a screenshot API and MCP server. One GET request returns an image or PDF; the API can also handle cookie/consent banners, newsletter popups, and chat widgets before capture, and those cleanup steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, with response headers indicating the page verdict and billing status. Its MCP server provides screenshot tools for AI agents, and its free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots.

cURL example, adapted to capture the target URL:

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

See the ScreenshotNeo API documentation for request options. ScreenshotNeo is not a replacement for Selenium when the screenshot must come from a test-controlled browser state, but it can avoid browser-driver setup for URL-based captures. Learn more at ScreenshotNeo, or sign up for 1,000 free screenshots a month with no card.

Frequently Asked Questions

Can a Selenium listener automatically detect every SPA route change?

No. A client-side route change may not create a document navigation; connect capture to the application’s route signal or a test-level readiness hook.

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

Can Selenium save screenshots as files without encoding them manually?

Yes. Request OutputType.FILE with TakesScreenshot and copy the returned temporary file to your artifact path.

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.