This episode dissects the browser's built-in WebSocket API: creating an instance, the four event handlers, the send and close methods, and the readyState and bufferedAmount properties, plus a simple reconnection pattern.

All the protocol concepts we dissected in episodes 2 and 3 now take practical form: the browser's built-in WebSocket API. You do not need to install any library — every modern browser already implements RFC 6455.
Episode 4 takes you through this API from scratch: creating a WebSocket instance, registering the four event handlers, using the send and close methods, reading the readyState and bufferedAmount properties, and putting together reconnection logic. By the end of the episode you will have a complete WebSocket client ready to talk to any server.
Opening a connection is just one line:
const ws = new WebSocket("wss://example.com/ws");
const wsChat = new WebSocket("wss://example.com/chat", ["chat-v1", "chat-v2"]);The second parameter is a list of requested subprotocols. new WebSocket(url, protocols) creates the instance and immediately starts the handshake. The server may pick one from that list via the Sec-WebSocket-Protocol header.
Immediately after the instance is created:
ws.readyState holds the connection state (0 to 3).ws.bufferedAmount holds the number of bytes not yet sent.ws.url shows the final URL after redirects.Called when the handshake completes and the connection is ready to use:
ws.onopen = () => {
console.log("koneksi terbuka");
ws.send("halo server");
};Make sure all initial messages are sent from inside onopen — sending before this event can fail because the connection is not yet OPEN.
Called every time a data frame arrives. This is the heart of a real-time application:
ws.onmessage = (event) => {
const data = event.data;
if (typeof data === "string") {
renderText(data);
} else {
renderBinary(data);
}
};event.data can be a string for text frames, or a Blob and ArrayBuffer for binary frames. The default binary behavior is Blob; it can be changed with ws.binaryType = "arraybuffer".
Errors and closures need to be handled separately:
ws.onerror = (event) => {
console.error("terjadi error", event);
};
ws.onclose = (event) => {
console.log("koneksi ditutup", event.code, event.reason);
};onclose receives an object with event.code and event.reason. Note: onerror is not always followed by a closure, but onclose almost always comes after a fatal error.
The two main methods:
ws.send("pesan teks");
ws.send(new Blob([data]));
ws.send(new Uint8Array([1, 2, 3]));
ws.close(1000, "tutup normal");ws.send() accepts a string, Blob, or ArrayBufferView. ws.close(code, reason) starts a polite closure: a close frame is sent, then the state moves to CLOSED.
Both properties are important for debugging:
function kirimPelan(ws, teks) {
ws.send(teks);
if (ws.bufferedAmount > 0) {
console.log("masih ada data tertunda:", ws.bufferedAmount);
}
}ws.bufferedAmount tells you how many bytes have not yet reached the network — an early signal of backpressure that we will discuss in a later episode.
A WebSocket connection can drop at any time. This is the minimum pattern you must have:
let ws;
function hubungkan() {
ws = new WebSocket("wss://example.com/ws");
ws.onclose = () => {
setTimeout(hubungkan, 3000);
};
}
hubungkan();Calling hubungkan() from inside onclose with setTimeout(hubungkan, 3000) is the essence of reconnection. A later episode will upgrade this pattern with exponential backoff and retry limits.
All modern browsers support WebSocket, but defensive code is still worthwhile:
if (window.WebSocket) {
// jalan normal
} else {
// fallback ke polling atau SSE
}Check window.WebSocket before using the API. For older browsers, the common fallback is SSE or long polling — exactly the options from episode 1.
Warning
On mobile, WebSocket connections die more often due to network switching. Always install reconnection logic and state recovery code like the upcoming episode covers, not just an onopen handler.
Episode 4 equipped you with a native WebSocket client: creating an instance, the four event handlers, the send and close methods, the readyState and bufferedAmount properties, and a simple reconnection pattern to withstand dropped connections.
Key takeaways:
In the next episode we move to the server side: a WebSocket server with Node.js and the ws library — installation, server creation, the connection event, broadcast, and managing connected clients. You will have a complete client and server pair.