skip to content

BiDi Event Modules

WebDriver BiDi adds a second, socket-based channel beside classic WebDriver so the browser can push logs and network events as they happen. Interviewers ask what request/response simply cannot do.

on this pageshow

explore

questions

5

In Selenium 4, what does setting the `webSocketUrl` capability to true on a new session do?

level: juniorimportance: must knowfreq 64%

answer

  1. It is negotiated like any capability
  2. Two appearances, two different types
  3. The client is told where to connect
  4. Absent in the response means no channel
  5. Boolean out, ws:// address back

basics

~20 s

It asks the remote end to open a WebDriver BiDi socket for that session. If the remote end supports BiDi, the capabilities it returns contain webSocketUrl again, this time as the ws:// address the client connects to.

solid answer

~40 s

`webSocketUrl` is the switch that turns the BiDi channel on, and it is negotiated like any other capability in Selenium 4. The client puts `webSocketUrl: true` into the new-session request — in Java, `options.setCapability("webSocketUrl", true)`. If the remote end supports **WebDriver BiDi**, it opens a WebSocket for that session and returns `webSocketUrl` in the response capabilities, now as a `ws://` string. The client reads that string back from the session's capabilities and connects there. The type therefore changes direction: boolean going out, URL coming back. A remote end that does not support BiDi simply returns no `webSocketUrl` string, so there is no socket and nothing can be subscribed to. Because the address is returned rather than assumed, an intermediary in front of the browser can hand back an address that points at itself.

code

java · 24 lines
java
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class BookingCalendarBiDiSocket {

    public static void main(String[] args) {
        ChromeOptions options = new ChromeOptions();
        options.setCapability("webSocketUrl", true);

        ChromeDriver driver = new ChromeDriver(options);
        try {
            Capabilities caps = driver.getCapabilities();
            Object socketUrl = caps.getCapability("webSocketUrl");
            if (socketUrl == null) {
                throw new IllegalStateException("No BiDi channel for this session");
            }
            System.out.println("BiDi socket: " + socketUrl);
            driver.get("https://hotel.example.com/rooms/calendar");
        } finally {
            driver.quit();
        }
    }
}

go deeper

for a junior

Be ready to say that webSocketUrl is a capability set to true when the session is created, and that the response hands back the socket address. That request-then-read-back pair is the answer at this level.

for a middle

Explain the type change in each direction, what an absent string in the response means, and why the channel still delivers nothing until a subscribe command names the events you want.

for a senior

Show that you guard for it. Check the returned capability before wiring observation code, expect BiDi support to vary across the browser matrix, and recognise an empty capture as a missing channel rather than a quiet browser.

for a principal

Own the rollout: whether every session in the suite requests the channel or only some, what an absent channel means for the run's evidence policy, and how you keep the observation path from becoming a source of run failures.

## A capability, not a separate connection setting In Selenium 4 the BiDi channel is switched on the same way everything else about a session is: through the **capabilities** of the new-session request. The client sets `webSocketUrl` to boolean `true`. Nothing else about starting the browser changes — you still build `ChromeOptions` or `FirefoxOptions`, still pass them to the driver, and still drive the page through the ordinary WebDriver HTTP commands afterwards. What the flag asks for is a second channel attached to that one session: a **WebSocket** over which the browser can push messages the client never requested. ## The type changes direction This is the detail interviewers actually probe, because it is easy to half-remember: | Direction | Member | Value | |---|---|---| | New-session **request** | `webSocketUrl` | boolean `true` — "I would like a BiDi socket" | | New-session **response** | `webSocketUrl` | a string such as `ws://localhost:9515/session/<id>` — "here it is" | So `webSocketUrl` appears twice with two different types. The request is a wish; the response is the address. A client that sends the boolean and then guesses the URL has misunderstood the handshake. ## What happens step by step 1. Build the browser options for a hotel room-booking calendar run and set `webSocketUrl` to `true`. 2. Start the driver; Selenium sends the new-session command with those capabilities. 3. The remote end, if it implements BiDi, opens a socket for the session and includes the `ws://` address in the capabilities it returns. 4. The client reads that string back out of the session's capabilities. 5. The client connects to it and sends `session.subscribe` before expecting any event. 6. The test drives the calendar normally — click the next-month control, wait for the rate grid — while pushed frames arrive on the socket. ## It sits beside the other capabilities, not above them `webSocketUrl` is one member of the same capability map that carries everything else about the session, and it is orthogonal to all of it: - It does not influence which browser you get; `browserName` and `browserVersion` still decide that. - It does not conflict with the vendor options blocks in the same map, so a booking-calendar run can request the socket and still pass browser arguments in the usual way. - It is matched like any other capability, so a remote end that cannot provide it does not have to fail — it simply does not return the string. ## When the capability comes back missing A remote end that does not implement BiDi does not fail the session; it simply does not return a `webSocketUrl` string. That is a quiet outcome, and it is worth handling deliberately: - Check the returned capabilities rather than assuming the socket exists. An absent string means there is no channel to connect to, so any subscription code should be skipped rather than left to fail later. - BiDi support differs by browser and by browser version, and it moves release to release, so verify it on the browsers your suite actually runs rather than assuming parity across the matrix. - The failure mode people misread is a **silent absence of events** — the calendar test still passes or fails on its own assertions, and the capture is empty for a reason that has nothing to do with the page. ## Why the address is returned rather than fixed Because the socket address arrives in the response, it does not have to point at the machine the browser runs on. Something standing between the client and the browser can return an address that points at itself and relay the traffic. That is the same indirection the classic HTTP endpoints already rely on, and it is why the client is told where to connect instead of constructing the URL from a host and a port it guessed. ## What the capability does not do Three further boundaries keep the mental model clean: - It does **not** move your existing commands onto the socket. `driver.get(...)`, element lookup and clicks still travel over the classic WebDriver HTTP endpoints. - It does **not** start any event flowing. The socket is silent until `session.subscribe` names events or modules, and nothing from before that call is replayed. - It does **not** survive the session. End the session and the socket goes with it. ## The one-sentence version **`webSocketUrl: true` is a request for a BiDi socket, and the string of the same name in the response capabilities is that socket's address** — request a channel, read back where it lives, connect, subscribe.

  • You requested `webSocketUrl` but the returned capabilities have no such string. What does that mean?
    That the remote end did not honour the request, so no BiDi channel exists for this session. It is not an error — session creation succeeded and the calendar test will run normally over the classic HTTP endpoints — but there is nothing to connect to and no subscription can be made. Treat the check as a guard: skip the observation code and report the missing channel, rather than letting a connection attempt fail later with a confusing message.
  • Once the socket is open, does anything about your existing calendar test code change?
    No. `webSocketUrl` adds a channel; it does not migrate the commands you already send. Navigation, element lookup, clicks and waits still travel over the classic WebDriver HTTP endpoints on the same session. What changes is that a second piece of code connects to the socket, subscribes to events and reads pushed frames concurrently with the test's own steps.
  • Why is the socket address returned by the remote end instead of built by the client?
    Because the browser may not be where the client thinks it is. Returning the address lets something standing between the client and the browser hand back an address pointing at itself and relay the traffic, which is the same indirection the classic HTTP endpoints already allow. A client that constructed the URL from a guessed host and port would break the moment the browser stopped being local.

saying these in an interview costs you the question

  • Guessing the socket URL instead of reading the returned capability
  • Expecting webSocketUrl to be a string in the request
  • Thinking the missing capability makes session creation fail
  • Assuming events flow the moment the socket connects
  • Believing the flag moves ordinary commands onto the socket
open as a page

In Selenium 4's WebDriver BiDi, what do event names like `log.entryAdded` and `network.beforeRequestSent` tell you?

level: juniorimportance: should knowfreq 38%

basics

~20 s

Every BiDi name is module dot member. The prefix names the module that owns it, so log owns entryAdded and network owns beforeRequestSent. The same prefixes cover commands, which is how the protocol is organised.

open as a page

Why can't classic WebDriver's HTTP contract in Selenium report a console error at the moment it happens?

level: juniorimportance: should knowfreq 51%

basics

~10 s

Classic WebDriver is client-initiated request and response: the remote end only answers, never speaks first. A browser event can only be asked for afterwards, which is why Selenium 4 adds the BiDi socket.

open as a page

In Selenium 4's WebDriver BiDi, why does a freshly opened socket deliver no events until `session.subscribe` is sent?

level: middleimportance: should knowfreq 48%

basics

~10 s

WebDriver BiDi is subscription-based. Connecting to the socket only establishes the channel; the remote end pushes nothing until the client sends session.subscribe naming the events or modules it wants.

open as a page

In Selenium 4, why does a cross-browser hotel booking-calendar suite prefer WebDriver BiDi to the Chromium-only DevTools bridge?

level: seniorimportance: should knowfreq 42%

basics

~10 s

WebDriver BiDi is a W3C-specified channel that Chromium browsers and Firefox both speak, so one subscription covers the whole matrix. The DevTools bridge is Chromium-only and pinned to browser versions.

open as a page