Web APIs Cheatsheet

WebSocket API

Use this Web APIs reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Creating a Connection

const ws = new WebSocket('wss://api.example.com/socket');
// With sub-protocols (server selects one)
const ws = new WebSocket('wss://api.example.com/socket', ['json', 'binary']);

ws.protocol;      // sub-protocol server selected (string)
ws.url;           // connection URL
ws.binaryType;    // 'blob' (default) | 'arraybuffer'
ws.bufferedAmount; // bytes queued but not yet sent
ws.extensions;    // negotiated extensions string

readyState Values

ValueConstantMeaning
0WebSocket.CONNECTINGConnection not yet open
1WebSocket.OPENOpen and ready to send
2WebSocket.CLOSINGClosing handshake in progress
3WebSocket.CLOSEDConnection closed
ws.readyState === WebSocket.OPEN; // safe to send

Event Handlers

ws.addEventListener('open', e => {
  console.log('Connected');
  ws.send('hello');
});

ws.addEventListener('message', e => {
  // e.data is string | Blob | ArrayBuffer depending on binaryType
  if (typeof e.data === 'string') {
    const msg = JSON.parse(e.data);
  } else if (e.data instanceof ArrayBuffer) {
    const view = new Uint8Array(e.data);
  }
});

ws.addEventListener('close', e => {
  e.code;     // close code (1000 = normal, 1006 = abnormal)
  e.reason;   // string reason
  e.wasClean; // boolean
});

ws.addEventListener('error', e => {
  // e is a generic Event — no detail; check network tab
  console.error('WebSocket error', e);
});

Common Close Codes

CodeMeaning
1000Normal closure
1001Endpoint going away (page unload, server restart)
1002Protocol error
1003Unsupported data type
1006Abnormal closure (connection lost, no close frame)
1007Invalid frame payload
1008Policy violation
1009Message too large
1011Unexpected server error
4000–4999Application-defined codes

Sending Data

// String
ws.send('plain text');
ws.send(JSON.stringify({ type: 'ping' }));

// Binary
ws.send(new ArrayBuffer(8));
ws.send(new Uint8Array([1, 2, 3]));
ws.send(new Blob(['binary data']));

// Guard: only send when open
if (ws.readyState === WebSocket.OPEN) ws.send(data);

Closing the Connection

ws.close();               // normal close, code 1000
ws.close(1000, 'Done');   // code + reason (≤123 bytes UTF-8)
ws.close(4001, 'Auth failed');

Receiving Binary Data

ws.binaryType = 'arraybuffer'; // change before or after open
ws.addEventListener('message', e => {
  const buf = e.data;           // ArrayBuffer
  const view = new DataView(buf);
  view.getUint8(0);
  new Uint8Array(buf);
});

// blob (default) — convert when needed
ws.binaryType = 'blob';
ws.addEventListener('message', async e => {
  const buf = await e.data.arrayBuffer();
});

Reconnection Pattern

function createSocket(url, onMessage) {
  let ws, reconnectTimer;

  function connect() {
    ws = new WebSocket(url);

    ws.addEventListener('open', () => {
      console.log('WebSocket open');
      clearTimeout(reconnectTimer);
    });

    ws.addEventListener('message', e => onMessage(JSON.parse(e.data)));

    ws.addEventListener('close', e => {
      if (!e.wasClean) {
        reconnectTimer = setTimeout(connect, 2000); // retry after 2 s
      }
    });

    ws.addEventListener('error', () => ws.close());
  }

  connect();

  return {
    send: data => ws.readyState === WebSocket.OPEN && ws.send(JSON.stringify(data)),
    close: () => { clearTimeout(reconnectTimer); ws.close(1000); },
  };
}

Heartbeat / Ping-Pong

The browser WebSocket API doesn't expose ping frames directly. Implement an application-level heartbeat.

let heartbeat;

ws.addEventListener('open', () => {
  heartbeat = setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: 'ping' }));
  }, 30000);
});

ws.addEventListener('message', e => {
  const msg = JSON.parse(e.data);
  if (msg.type === 'pong') return; // ignore heartbeat responses
  handleMessage(msg);
});

ws.addEventListener('close', () => clearInterval(heartbeat));

Backpressure / bufferedAmount

// Don't flood the socket — wait until buffer drains
function sendThrottled(ws, data) {
  if (ws.bufferedAmount > 64 * 1024) { // 64 kB threshold
    setTimeout(() => sendThrottled(ws, data), 50);
    return;
  }
  ws.send(data);
}

Authentication Patterns

The browser WebSocket handshake cannot set custom headers. Use one of these approaches:

// 1. Token in URL query parameter (visible in logs — use short-lived tokens)
const ws = new WebSocket(`wss://api.example.com/ws?token=${token}`);

// 2. Send auth message immediately after open
ws.addEventListener('open', () => {
  ws.send(JSON.stringify({ type: 'auth', token }));
});

// 3. Cookie-based — cookies are sent automatically on same-origin WS
const ws = new WebSocket('wss://same-origin.example.com/ws');

WebSocket in a Worker

// WebSocket works in dedicated and shared workers
// worker.js
const ws = new WebSocket('wss://api.example.com/ws');
ws.onmessage = e => postMessage(e.data);
onmessage = e => ws.send(e.data);

Common Message Protocol Patterns

// Typed message envelope
const send = (ws, type, payload) =>
  ws.send(JSON.stringify({ type, payload, ts: Date.now() }));

ws.addEventListener('message', e => {
  const { type, payload } = JSON.parse(e.data);
  handlers[type]?.(payload);
});

// Request-response over WebSocket
const pending = new Map();
function request(ws, type, payload) {
  const id = crypto.randomUUID();
  return new Promise((resolve, reject) => {
    pending.set(id, { resolve, reject });
    ws.send(JSON.stringify({ id, type, payload }));
    setTimeout(() => { pending.delete(id); reject(new Error('Timeout')); }, 10000);
  });
}
ws.addEventListener('message', e => {
  const { id, result, error } = JSON.parse(e.data);
  if (!pending.has(id)) return;
  const { resolve, reject } = pending.get(id);
  pending.delete(id);
  error ? reject(new Error(error)) : resolve(result);
});

Difference vs SSE vs Long Polling

FeatureWebSocketServer-Sent EventsLong Polling
DirectionFull-duplexServer → clientServer → client
ProtocolWS / WSSHTTPHTTP
ReconnectManualAutomaticManual
Binary supportYesNo (text only)With encoding
ProxiesMay block WSWorks everywhereWorks everywhere
Browser supportAllAll modernAll