WebSockets Cheatsheet
Client API
Use this WebSockets reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Constructor
// Basic const ws = new WebSocket("wss://example.com/ws"); // With subprotocols const ws = new WebSocket("wss://example.com/ws", "json"); const ws = new WebSocket("wss://example.com/ws", ["json", "msgpack"]);
The browser WebSocket constructor takes a URL string and an optional protocol string or array. No option object — use query params for extra data.
Properties Reference
| Property | Type | Description |
|---|---|---|
ws.url | string | The URL passed to the constructor |
ws.readyState | number | Current connection state (see below) |
ws.bufferedAmount | number | Bytes queued to send but not yet transmitted |
ws.protocol | string | Subprotocol selected by the server (or "") |
ws.extensions | string | Extensions negotiated (e.g. "permessage-deflate") |
ws.binaryType | string | "blob" (default) or "arraybuffer" |
WebSocket.CONNECTING | 0 | Static constant |
WebSocket.OPEN | 1 | Static constant |
WebSocket.CLOSING | 2 | Static constant |
WebSocket.CLOSED | 3 | Static constant |
readyState Values
switch (ws.readyState) { case WebSocket.CONNECTING: // 0 — handshake in progress case WebSocket.OPEN: // 1 — ready to use case WebSocket.CLOSING: // 2 — close handshake started case WebSocket.CLOSED: // 3 — connection closed }
Methods
send(data)
ws.send("hello world"); // text (string) ws.send(JSON.stringify({ type: "msg" })); // JSON as text ws.send(new ArrayBuffer(8)); // binary ws.send(new Uint8Array([1, 2, 3])); // typed array ws.send(blob); // Blob
Call only when
readyState === WebSocket.OPEN. Calling whileCONNECTINGthrowsInvalidStateError.
close([code[, reason]])
ws.close(); // code 1000, no reason ws.close(1000); // normal closure ws.close(1001, "Bye"); // with reason string (max 123 bytes UTF-8) ws.close(4001, "Custom app code");
After calling
close(),readyStatemoves toCLOSING. Thecloseevent fires when the handshake completes.
Events
Event Listener Pattern (recommended)
ws.addEventListener("open", (event) => { console.log("connected"); }); ws.addEventListener("message", (event) => { console.log("data:", event.data); // string, Blob, or ArrayBuffer console.log("origin:", event.origin); // server origin console.log("lastEventId:", event.lastEventId); }); ws.addEventListener("error", (event) => { // event is a generic Event — no error details exposed (security) console.error("WebSocket error"); }); ws.addEventListener("close", (event) => { console.log("code:", event.code); // number console.log("reason:", event.reason); // string console.log("wasClean:", event.wasClean); // boolean });
Handler Properties (alternative)
ws.onopen = (event) => { /* ... */ };
ws.onmessage = (event) => { /* ... */ };
ws.onerror = (event) => { /* ... */ };
ws.onclose = (event) => { /* ... */ };
addEventListenersupports multiple handlers per event; handler properties do not. PreferaddEventListener.
MessageEvent Properties
| Property | Type | Description |
|---|---|---|
event.data | string | Blob | ArrayBuffer | Message payload |
event.origin | string | Server origin ("wss://example.com") |
event.lastEventId | string | Always "" for WebSocket |
event.source | null | Always null for WebSocket |
CloseEvent Properties
| Property | Type | Description |
|---|---|---|
event.code | number | Close code (see codes table in Basics) |
event.reason | string | Human-readable reason |
event.wasClean | boolean | true if close handshake completed properly |
Receiving Binary Data
// Default: data arrives as Blob ws.binaryType = "blob"; ws.onmessage = async ({ data }) => { if (data instanceof Blob) { const text = await data.text(); const buffer = await data.arrayBuffer(); } }; // Prefer ArrayBuffer for direct typed-array access ws.binaryType = "arraybuffer"; ws.onmessage = ({ data }) => { if (data instanceof ArrayBuffer) { const view = new DataView(data); console.log(view.getUint8(0)); } };
Checking bufferedAmount Before Sending
const MAX_BUFFER = 1024 * 64; // 64 KB function throttledSend(ws, data) { if (ws.bufferedAmount > MAX_BUFFER) { console.warn("send buffer full, dropping frame"); return; } ws.send(data); }
bufferedAmountdoes not decrease in real time in all browsers — check it just beforesend().
Passing Auth Without Headers
The browser does not allow setting custom headers on WebSocket connections.
// Option 1: Query parameter const ws = new WebSocket(`wss://api.example.com/ws?token=${encodeURIComponent(jwt)}`); // Option 2: Cookie (sent automatically if same origin / SameSite allows it) // Set-Cookie: hu_session=...; HttpOnly; Secure; SameSite=None const ws = new WebSocket("wss://api.example.com/ws"); // Option 3: First message after open (protocol-level auth) ws.addEventListener("open", () => { ws.send(JSON.stringify({ type: "auth", token: jwt })); });
Full Minimal Client Example
class ChatClient { constructor(url) { this.url = url; this.ws = null; } connect() { this.ws = new WebSocket(this.url); this.ws.binaryType = "arraybuffer"; this.ws.addEventListener("open", () => this.onOpen()); this.ws.addEventListener("message", (e) => this.onMessage(e)); this.ws.addEventListener("error", (e) => this.onError(e)); this.ws.addEventListener("close", (e) => this.onClose(e)); } send(data) { if (this.ws?.readyState === WebSocket.OPEN) { this.ws.send(typeof data === "string" ? data : JSON.stringify(data)); } } onOpen() { console.log("connected"); } onMessage({ data }) { console.log("msg:", data); } onError() { console.error("error"); } onClose({ code, wasClean }) { console.log(`closed ${wasClean ? "cleanly" : "abruptly"} with code ${code}`); } disconnect() { this.ws?.close(1000, "User left"); } }
Gotchas
- The browser exposes no error detail in the
errorevent (intentional — prevents port scanning). Check server logs. ws.send()throwsInvalidStateErroronly whileCONNECTING; onCLOSING/CLOSEDit silently discards the data. Guard withreadyState === WebSocket.OPENso messages are not dropped without a trace.- Calling
new WebSocket()immediately begins the handshake — you cannot setbinaryTypebeforeopenfires and have it affect initial messages; set it right after construction instead. - Tab or browser close triggers code
1001("going away") — thebeforeunloadevent fires before the close frame completes. - CORS does not apply to WebSockets. The
Originheader is sent but the browser does not enforce same-origin — validate it server-side.