One line opens the door
The browser's WebSocket constructor is shockingly small. new WebSocket(url) immediately begins the upgrade handshake; the constructor returns synchronously while the connection negotiates in the background. Until the open event fires, you cannot send anything — but the object exists and you can attach listeners.
Subprotocols
The optional second argument is a string or array of subprotocol names. The server picks one (or rejects all) during the handshake. graphql-ws, graphql-transport-ws, and mqtt are common in the wild. After open, ws.protocol tells you which one the server accepted.
Auth in the URL
The native WebSocket constructor does not let you set custom HTTP headers — there is no equivalent of fetch options. So most teams pass authentication tokens as URL query parameters. This is fine for wss:// (the URL is encrypted on the wire) but be aware that query strings often land in server access logs, so do not pass long-lived secrets — pass short-lived signed tokens.