What Is a WebSocket and How Does It Differ from HTTP?
HTTP gets the job done for most of the web. You ask, the server answers, the connection closes. But for live chat, multiplayer games, stock tickers, and collaborative editors, that model breaks down. You cannot build a real-time feed by asking the server a question every second. WebSocket was designed to solve exactly this and understanding how it works explains a lot about why modern applications are built the way they are.
📋 What's in this article
The HTTP Request-Response Model
HTTP; the protocol that powers the web follows a simple pattern. A client sends a request. The server sends a response. The connection closes. Every interaction starts fresh. The server has no way to reach out to the client unless the client asks first.
This works perfectly for most of what the web does: loading a page, submitting a form, fetching data from an API, uploading a file. The client is always the initiator, the server always responds, and neither side needs to stay connected in between.
But some applications need something fundamentally different. A chat message does not wait for you to refresh the page. A stock price update does not need you to ask for it. A collaborative document edit from a remote user should appear on your screen immediately. In all of these cases, the server needs to push data to the client without waiting for a request. HTTP alone cannot do this cleanly.
What Is WebSocket?
WebSocket is a communication protocol that provides a persistent, full-duplex channel between a client and a server over a single TCP connection. Once the connection is established, both sides can send messages to each other at any time without either side having to wait for the other.
It is standardised in RFC 6455 and supported natively in every modern browser via the
WebSocket JavaScript API, as well as in server-side environments through libraries
in every major language; Node.js, Python, Go, Java, and others.
The key difference in one sentence
HTTP: client asks, server answers, connection closes.
WebSocket: client and server connect once, then both can talk whenever they want for as long as the connection stays open.
How a WebSocket Connection Works
A WebSocket connection starts as a regular HTTP request. The client sends a special HTTP upgrade request to the server asking to switch protocols. If the server supports WebSocket, it agrees and the connection is upgraded. From that point on, the TCP connection stays open and both sides communicate using the WebSocket protocol instead of HTTP.
Client sends an HTTP upgrade request
The initial request looks like a normal HTTP GET but includes special headers:
Upgrade: websocket and Connection: Upgrade.
This tells the server the client wants to switch to the WebSocket protocol.
Server responds with 101 Switching Protocols
If the server supports WebSocket, it responds with HTTP status 101 and the same upgrade headers. The HTTP phase is now complete and the protocol switches.
The connection stays open
The underlying TCP connection remains open. Both client and server can now send frames small packets of data to each other at any time. There is no request-response cycle. Either side initiates a message independently.
Either side closes the connection when done
When either party is finished, they send a close frame and the connection is terminated. Unlike HTTP, this does not happen after every message the connection can stay open for hours or days.
Because the connection starts as HTTP, WebSocket works through standard firewalls, proxies,
and load balancers that allow HTTP traffic. It uses the same port 80 (or 443 for secure connections).
The URL scheme uses ws:// for unencrypted and wss:// for encrypted connections,
analogous to http:// and https://.
HTTP vs WebSocket: A Direct Comparison
| HTTP | WebSocket | |
|---|---|---|
| Connection | Opens and closes per request | Persistent, stays open |
| Direction | Client initiates, server responds | Either side can send at any time |
| Overhead per message | High (full HTTP headers each time) | Low (small WebSocket frame headers) |
| Server push | Not natively supported | Built in |
| Latency | Higher (new connection setup each time) | Lower (connection already open) |
| Best for | Requests, responses, REST APIs, file transfers | Real-time data, live updates, bidirectional communication |
| Stateless | Yes | No, connection carries state |
| URL scheme | http:// / https:// |
ws:// / wss:// |
When to Use HTTP and When to Use WebSocket
The two protocols are not competitors. They solve different problems and most applications use both. HTTP handles the bulk of the work. WebSocket handles the parts that need to be live.
✅ Use HTTP for
Loading pages, fetching data, submitting forms, uploading files, REST API calls, authentication, anything that follows a request-response pattern, and anything where the client asks once and needs a single answer.
✅ Use WebSocket for
Live chat and messaging, multiplayer game state synchronisation, collaborative document editing, real-time dashboards and monitoring, live sports scores and financial data, push notifications, live code editors, and any feature where either the server or client needs to send data without waiting for the other to ask.
WebSocket in Code
The browser's native WebSocket API is straightforward. Here is a minimal example of a client connecting to a WebSocket server and exchanging messages.
Browser client (JavaScript)
// Connect to a WebSocket server
const socket = new WebSocket('wss://example.localto.net');
// Connection opened
socket.addEventListener('open', () => {
console.log('Connected');
socket.send(JSON.stringify({ type: 'hello', message: 'Hi from the browser' }));
});
// Receive messages from the server
socket.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log('Message from server:', data);
});
// Handle disconnection
socket.addEventListener('close', () => {
console.log('Connection closed');
});
// Send a message at any time
function sendMessage(text) {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ type: 'message', text }));
}
}
Server (Node.js with the ws library)
npm install ws
// server.js
const { WebSocketServer } = require('ws');
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', (socket) => {
console.log('Client connected');
socket.on('message', (data) => {
const message = JSON.parse(data);
console.log('Received:', message);
// Broadcast to all connected clients
wss.clients.forEach((client) => {
if (client.readyState === 1) { // WebSocket.OPEN
client.send(JSON.stringify({
type: 'broadcast',
text: message.text,
timestamp: Date.now()
}));
}
});
});
socket.on('close', () => {
console.log('Client disconnected');
});
});
console.log('WebSocket server running on ws://localhost:8080');
node server.js
Exposing a Local WebSocket Server with Localtonet
WebSocket connections start as HTTP and upgrade to the WebSocket protocol on the same connection.
Localtonet's HTTP tunnel handles this upgrade transparently it forwards the Upgrade header
and keeps the connection persistent, so wss:// connections to your tunnel URL
reach your local WebSocket server without any special configuration.
Start your WebSocket server locally
The Node.js example above runs on port 8080.
Start it and confirm it is listening.
Create an HTTP tunnel for port 8080
Go to the HTTP tunnel page,
set local IP to 127.0.0.1 and port to 8080.
Click Create and start the tunnel.
The dashboard shows a public HTTPS URL such as https://abc123.localto.net.
Connect using the wss:// scheme
Update your client to use the tunnel URL with the wss:// scheme.
The Localtonet relay terminates TLS and forwards the WebSocket frames to your local server.
// Replace ws://localhost:8080 with your tunnel URL using wss://
const socket = new WebSocket('wss://abc123.localto.net');
Remote clients, other browsers, mobile apps, or external services can now connect to your local WebSocket server from anywhere in the world. The connection is encrypted end-to-end using the tunnel's TLS certificate.
Most WebSocket servers also serve HTTP on the same port the upgrade happens on the same connection. A single Localtonet HTTP tunnel covers both. Your REST API endpoints and WebSocket connections both flow through the same tunnel URL.
Frequently Asked Questions
What is the difference between ws:// and wss://?
ws:// is unencrypted WebSocket, equivalent to http://. wss:// is WebSocket over TLS, equivalent to https://. Browsers block ws:// connections from HTTPS pages for security reasons, so in practice you almost always need wss:// for any production or publicly accessible setup. Localtonet HTTP tunnels use HTTPS, so clients must connect using wss://.
Is WebSocket better than HTTP for everything?
No. WebSocket is a persistent connection, which means server resources stay allocated for each connected client for the duration of the session. For applications with millions of occasional users, that resource cost adds up quickly. HTTP is stateless and scales more naturally for request-response workloads. Use WebSocket where the continuous connection adds real value live updates, bidirectional communication and HTTP everywhere else.
What is long polling and how does it compare to WebSocket?
Long polling is a workaround that simulates server push using HTTP. The client sends a request, the server holds it open until there is new data, then responds. The client immediately sends another request. It works but generates significant overhead a new HTTP connection for every update cycle. WebSocket eliminates this entirely by keeping one connection open. Long polling was common before WebSocket was widely supported; today there is rarely a reason to use it in new code.
What is Server-Sent Events and how does it compare?
Server-Sent Events (SSE) is a standard that lets a server push a continuous stream of data to the browser over a regular HTTP connection. It is simpler than WebSocket and works well for one-directional streams; news feeds, log tailing, AI response streaming. The key difference is that SSE is one-directional (server to client only), while WebSocket is bidirectional. For AI chat interfaces that stream responses, SSE is often a better fit than WebSocket because the client only needs to receive, not send continuously.
Do WebSocket connections work through firewalls and corporate proxies?
Usually yes, because the initial handshake looks like a normal HTTPS request on port 443. Most firewalls allow this. Some corporate HTTP proxies do not support the Upgrade header and will drop WebSocket connections. In those environments, libraries like Socket.IO fall back automatically to long polling, which works through any HTTP proxy. If you control the server, using wss:// on port 443 maximises compatibility.
Can I use WebSocket with frameworks like Socket.IO or Phoenix Channels?
Yes. Socket.IO (Node.js), Phoenix Channels (Elixir), Action Cable (Rails), and similar abstractions all use WebSocket as their primary transport. They add features on top rooms, namespaces, automatic reconnection, fallback transports. These higher-level frameworks work through Localtonet HTTP tunnels the same way raw WebSocket does, since the underlying upgrade mechanism is identical.
Share Your Local WebSocket App from Anywhere
Create a free Localtonet account, start your WebSocket server, open an HTTP tunnel,
and connect remote clients using the wss:// tunnel URL.
No deployment, no certificate setup, no proxy configuration.