How to Use Java Event Listeners in Selenium
Learn how to register Selenium Java event listeners with EventFiringDecorator, choose callbacks, handle exceptions, and update legacy code.
Use Selenium’s WebDriverListener with EventFiringDecorator. Create the listener, decorate the original driver, then make the browser calls through the returned driver. That wrapper forwards matching WebDriver, WebElement, and alert calls to listener callbacks.
Register a listener
This example uses the current Selenium Java API. It logs navigation before it happens and a click after it succeeds:
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.events.EventFiringDecorator;
import org.openqa.selenium.support.events.WebDriverListener;
public class ListenerExample {
public static void main(String[] args) {
WebDriver original = new FirefoxDriver();
WebDriverListener listener = new WebDriverListener() {
@Override
public void beforeGet(WebDriver driver, String url) {
System.out.println("Opening: " + url);
}
@Override
public void afterClick(WebElement element) {
System.out.println("Clicked an element");
}
};
WebDriver driver = new EventFiringDecorator(listener).decorate(original);
try {
driver.get("https://www.selenium.dev/");
} finally {
driver.quit();
}
}
}
Use the imports and classes from your installed Selenium version. The API reference documents EventFiringDecorator and WebDriverListener.
Choose callback scope
Implement specific callbacks when you only need a few events, such as beforeClick, afterNavigateTo, or afterGetText. Use generic callbacks such as beforeAnyCall, beforeAnyWebDriverCall, or beforeAnyWebElementCall when you want broader instrumentation. The listener interface provides default implementations, so you only need to override the callbacks you need.
When generic and specific callbacks are both present, before callbacks run from generic to specific; after callbacks run in reverse. Keep handlers small: they run on the same thread as the WebDriver operation, and blocking there delays the browser call.
Use the decorated driver consistently
decorate(original) returns a wrapper that implements the same interfaces as the original driver. Store and use that returned reference for every interaction you want observed, including calls on elements obtained from it. Calls made through a separate reference to the original driver bypass the wrapper and its events.
Decorate once for a driver session. If you need to observe events in a test framework, construct the decorated driver at the point where that framework creates the driver and pass the wrapper into the test code.
Handle callback exceptions deliberately
By default, exceptions thrown by listener code are suppressed. This can keep logging failures from interrupting browser automation, but it can also hide a broken listener. If listener failures must fail the operation, override throwsExceptions() to return true:
WebDriverListener listener = new WebDriverListener() {
@Override
public boolean throwsExceptions() {
return true;
}
@Override
public void beforeGet(WebDriver driver, String url) {
if (url == null || url.isBlank()) {
throw new IllegalArgumentException("URL is required");
}
}
};
Choose this behavior based on the purpose of the callback. Diagnostic logging is often best-effort; validation or required auditing may need failures surfaced. See the listener API documentation for exception behavior.
Update older event-listener code
Older examples may use AbstractEventListener, EventFiringWebDriver, or WebDriverEventListener. Selenium’s migration guidance says these classes were removed. Replace that registration approach with WebDriverListener and EventFiringDecorator, then update code to use the decorated driver returned by decorate. The Selenium migration article shows the transition.
When to use a custom decorator instead
Listeners are for observing calls and adding limited side effects such as logging. They are not intended to prevent decorated methods from running or generally alter method parameters and results. If you need to change driver behavior, use Selenium’s WebDriverDecorator extension point instead. See the EventFiringDecorator documentation for this boundary.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| No callback fires | Interactions use the original driver reference instead of the decorated one. | Keep the result of decorate(original) and use it for navigation, lookup, and element actions. |
| Old listener imports do not compile | The code follows the removed event classes in an older example. | Move to WebDriverListener and EventFiringDecorator; consult Selenium’s migration guidance. |
| Listener errors do not fail the test | Listener exceptions are suppressed by default. | Override throwsExceptions() to return true if propagation is required. |
| Automation becomes slower or appears stuck | A callback is doing blocking work on the WebDriver call’s thread. | Keep callbacks quick; send heavier work to a separate mechanism without waiting in the callback. |
| Too many logs are produced | A generic callback observes a wide range of calls. | Use specific callbacks or filter what the handler records. |
| Callback signature is not found | The override signature may not match the Selenium API version on the classpath. | Inspect the installed version’s Java API documentation and use the matching callback parameters. |
Performance, reliability, and cost
Each synchronous callback adds work to the operation it observes, so keep instrumentation concise and avoid network calls, long file operations, or waits inside callbacks. Generic hooks can run for many methods; choose their scope carefully. Listener callbacks do not make browser operations more reliable by themselves. Keep normal WebDriver waits, cleanup, and failure handling in the test code.
The Selenium listener APIs described here are library features; the research sources identify no separate listener charge or published performance benchmark. Your practical cost comes from the browser and test infrastructure you run.
Or skip the browser setup
If your goal is to capture a page rather than instrument Selenium interactions, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns a screenshot or PDF. See the ScreenshotNeo API docs for parameters and configuration.
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}`);
Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. An MCP server lets AI agents use screenshot, page-info, and PDF tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots.
Sign up free for 1,000 screenshots a month, with no card required.
FAQ
Can a listener observe WebElement calls?
Yes. The decorator forwards events from WebDriver and derived objects such as WebElements and alerts when calls go through the decorated wrapper.
Can I combine generic and specific callbacks?
Yes. They can be implemented together; Selenium defines their before and after ordering.
Should a listener change click behavior?
No. For substantial behavior changes, Selenium documents a custom decorator as the appropriate extension point.
Where can I confirm the listener features for my version?
Check the Selenium Java API documentation matching the Selenium dependency used by your project, since APIs can change in future releases.


