WebSocket vs Server-Sent Events

Meta Description: Need real-time updates in your API? Compare WebSocket and Server-Sent Events (SSE) to choose the right protocol for your use case. Keywords: websocket, server sent events, real-time api, sse vs websocket, push notifications, real-time communication Word Count: ~2,200 words Your API needs real-time updates. Users should see

TRY NANO BANANA FOR FREE

WebSocket vs Server-Sent Events

TRY NANO BANANA FOR FREE
Contents

Meta Description: Need real-time updates in your API? Compare WebSocket and Server-Sent Events (SSE) to choose the right protocol for your use case.

Keywords: websocket, server sent events, real-time api, sse vs websocket, push notifications, real-time communication

Word Count: ~2,200 words


Your API needs real-time updates. Users should see changes instantly without polling.

You have two main options: WebSocket and Server-Sent Events (SSE).

Both enable real-time communication, but they work differently and suit different use cases. Here's how to choose.

Quick Comparison

Feature WebSocket Server-Sent Events
Direction Bidirectional Server to client only
Protocol ws:// or wss:// HTTP/HTTPS
Data Format Binary or text Text (typically JSON)
Browser Support Excellent Excellent
Reconnection Manual Automatic
Complexity Higher Lower
Use Case Chat, gaming, collaboration Notifications, feeds, monitoring

Server-Sent Events: Simple Push

SSE is an HTTP-based protocol for server-to-client streaming. The server pushes updates over a long-lived HTTP connection.

How SSE Works

Client opens a connection:

const eventSource = new EventSource('https://api.petstoreapi.com/v1/pets/123/updates');

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Pet updated:', data);
};

eventSource.onerror = (error) => {
  console.error('Connection error:', error);
};

Server sends events:

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

data: {"id":"123","status":"ADOPTED","updatedAt":"2026-03-13T10:30:00Z"}

data: {"id":"123","status":"AVAILABLE","updatedAt":"2026-03-13T11:00:00Z"}

Each event starts with data: followed by the payload.

SSE Event Format

Simple event:

data: {"message":"Pet status changed"}

Multi-line event:

data: {
data:   "id": "123",
data:   "status": "ADOPTED"
data: }

Named event:

event: statusChanged
data: {"id":"123","status":"ADOPTED"}

Client listens for named events:

eventSource.addEventListener('statusChanged', (event) => {
  const data = JSON.parse(event.data);
  console.log('Status changed:', data);
});

Event with ID (for reconnection):

id: 1234
data: {"id":"123","status":"ADOPTED"}

If the connection drops, the client sends the last event ID when reconnecting:

GET /v1/pets/123/updates
Last-Event-ID: 1234

The server resumes from that point.

SSE Server Implementation

Node.js with Express:

app.get('/v1/pets/:id/updates', (req, res) => {
  const petId = req.params.id;

  // Set SSE headers
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  // Send initial event
  res.write(`data: ${JSON.stringify({ connected: true })}\n\n`);

  // Subscribe to pet updates
  const listener = (update) => {
    if (update.petId === petId) {
      res.write(`data: ${JSON.stringify(update)}\n\n`);
    }
  };

  petUpdateEmitter.on('update', listener);

  // Cleanup on disconnect
  req.on('close', () => {
    petUpdateEmitter.off('update', listener);
    res.end();
  });
});

Python with Flask:

from flask import Flask, Response
import json
import time

app = Flask(__name__)

@app.route('/v1/pets/<pet_id>/updates')
def pet_updates(pet_id):
    def generate():
        # Send initial event
        yield f"data: {json.dumps({'connected': True})}\n\n"

        # Send updates
        while True:
            update = get_pet_update(pet_id)
            if update:
                yield f"data: {json.dumps(update)}\n\n"
            time.sleep(1)

    return Response(generate(), mimetype='text/event-stream')

SSE Strengths

1. Simple to implement

SSE uses standard HTTP. No special protocol or library needed. The browser's EventSource API handles everything.

2. Automatic reconnection

If the connection drops, the browser automatically reconnects. You don't write reconnection logic.

3. Works with HTTP/2

SSE benefits from HTTP/2 multiplexing. Multiple SSE connections share one TCP connection.

4. Built-in event IDs

SSE has built-in support for resuming from the last received event. No custom logic needed.

5. Firewall-friendly

SSE uses standard HTTP/HTTPS. It works through corporate firewalls and proxies that block WebSocket.

SSE Weaknesses

1. Server to client only

SSE is one-way. Clients can't send messages over the SSE connection. They must use separate HTTP requests.

2. Text only

SSE sends text data. Binary data must be base64-encoded, which increases size.

3. Connection limits

Browsers limit concurrent HTTP connections per domain (typically 6). Each SSE connection counts toward this limit.

HTTP/2 helps, but the limit still exists.

4. No built-in compression

SSE doesn't compress messages automatically. You must compress data before sending.

When to Use SSE

Notifications: Push notifications, alerts, status updates Live feeds: News feeds, social media updates, activity streams Monitoring: Server metrics, log streaming, dashboard updates Progress tracking: File uploads, batch processing, long-running tasks

Use SSE when: - Updates flow from server to client - You don't need bidirectional communication - Simplicity matters - You want automatic reconnection

WebSocket: Bidirectional Communication

WebSocket provides full-duplex communication. Both client and server can send messages anytime.

How WebSocket Works

Client connects:

const ws = new WebSocket('wss://api.petstoreapi.com/v1/ws');

ws.onopen = () => {
  console.log('Connected');
  ws.send(JSON.stringify({ type: 'subscribe', petId: '123' }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
};

ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};

ws.onclose = () => {
  console.log('Disconnected');
};

Server handles connections:

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws) => {
  console.log('Client connected');

  ws.on('message', (message) => {
    const data = JSON.parse(message);

    if (data.type === 'subscribe') {
      // Subscribe client to pet updates
      subscribeToPet(ws, data.petId);
    }
  });

  ws.on('close', () => {
    console.log('Client disconnected');
  });
});

function subscribeToPet(ws, petId) {
  petUpdateEmitter.on('update', (update) => {
    if (update.petId === petId) {
      ws.send(JSON.stringify(update));
    }
  });
}

WebSocket Protocol

WebSocket starts with an HTTP upgrade request:

GET /v1/ws HTTP/1.1
Host: api.petstoreapi.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

Server responds:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

After the handshake, the connection switches to WebSocket protocol. Both sides can send messages.

WebSocket Strengths

1. Bidirectional

Both client and server send messages anytime. No need for separate HTTP requests.

2. Low latency

WebSocket has minimal overhead. Messages arrive faster than HTTP requests.

3. Binary support

WebSocket handles binary data natively. No base64 encoding needed.

4. Efficient

After the initial handshake, WebSocket frames have minimal overhead (2-14 bytes per message).

5. No connection limits

WebSocket connections don't count toward browser HTTP connection limits.

WebSocket Weaknesses

1. More complex

WebSocket requires: - Handshake handling - Frame parsing - Ping/pong for keep-alive - Manual reconnection logic - State management

2. No automatic reconnection

If the connection drops, you must reconnect manually:

function connectWebSocket() {
  const ws = new WebSocket('wss://api.petstoreapi.com/v1/ws');

  ws.onclose = () => {
    console.log('Disconnected, reconnecting...');
    setTimeout(connectWebSocket, 1000);
  };

  return ws;
}

3. Firewall issues

Some corporate firewalls and proxies block WebSocket. You need fallback mechanisms.

4. Scaling challenges

WebSocket connections are stateful. Scaling requires: - Sticky sessions (route clients to the same server) - Or shared state (Redis, database) - Or message brokers (RabbitMQ, Kafka)

When to Use WebSocket

Chat applications: Real-time messaging, group chat Collaborative editing: Google Docs-style collaboration Gaming: Multiplayer games, real-time game state Trading platforms: Live price updates, order execution IoT: Device control, sensor data streaming

Use WebSocket when: - You need bidirectional communication - Low latency is critical - You're sending binary data - Clients send frequent updates

Combining Both

You don't have to choose one. Use both for different features.

Example: Pet adoption platform

SSE for notifications:

// Receive notifications
const notifications = new EventSource('/v1/notifications');
notifications.onmessage = (event) => {
  showNotification(JSON.parse(event.data));
};

WebSocket for chat:

// Real-time chat with adoption coordinator
const chat = new WebSocket('wss://api.petstoreapi.com/v1/chat');
chat.onmessage = (event) => {
  displayMessage(JSON.parse(event.data));
};

// Send messages
sendButton.onclick = () => {
  chat.send(JSON.stringify({ message: messageInput.value }));
};

SSE handles one-way notifications. WebSocket handles bidirectional chat. Each protocol does what it does best.

Decision Framework

Choose SSE if: - Updates flow from server to client only - You want simplicity and automatic reconnection - You need to work through restrictive firewalls - You're building notifications, feeds, or monitoring

Choose WebSocket if: - You need bidirectional communication - Low latency is critical - You're sending binary data - You're building chat, gaming, or collaboration features

Use both if: - Different features have different requirements - You want the best tool for each job

Modern PetStore API Example

The Modern PetStore API supports both:

SSE for pet status updates:

GET /v1/pets/123/updates

Streams status changes, adoption updates, and medical records.

WebSocket for real-time chat:

wss://api.petstoreapi.com/v1/chat

Enables real-time communication between adopters and shelter staff.

Each protocol serves its purpose. The API is more flexible and performant as a result.


Key Takeaway: SSE is simpler for server-to-client updates. WebSocket is more powerful for bidirectional communication. Choose based on your requirements, not trends.

Real-time doesn't always mean WebSocket. Often, SSE is the better choice.