← Add options bag to WebSocket constructor

v154 · experimental · constructor

WebSocket(url, protocols­OrOptions)

The WebSocket() constructor with its widened second parameter: a subprotocol string, an array of subprotocol strings, or — new in this feature — a WebSocketInit options dictionary. Connection semantics are otherwise unchanged from the classic constructor. Implemented in Chromium behind the experimental WebSocketOptionBag flag, targeted at Chrome 154.

Experimental

Behind --enable-blink-features=WebSocketOptionBag (or chrome://flags/#enable-experimental-web-platform-features); the stable-promotion CL 8256918 and the defining spec change whatwg/websockets PR #76 are both open as of 2026-09-20. With the flag off, an options object coerces to the string "[object Object]" and the constructor throws SyntaxError. See the overview warn-block for a feature-detection pattern.

syntax

new WebSocket(url)
new WebSocket(url, protocols)        // string or array — classic form
new WebSocket(url, options)          // WebSocketInit dictionary — new

Proposed spec IDL (whatwg/websockets PR #76, quoted verbatim):

constructor(USVString url,
            optional (DOMString or sequence<DOMString> or WebSocketInit) protocolsOrOptions = []);

Shipping Chromium IDL (websocket.idl at trunk, 2026-09-20 — quoted verbatim; the parameter is temporarily any so behavior can differ by flag state):

// The type of `protocolsOrOptions` is `any` because the type needs to
// differ depending on the setting of the "WebSocketOptionBag" feature.
// TODO(crbug.com/542670554): Change to `(DOMString or sequence<DOMString> or
// WebSocketInit)` when the "WebSocketOptionBag" feature is permanently
// enabled and removed.
[CallWith=ExecutionContext, RaisesException]
constructor(USVString url, optional any protocolsOrOptions);
Source: PR #76 diff; websocket.idl; crbug.com/542670554

parameters

urlUSVString — the endpoint. Unchanged by this feature: ws, wss, http, and https schemes are allowed, fragments are not (per the living standard)
protocolsOrOptions (optional)One of: a subprotocol string (equivalent to a one-element array), a sequence of strings (any iterable of strings, most commonly an array), or a WebSocketInit dictionary whose protocols member supplies the same list. Defaults to [] (offer no subprotocol). Union routing follows Web IDL union conversion: strings take the DOMString branch, iterable objects the sequence branch, other objects the dictionary branch, and undefined the parameter default
Source: PR #76 diff; Web IDL § ES union conversion; living standard

return value

A new WebSocket object in the CONNECTING state, exactly as the classic constructor returns; the connection is established asynchronously and open fires when the handshake (including subprotocol negotiation) completes. The server-selected subprotocol is then readable on socket.protocol. Which spelling supplied the protocols list is not observable on the returned object — { protocols: ["soap"] } and ["soap"] produce identical connections (in Chromium both feed the same Vector<String> handed to Connect() in dom_websocket.cc).

Source: living standard (connection algorithm); dom_websocket.cc

errors

SyntaxError DOMExceptionUnchanged host-constructor errors: a URL with a disallowed scheme or a fragment, or an invalid/duplicate subprotocol name — whichever branch supplied it. With the flag off, passing an options object lands here too: it coerces to "[object Object]", which is not a valid subprotocol token
TypeErrorA WebSocketInit whose protocols member is not an iterable object of strings — including the tempting bare string { protocols: "soap" } — fails Web IDL sequence conversion before any network activity
SecurityError DOMExceptionUnchanged: ports blocked by the user agent (per the living standard)
Source: living standard (constructor exceptions); Web IDL § sequence conversion

context and exposure

Exposed wherever WebSocket is exposed: Window and Worker contexts ([Exposed=(Window,Worker)] in both the spec PR and Chromium's IDL). The overload requires no permission, secure-context, or policy gate of its own — only the WebSocketOptionBag runtime flag in Chromium. The dictionary branch simply does not exist when the flag is off; there is no partial state.

Source: PR #76 diff; websocket.idl

lifecycle

  1. Script calls the constructor; the second argument is routed by union conversion (in Chromium: V8UnionStringOrStringSequenceOrWebSocketInit::Create, then ParseConstructorOptionsWithBag() in dom_websocket.cc).
  2. A dictionary's protocols list replaces the positional list; all later steps are the classic algorithm: validate protocols, open the handshake, fire open/error/close.
  3. The choice of spelling has no further lifecycle effect — reconnection, buffering, close(), and events behave identically.
Source: dom_websocket.cc; PR #76 diff (“Otherwise, set protocols to protocolsOrOptions”)

examples

// Feature-detect, then prefer the extensible form:
let socket;
try {
  socket = new WebSocket("wss://example.com/feed", { protocols: ["v2.feed"] });
} catch {
  // Older engine: object was coerced to "[object Object]" → SyntaxError.
  socket = new WebSocket("wss://example.com/feed", ["v2.feed"]);
}

socket.addEventListener("open", () => {
  console.log("negotiated subprotocol:", socket.protocol); // "v2.feed" or ""
});
Source: gendn-derived from the PR #76 semantics and the WPT negotiation test (labelled accordingly)

browser compatibility

Interim table. No BCD key for the overload (verified 2026-09-20); rows compiled from primary sources.

BrowserSupportEvidence
Chrome / Edge (Chromium)Implemented behind WebSocketOptionBag (experimental); stable promotion targeted at 154, pending as of 2026-09-20CL 8197225; flag record; CL 8256918
FirefoxNo signalChromeStatus API record; mozilla/standards-positions #1444
SafariPositive position, not shippedWebKit/standards-positions #708
Every row above links its own source record.

security and privacy

No new capability: the overload cannot reach any endpoint, port, or protocol the classic constructor cannot. The one behavioral delta is web-compat — a non-iterable object argument stops throwing SyntaxError and starts meaning “empty options”; the spec PR review is measuring how much shipping code relies on the old rejection before the change merges. Future dictionary members are individually security-reviewed (see targetAddressSpace on the WebSocketInit page).

Source: PR #76 review thread

see also