The bundled debugger UI ignores the `token` query parameter whenever a previously saved "Browser URL" exists in localStorage

Author: AnonymousMonkeyNo12Created Sep 2, 2026Updated Sep 2, 2026

Describe the bug The bundled debugger UI ignores the token query parameter whenever a previously saved "Browser URL" exists in localStorage and since settings are written to localStorage on every page load, a single visit to /debugger/ without ?token= permanently breaks all later visits with a valid ?token=.

Concretely, in src/api.ts (https://github.com/browserless/debugger):

typescript
const priorSettings = getState() ?? {};
const token = new URL(window.location.href).searchParams.get("token");
const defaultURL = new URL(window.location.origin);
if (token) defaultURL.searchParams.set('token', token);
const baseURL = priorSettings.baseURL ?? defaultURL.href;
saveState({ ..., baseURL, ... });

The URL token is only applied when priorSettings.baseURL is unset. Once any token-less baseURL is persisted (localStorage key browserless-debugger:<origin><pathname>apiSettings.baseURL), every subsequent /debugger/?token=<VALID_TOKEN> load reuses the stale URL: the WebSocket connect and the GET /sessions call are sent with no token and fail with 401. This also silently breaks the debugger after a server-side TOKEN change, because the old saved URL (old/no token) keeps winning over the new ?token=.

Note the storage key includes the pathname, so /debugger/ and / keep separate settings token behavior then depends on which entry point was used first, which makes the bug extra confusing.

To Reproduce

  1. Start browserless with a token: docker run --rm -p 3000:3000 -e "TOKEN=6R0W53R135510" ghcr.io/browserless/chromium
  2. Open http://localhost:3000/debugger/ (deliberately WITHOUT ?token=). The debugger persists a token-less Browser URL to localStorage.
  3. Now open http://localhost:3000/debugger/?token=6R0W53R135510.
  4. Press Run / connect. The debugger shows ⚠️ Couldn't establish a connection "wss://localhost:3000/?launch=...". In DevTools → Network → WS, the upgrade request URL contains no token parameter; the server logs: browserless.io:server:error Websocket request is not properly authorized, responding with 401 The Sessions tab also fails: GET /sessions → 401.
  5. Fix/workaround: in the console run Object.keys(localStorage).filter(k => k.startsWith("browserless-debugger:")).forEach(k => localStorage.removeItem(k)) and reload with ?token= → the WS URL now includes ?token=, connects (101), and everything works until the stale entry is (re)created again. Alternatively re-entering the Browser URL (incl. token) in the Settings modal also fixes it, but nothing in the UI hints that a stored URL is overriding the ?token= parameter.

Expected behavior When ?token= is present in the page URL it should take precedence e.g. the token should be merged into the stored baseURL on every load (or at minimum trigger a visible warning that a saved Browser URL is overriding the URL parameter). ?token= is the documented/printed way to open the debugger (startup banner: Debugger: http://localhost:3000/debugger/?token=...), so it should not be silently ignored.

Additional context

  • Environment: self-hosted ghcr.io/browserless/chromium:latest behind a reverse proxy, TOKEN set. The token itself is valid: POST /function with the same token authorizes and runs fine; only debugger-originated requests (WS /?launch=... and GET /sessions) 401 because they carry no token.
  • Aggravating real-world case: with a browser configured to clear site data on close (private-session-like setup), the debugger breaks again on the next session and the localStorage key has to be removed manually every time the stale entry either survives the "clear on close" or gets re-persisted by a token-less load, and there is no UI hint about the override.
  • Helpful for diagnosis: the connection error message already prints the effective browserWSEndpoint, which is how the missing ?token= was spotted. Printing the same effective URL (and whether it came from saved settings vs. URL param) in the Settings modal would help users self-diagnose.