skip to content

In Selenium 4's WebDriver protocol, how are command URLs structured around the session id?

level: middleimportance: should knowfreq 66%

answer

  1. The identifier lives in the path
  2. Everything hangs under one prefix
  3. One route creates, one route destroys
  4. No cookie, no header, no connection affinity
  5. One route needs no session at all

basics

~20 s

A POST to /session creates a session and returns its id, every later command is addressed under /session/{session id}/, and a DELETE on that path ends it. The id is a path segment; the remote end holds all the state.

solid answer

~40 s

In Selenium 4, `POST /session` creates a session and its reply carries a `sessionId` inside the `value` member. Every command after that hangs off that identifier: `POST /session/{session id}/url` to navigate, `POST /session/{session id}/element` to find, `POST /session/{session id}/element/{element id}/click` to click, `POST /session/{session id}/execute/sync` to run a script, and `DELETE /session/{session id}` to finish. The id is an opaque path segment rather than a cookie, a header or a binding to the connection, so any connection can carry any command and anything in the middle can route on the URL alone. All the state - browsing context, cookies, element handles - lives on the remote end under that id. `GET /status` is the one route with no session in its path.

code

bash · 10 lines
bash
SESSION=$(curl -s -X POST http://localhost:4444/session \
  -H 'Content-Type: application/json' \
  -d '{"capabilities":{"alwaysMatch":{"browserName":"chrome"}}}' \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["value"]["sessionId"])')

curl -s -X POST "http://localhost:4444/session/$SESSION/url" \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://fleet.internal/vehicles/overdue"}'

curl -s -X DELETE "http://localhost:4444/session/$SESSION"

go deeper

for a junior

Know that a session is created first, that it has an id, and that everything your test does afterwards is addressed under that id until the session is deleted.

for a middle

Be able to name the routes for navigating, finding, clicking and scripting, and to explain that the id is a path segment rather than a header, cookie or connection binding.

for a senior

Connect the shape to failures you have seen: why a dead browser yields an invalid session id on the next command, and why a handle from one session is worthless in another.

for a principal

Talk about what the design enables - routing on the path alone, no connection affinity, all state on the remote end - and what that means for anything you build or place between clients and drivers.

## Two routes bracket everything else The Selenium 4 command catalogue has a shape you can hold in your head. One route creates a session and one route destroys it, and every other command lives underneath the identifier the first one handed back: - **`POST /session`** creates a session. Its reply carries, inside the usual `value` member, a `sessionId` string and the `capabilities` the remote end actually granted. - **`DELETE /session/{session id}`** ends that session and releases the browser behind it. - **Everything in between** is a route of the form `/session/{session id}/...`. That single-prefix design is why the whole catalogue is learnable. There is no second addressing scheme and no per-command handshake: if you know the session id, you can address any command in the specification. ## The routes a fleet-scheduler case actually uses | Command | Route | |---|---| | Navigate To | `POST /session/{session id}/url` | | Get Current URL | `GET /session/{session id}/url` | | Find Element | `POST /session/{session id}/element` | | Find Elements | `POST /session/{session id}/elements` | | Element Click | `POST /session/{session id}/element/{element id}/click` | | Element Send Keys | `POST /session/{session id}/element/{element id}/value` | | Execute Script | `POST /session/{session id}/execute/sync` | Reading the table against a real case makes the mapping obvious. Opening the depot's overdue-vehicle list is a `POST` to `/url`; finding the row for truck `FL-118` is a `POST` to `/element`; clicking its **Schedule service** button is a `POST` to the `click` route under the handle that find returned; typing the technician's name into the work-order form is a `POST` to the `value` route. Note the two different meanings of the word `value` in the protocol — the response member that wraps every result, and the route segment that means *send keys to this element*. They are unrelated, and confusing them is a classic interview stumble. ## What putting the id in the path actually buys The session identifier travels as a path segment. Not a cookie, not an authorization header, not an implicit binding to the connection that created it. Three real properties follow: 1. **Any connection can carry any command.** Nothing about the session is pinned to the socket that created it, so a client may open, reuse or drop connections freely without the remote end losing track of which browser it is driving. 2. **An intermediary can route on the path alone.** Something sitting between the local end and the remote end can read the id out of the URL and forward the request to the right place without parsing the body or holding per-connection state. 3. **The remote end owns all the state.** Current browsing context, cookies, timeouts and every live element handle live on the driver side, filed under that id. The client holds an identifier and nothing else, which is why two client objects pointed at the same id would drive the very same browser. ## Creating and destroying, and what sits outside - The id is opaque. It is a string the remote end chose; a client must never parse or construct one. - Once `DELETE /session/{session id}` has run, every later command carrying that id fails, because the remote end no longer has anything filed under it. - Element handles are scoped inside the session: they appear in the path as a further segment and mean nothing under a different session id. - **`GET /status`** is the one route in normal use that carries no session id at all. It reports whether the remote end is in a state to create a new session, which is exactly the question you cannot answer from inside a session. ## Reading it back off the wire A quick pass by hand is the fastest way to make the shape stick: ``` POST /session -> {"value":{"sessionId":"8f3c","capabilities":{...}}} POST /session/8f3c/url -> {"value":null} POST /session/8f3c/element -> {"value":{"<element key>":"e19a"}} POST /session/8f3c/element/e19a/click -> {"value":null} DELETE /session/8f3c -> {"value":null} ``` Five requests, and the second through fourth are indistinguishable in structure from every other command in the catalogue. The Java you would write over them — `driver.get(...)`, `findElement(...)`, `click()`, `quit()` — is a typed skin over exactly this sequence, which is why a driver log and a test method can be read side by side when something goes wrong. ## Why interviewers ask it The question separates people who have only used the client API from people who have looked underneath it. Knowing that the id is a path segment explains, without further study, why a crashed browser produces an `invalid session id` on the next command, why an element handle from one session is meaningless in another, and why anything standing between client and driver can route commands without understanding them.

  • Why is the session id in the path rather than in a header or a cookie?
    Because it keeps addressing uniform and stateless. Anything forwarding the request can pick the target out of the URL without reading the body or tracking connections, a client can reuse or drop connections freely, and a command is fully described by its route plus its body. Nothing about the session is tied to the socket that created it.
  • What happens to element handles once the session is deleted?
    They become meaningless. A handle is scoped to the session that produced it and appears as a further path segment under that session, so it cannot be replayed under a different id. After the delete, the remote end has nothing filed under the session at all and any command carrying that id fails.
  • Which route would you call to check a remote end before starting a run?
    `GET /status`, the one route in normal use that carries no session id. It reports whether the remote end is in a state to create a new session, which is exactly the question you cannot ask from inside a session that does not exist yet.

saying these in an interview costs you the question

  • Thinks the session is bound to the connection that created it
  • Believes the session id travels in a header or cookie
  • Tries to reuse an element handle under another session id
  • Assumes each command needs its own handshake with the driver
  • Cannot say which route ends a session