JavaScript WebSocket API
Learn the JavaScript WebSocket API: the connection lifecycle and readyState, sending text, JSON, and binary data, reconnection, and security.
Introduction to WebSocket Technology
WebSocket is a protocol that provides a full-duplex (two-way) communication channel between the browser and a server over a single, long-lived TCP connection. Once the connection is open, either side can send a message at any time without waiting for the other to ask — something plain HTTP cannot do.
This page covers what WebSockets solve, the connection lifecycle, sending text and binary data, working with JSON messages, reconnection, security, and where to use a library instead of the raw API. We build everything around a runnable Echo Chat example.
Why WebSockets instead of HTTP?
With regular HTTP (including the Fetch API and XMLHttpRequest), the client must initiate every exchange. To get live updates you have to poll — repeatedly ask "anything new?" — which wastes bandwidth and adds latency. WebSockets flip this: the server can push data the instant it has something, with almost no per-message overhead.
| Approach | Direction | Overhead | Best for |
|---|---|---|---|
| HTTP request/response | Client asks, server answers | Full headers per request | One-off fetches, REST APIs |
| Polling | Client asks on a timer | Many wasted requests | Simple, low-frequency updates |
| WebSocket | Both push freely | One handshake, tiny frames | Chat, live feeds, games, dashboards |
Use WebSockets when the server needs to talk first or messages flow constantly: chat, multiplayer games, collaborative editors, trading tickers, and live dashboards. For occasional one-directional updates from server to client only, Server-Sent Events or the Push API may be simpler.
The WebSocket Connection Lifecycle
You open a connection by passing a ws:// (plain) or wss:// (encrypted) URL to the WebSocket constructor. The connection then moves through four states exposed by socket.readyState:
| Constant | Value | Meaning |
|---|---|---|
WebSocket.CONNECTING | 0 | Handshake in progress (the initial state) |
WebSocket.OPEN | 1 | Ready to send and receive |
WebSocket.CLOSING | 2 | A close was requested |
WebSocket.CLOSED | 3 | Connection closed or failed to open |
You react to transitions with four events: open, message, error, and close. The key rule is that you can only call socket.send() while readyState is OPEN — sending before open fires throws an error.
const socket = new WebSocket("wss://echo.websocket.events");
socket.addEventListener("open", () => {
console.log("open, readyState =", socket.readyState); // 1
socket.send("hello");
});
socket.addEventListener("message", (event) => {
console.log("received:", event.data); // "hello" (echoed back)
});
socket.addEventListener("close", (event) => {
console.log("closed, code =", event.code); // e.g. 1000
});Setting Up the WebSocket Echo Chat
Basic HTML Structure
First, we establish the user interface with HTML that includes a message display area, input field, and control buttons.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>WebSocket Echo Chat</title>
</head>
<body>
<textarea id="chatBox" readonly style="width: 100%; height: 300px"></textarea><br />
<input type="text" id="messageInput" placeholder="Type a message..." style="width: 75%" />
<button onclick="sendMessage()">Send</button>
<button onclick="closeConnection()">Close Connection</button>
</body>
</html>Integrating WebSocket with JavaScript
The JavaScript for managing WebSocket communication is key to enabling real-time interactions.
<script>
// Accessing the chat box and message input elements from the HTML.
const chatBox = document.getElementById("chatBox");
const messageInput = document.getElementById("messageInput");
// Establishing a WebSocket connection to the echo server.
const socket = new WebSocket("wss://echo.websocket.events");
// When the connection is open, display a connected message in the chat box.
socket.addEventListener("open", function (event) {
chatBox.value += "Connected to the echo server\n";
});
// Handle incoming messages by adding them to the chat box.
socket.addEventListener("message", function (event) {
chatBox.value += "Echoed back: " + event.data + "\n";
});
// Handle connection errors.
socket.addEventListener("error", function (event) {
chatBox.value += "Connection error occurred.\n";
});
// Handle connection closure.
socket.addEventListener("close", function (event) {
chatBox.value += "Connection closed. Code: " + event.code + "\n";
});
// Function to send a message when the send button is clicked.
function sendMessage() {
const message = messageInput.value; // Get the message from the input field.
if (!message) return; // If there's no message, don't do anything.
socket.send(message); // Send the message to the server.
chatBox.value += "You: " + message + "\n"; // Show the message in the chat box.
messageInput.value = ""; // Clear the message input field.
}
// Function to close the WebSocket connection.
function closeConnection() {
if (socket.readyState === WebSocket.OPEN) {
socket.close(1000, "The user closed the connection"); // Close the connection normally.
chatBox.value += "Connection closed by user\n"; // Inform the user in the chat box.
} else {
alert("Connection is not open or already closed."); // Alert if the connection can't be closed.
}
}
// Ensure the WebSocket is closed properly when the webpage is closed or reloaded.
window.addEventListener("beforeunload", function () {
if (socket.readyState === WebSocket.OPEN) {
socket.close(1000, "The page is unloading"); // Close the connection normally.
}
});
</script>This script sets up a chat feature on a webpage that connects to a server using WebSockets. Here’s a simple explanation of its parts:
- Accessing HTML Elements: The script gets the chat box and message input box from the webpage so it can interact with them.
- WebSocket Connection: It opens a connection to a server that echoes messages back. This means anything you send to this server will be sent right back to you.
- Displaying Connection Status: When the connection is successfully made, it displays a message in the chat box saying that the connection to the echo server is established.
- Handling Incoming Messages: Any messages that come back from the server are added to the chat box, showing that the server has echoed the messages.
- Sending Messages: There’s a function to send messages typed into the input box. If there's text, it sends it to the server and then displays it in the chat box as your message.
- Closing the Connection: There’s also a function to close the WebSocket connection when needed, like when the user decides to close it or when the webpage is being closed.
This setup allows for real-time communication with the server and helps to test and demonstrate how messaging applications work.
And now let's put it all together and see it in action:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>WebSocket Echo Chat</title>
</head>
<body>
<textarea id="chatBox" readonly style="width: 100%; height: 300px">
</textarea>
<br />
<input
type="text"
id="messageInput"
placeholder="Type a message..."
style="width: 75%"
/>
<button onclick="sendMessage()">Send</button>
<button onclick="closeConnection()">Close Connection</button>
</body>
<script>
const chatBox = document.getElementById("chatBox");
const messageInput = document.getElementById("messageInput");
const socket = new WebSocket("wss://echo.websocket.events");
socket.addEventListener("open", function (event) {
chatBox.value += "Connected to the echo server\n";
});
socket.addEventListener("message", function (event) {
chatBox.value += "Echoed back: " + event.data + "\n";
});
socket.addEventListener("error", function (event) {
chatBox.value += "Connection error occurred.\n";
});
socket.addEventListener("close", function (event) {
chatBox.value += "Connection closed. Code: " + event.code + "\n";
});
function sendMessage() {
const message = messageInput.value;
if (!message) return;
socket.send(message);
chatBox.value += "You: " + message + "\n";
messageInput.value = "";
}
function closeConnection() {
if (socket.readyState === WebSocket.OPEN) {
socket.close(1000, "The user closed the connection");
chatBox.value += "Connection closed by user\n";
} else {
alert("Connection not open or already closed.");
}
}
window.addEventListener("beforeunload", function () {
if (socket.readyState === WebSocket.OPEN) {
socket.close(1000, "The page is unloading");
}
});
</script>
</html>In the example above, as soon as you connect to the server, you can start sending messages and you will receive exactly what you have typed, echoed back to you. If you click the 'Close Connection' button, the WebSocket connection will be terminated, and you will no longer receive echoed messages.
Advanced WebSocket Features and Techniques
Sending Structured Data as JSON
Real apps rarely send plain strings — they send objects. Because the wire only carries text or binary, you serialize objects with JSON.stringify() before sending and parse them back with JSON.parse() on arrival. See Working with JSON for more on this format.
// Sending an object
const payload = { type: "chat", user: "Ann", text: "Hi!" };
socket.send(JSON.stringify(payload));
// Receiving and parsing it
socket.addEventListener("message", (event) => {
const msg = JSON.parse(event.data);
console.log(msg.user + ": " + msg.text); // "Ann: Hi!"
});A common pattern is a type field that lets one connection multiplex many kinds of messages — chat, presence, typing, and so on — each handled by its own branch.
Handling Binary Data
WebSockets are not limited to text. They can also carry binary frames, useful for audio, images, or game state. Set socket.binaryType to control how incoming binary arrives — "blob" (the default) or "arraybuffer".
socket.binaryType = "arraybuffer";
// Send raw bytes
const bytes = new Uint8Array([72, 73]); // "HI"
socket.send(bytes);
socket.addEventListener("message", (event) => {
if (typeof event.data === "string") {
console.log("text frame:", event.data);
} else {
const view = new Uint8Array(event.data);
console.log("binary frame, length:", view.length);
}
});Automatic Reconnection
Networks drop. The raw WebSocket does not reconnect on its own — when close fires unexpectedly, you must reopen the connection yourself, ideally with a growing (exponential) back-off so you do not hammer the server.
let delay = 1000; // start at 1 second
function connect() {
const socket = new WebSocket("wss://echo.websocket.events");
socket.addEventListener("open", () => {
delay = 1000; // reset back-off after a successful connection
});
socket.addEventListener("close", () => {
setTimeout(connect, delay);
delay = Math.min(delay * 2, 30000); // cap at 30 seconds
});
}
connect();Implementing WebSocket Security
Security is paramount when dealing with WebSockets:
- Use WSS: Always use WebSocket Secure (WSS), which encrypts the data transmitted between the client and server.
- Authentication: Implement token-based authentication to ensure that only authorized users can establish WebSocket connections.
- Validation: Properly validate all data sent to the server to prevent common web vulnerabilities such as XSS or SQL injection.
WebSocket and Pub/Sub Pattern
The publish/subscribe pattern is a popular model in real-time data services where messages are broadcast through a channel. WebSocket services like PubNub offer APIs that support the pub/sub model, enhancing the capabilities of WebSocket by managing connections, providing data encryption, and facilitating channel-based broadcasting.
WebSocket Libraries and Frameworks
Several JavaScript libraries make working with WebSockets easier and more robust:
- Socket.IO: Provides additional features like auto-reconnection, event handling, and room management.
- WebSocket-Node: A WebSocket server implementation for Node.js.
- ReconnectingWebSocket: A small library that adds reconnection features to plain WebSockets.
Conclusion
WebSocket technology is a fundamental building block for developing interactive, real-time web applications. By integrating WebSockets into your applications, you enable direct, two-way interaction between clients and servers. This guide walked through the connection lifecycle, the Echo Chat example, JSON and binary messages, reconnection, and security — enough to build robust real-time features.
See Also
- Fetch API — for one-off HTTP requests when you do not need a live channel.
- XMLHttpRequest — the older request API that WebSockets and Fetch build on conceptually.
- Push API — server-to-client messages even when the page is closed.
- Working with JSON — the standard format for structured WebSocket messages.