REST is request-response. You ask, server answers, connection closes. Works fine for most things.
But chat messages can’t wait for you to ask. Stock prices need to push the moment they change. Notifications should appear, not be polled for.
Two options: WebSockets and Server-Sent Events. Different tools, different trade-offs.
The Quick Answer
WebSockets: Two-way communication. Client and server can both send anytime. Use for chat, games, collaborative editing.
Server-Sent Events (SSE): One-way. Server pushes to client. Use for notifications, live feeds, dashboards.
If you only need server-to-client, use SSE. It’s simpler.
WebSockets
Full duplex. Once connected, either side can send messages whenever.
// Client
const socket = new WebSocket('ws...
REST is request-response. You ask, server answers, connection closes. Works fine for most things.
But chat messages can’t wait for you to ask. Stock prices need to push the moment they change. Notifications should appear, not be polled for.
Two options: WebSockets and Server-Sent Events. Different tools, different trade-offs.
The Quick Answer
WebSockets: Two-way communication. Client and server can both send anytime. Use for chat, games, collaborative editing.
Server-Sent Events (SSE): One-way. Server pushes to client. Use for notifications, live feeds, dashboards.
If you only need server-to-client, use SSE. It’s simpler.
WebSockets
Full duplex. Once connected, either side can send messages whenever.
// Client
const socket = new WebSocket('wss://example.com/socket');
socket.onopen = () => {
socket.send(JSON.stringify({ type: 'subscribe', channel: 'chat' }));
};
socket.onmessage = (event) => {
const message = JSON.parse(event.data);
displayMessage(message);
};
// Send a message
function sendChat(text) {
socket.send(JSON.stringify({ type: 'chat', text }));
}
The connection stays open. Messages flow both directions.
Good for:
- Chat applications
- Multiplayer games
- Collaborative tools (multiple users editing)
- Anything where clients send frequent messages
Annoying parts:
- You handle reconnection yourself
- Some proxies/firewalls don’t like long-lived connections
- More complex server infrastructure
Server-Sent Events
One direction: server to client. Built on regular HTTP.
// Client
const events = new EventSource('/api/notifications');
events.onmessage = (event) => {
const notification = JSON.parse(event.data);
showNotification(notification);
};
// That's it. Browser handles reconnection automatically.
// Server (Express)
app.get('/api/notifications', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// Send data whenever you want
const send = (data) => {
res.write(`data: ${JSON.stringify(data)}\n\n`);
};
send({ type: 'connected' });
// Clean up when client disconnects
req.on('close', () => {
// Remove from active connections
});
});
Good for:
- Live notifications
- Activity feeds
- Dashboards and metrics
- Stock tickers
- Any "subscribe and receive updates" pattern
Why it’s nice:
- Automatic reconnection built in
- Works through most proxies
- Just HTTP — nothing special to deploy
- Simpler server code
Side by Side
| Aspect | WebSockets | SSE |
|---|---|---|
| Direction | Both ways | Server to client |
| Protocol | Custom (ws://) | Regular HTTP |
| Reconnection | Manual | Automatic |
| Binary data | Yes | Text only |
| Complexity | Higher | Lower |
| Proxy support | Sometimes problematic | Usually fine |
When Polling Is Actually Fine
Real-time tech has overhead. Sometimes polling is the right call:
- Updates are infrequent (minutes apart)
- You can’t maintain persistent connections
- Simplicity matters more than immediacy
Polling every 30 seconds for weather data? Totally reasonable. Don’t overcomplicate it.
Combining SSE with REST
You don’t have to pick one protocol for everything. Common pattern:
- SSE for receiving updates (server → client)
- REST for sending actions (client → server)
// Receive notifications via SSE
const events = new EventSource('/api/feed');
events.onmessage = handleUpdate;
// Send actions via REST
async function postComment(text) {
await fetch('/api/comments', {
method: 'POST',
body: JSON.stringify({ text })
});
// Server broadcasts update to all SSE clients
}
Simpler than WebSockets, covers most use cases.
Getting Real-Time Data
You need something to stream. Options:
- Your own data — Database changes, user actions, internal events
- External APIs — Pull from data sources, push to your clients
For the second one, you poll the API and broadcast to connected clients:
// Poll external API, push to clients
setInterval(async () => {
const weather = await fetch('https://api.apiverve.com/v1/weatherforecast?city=NYC', {
headers: { 'x-api-key': process.env.API_KEY }
}).then(r => r.json());
broadcastToClients({ type: 'weather', data: weather.data });
}, 60000); // Every minute
You absorb the polling. Users get real-time feel.
Scaling
One server, simple. Multiple servers, slightly harder.
Problem: User connects to Server A, but the event happens on Server B.
Solution: Pub/sub. Redis is common:
// When event happens (any server)
redis.publish('notifications', JSON.stringify({ userId, data }));
// All servers subscribe
redis.subscribe('notifications');
redis.on('message', (channel, message) => {
const { userId, data } = JSON.parse(message);
sendToUser(userId, data); // If they're connected to this server
});
Event goes to Redis, all servers hear it, the one with the connection delivers it.
Making the Choice
Start with SSE if:
- Users primarily receive updates
- You want simpler infrastructure
- Automatic reconnection matters
Use WebSockets if:
- High-frequency bidirectional messages
- Binary data needed
- Building games or collaborative editing
Stick with polling if:
- Updates are infrequent
- You’re optimizing for simplicity
- Real-time isn’t actually required
Most "real-time" features are actually SSE use cases masquerading as WebSocket projects. Start simple, upgrade if you actually need bidirectional.
For data to stream, check the APIVerve marketplace — weather, currency, stocks. Pull from APIs, push to your users.
Originally published at APIVerve Blog