Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesSome links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
There are three different things “a Selenium listener before page unload” can mean: run JavaScript inside the page as it unloads, receive a lifecycle event in your test code, or handle a beforeunload confirmation. They require different approaches. Install page-side handlers while the document is still active; subscribe to WebDriver BiDi events before triggering navigation or closing a context; and configure prompt handling when a confirmation is the actual target. None of these makes beforeunload a guaranteed signal that a browser session has ended.
Choose the signal you actually need
| Goal | Approach | Important limitation |
|---|---|---|
| Run code inside the current page when it receives a page event | Register a JavaScript event handler in that document | It must be registered before the event. Navigation replaces the document’s execution context. |
| Notify the test process about navigation or context lifecycle | Subscribe to the relevant WebDriver BiDi event | Connect and subscribe before triggering the action; event availability varies by binding and browser. |
Accept, dismiss, or otherwise handle a beforeunload dialog |
Configure WebDriver’s unhandled-prompt behavior or use the relevant BiDi prompt handling | Recent drivers automatically dismiss beforeunload prompts by default, according to Selenium’s alerts documentation. |
First decide where the callback must run. A JavaScript handler in the page is not a notification subscription in the test client, and neither is the same thing as the browser’s confirmation dialog.
Run JavaScript in the page before it unloads
If the page itself needs to react to an event, register the listener in the page’s current execution context. In Python, Selenium’s execute_script runs the supplied script in the currently selected page:
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →from selenium import webdriver
# Create and navigate the driver using your normal browser setup.
driver = webdriver.Chrome()
driver.get("https://example.com")
driver.execute_script("""
window.addEventListener("beforeunload", function (event) {
// Page-side work only. Do not rely on an asynchronous request completing here.
console.log("The current document is preparing to unload");
});
""")
# A later action may trigger navigation and replace this document.
driver.get("https://example.org")
This demonstrates registration timing, not guaranteed delivery. The listener belongs to the document in which it was registered. If the test navigates away before executing the registration script, the old page cannot be instrumented afterward. Once the document is replaced, its JavaScript context and handlers are gone.
#1 Best Overall
Use beforeunload only for the page behavior it supports
Browsers do not guarantee beforeunload as a universal exit callback. Chrome for Developers cautions: “Never add a beforeunload listener unconditionally or use it as an end-of-session signal.” Its Page Lifecycle API guidance notes that the event may not fire when a page enters the back/forward cache, and some browsers require prior user interaction before allowing it to fire.
For a page you control, add a beforeunload handler only while unsaved work exists, and remove it when that work is saved. For test automation, do not make cleanup, persistence, or end-of-session accounting depend on this callback running. A callback also is not a good place to assume asynchronous network work will finish before the page is discarded.
Install at document startup only when necessary
A script run with execute_script is too late if the page event can occur before your test reaches that command. WebDriver BiDi bootstrap scripts are intended to run in newly created script contexts before other scripts. However, the W3C bootstrap-scripts document is a proposal, not proof that a particular Selenium binding and browser expose a stable, supported production API. Verify support for your exact combination before relying on it.
Rank #2
Receive lifecycle events in the test process with WebDriver BiDi
Traditional WebDriver is primarily a request/response protocol. Selenium describes WebDriver BiDi as a bidirectional protocol that adds a WebSocket event stream, allowing a client to subscribe to browser events. Selenium documents enabling the WebSocket connection with the webSocketUrl capability; the setup and subscription syntax depend on the language binding. See Selenium’s WebDriver BiDi documentation.
The essential ordering is: create a BiDi-enabled session, connect and register the event handler, and only then trigger navigation or context closure. Subscribing after the action can miss the event you wanted to observe.
Python event coverage and version checks
Selenium’s Python BiDi browsing-context API documents handlers for events including navigation_started, navigation_committed, navigation_failed, context_destroyed, and user_prompt_opened. The API reference identifies Selenium 4.43.0, but that documentation marker does not establish identical support across all drivers and browsers. Check the current API for your installed binding and browser: Selenium Python BiDi browsing-context API.
Rank #3
Use the event that matches your question. A navigation-started notification means navigation began; a committed event represents a different stage; a failed event reports a failure; context destruction is about a browsing context. Do not treat any one of these as a universal “the browser has exited” event. The exact supported event set and method names can differ by binding and release, so use the API reference for the language you actually run rather than copying an assumed cross-language method signature.
Free tools Windows power users keep installed
One-click scans. No signup required.
Subscribe before initiating the action
- Confirm support. Check the Selenium documentation and API reference for your language binding, driver, and browser version. BiDi is not simply an interchangeable name for legacy Chrome DevTools Protocol commands.
- Enable the WebSocket connection. Configure the session to request the
webSocketUrlcapability using the syntax documented for your binding. - Register the handler. Subscribe to a browsing-context event before the action. Keep the handler’s work short and pass data back to the test’s synchronization mechanism if needed.
- Trigger navigation or closure. Perform the action only after the subscription is active.
- Assert the specific event and outcome. Allow for the actual event sequence and failures your test expects; do not infer session termination merely from a navigation notification.
Because the supplied official API material does not establish one subscription-call signature for every Selenium binding, a purported single code sample would risk presenting a binding-specific API as universal. Use the documented handler-registration API for your installed language and version.
Handle a beforeunload confirmation prompt
If the test is failing because the browser displays a confirmation prompt, the goal is prompt handling, not attaching a JavaScript listener. Selenium’s alerts documentation says recent drivers automatically dismiss beforeunload prompts by default and points to unhandledPromptBehavior for the behavior. Set the policy explicitly when the test depends on acceptance or dismissal, using the capability syntax supported by your binding and driver.
Rank #4
WebDriver BiDi also has prompt-handling support: Selenium’s Python session API documents a user-prompt handler with a before_unload setting that can accept, dismiss, or ignore prompts. Consult the Selenium Python BiDi session API for the installed API’s exact call shape.
For BiDi context closure, the protocol’s browsingContext.close command includes a promptUnload option. MDN documents false as closing without running beforeunload handlers and true as requesting them; the prompt is handled according to the session’s unhandled-prompt behavior. Verify that your Selenium binding exposes this command before building a test around it: MDN’s browsingContext.close reference.
Troubleshoot missed listeners and unexpected prompts
- The page callback never ran. Check that the script registered the handler in the intended document before navigation. A handler cannot observe an event that already happened, and it does not survive replacement of its document.
- The callback ran in the page, but the test did not receive anything. A page-side DOM listener does not stream events to Selenium. Subscribe to a supported BiDi event if the test process needs the notification.
- The BiDi handler missed navigation. Check ordering: establish the connection and register the subscription before calling the navigation or close action. Also verify the event name and support in the installed binding’s API documentation.
- The browser closed or continued without the expected dialog. Recent Selenium drivers dismiss
beforeunloadprompts automatically by default. Configure the needed prompt policy explicitly and verify the driver exposes the option you intend to use. - A prompt appears only on some runs. Browser lifecycle behavior is conditional; user interaction, back/forward-cache behavior, browser, and the action being tested can matter. Avoid treating prompt appearance as a guaranteed result.
- A startup-injected script is unavailable. Do not assume the W3C bootstrap proposal is implemented in your browser/binding combination. Check current implementation documentation or use a different observable event supported by that combination.
- The test reports a lifecycle event but not a full browser exit. Navigation and browsing-context destruction are scoped events, not proof that every exit path has occurred. Define the specific state your test needs and observe that state directly.
Performance, reliability, and cost considerations
Keep event handlers lightweight: log or record the event and let the test process perform substantial work. Avoid making page unload a dependency for flushing data or completing requests. For test reliability, prefer explicit synchronization around the event or resulting state, and distinguish a navigation beginning from a commit, failure, or context destruction.
Best Value
BiDi support is binding- and browser-dependent, so feature-checking has a maintenance cost. The official Python API documentation identifies Selenium 4.43.0, while the alerts page reports a last-modified date of September 16, 2026; neither date guarantees uniform behavior on every browser/driver pairing. Pin and verify the versions your suite uses, and consult their current documentation when upgrading.
Or skip the browser setup
If the practical goal is to capture a page rather than test its unload lifecycle, ScreenshotNeo offers a website screenshot API and MCP server. It does not attach a Selenium listener or detect an unload event; it is an alternative for capturing a URL as an image or PDF.
One GET request returns a screenshot. For example, in Python:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
See the ScreenshotNeo documentation for request options and response details. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month with no card.
Frequently Asked Questions
Can Selenium reliably detect that a user closed the browser with `beforeunload`?
No. Page lifecycle behavior varies, and `beforeunload` is not a guaranteed end-of-session signal. Use a specific supported BiDi event only when it matches the state you need to observe.
Does WebDriver BiDi replace Chrome DevTools Protocol?
Selenium describes BiDi as the cross-browser replacement for CDP, but check support for the particular event and command in your binding and browser.
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.

