Question

WebSockets vs Server-Sent Events (EventSource): Differences, Use Cases, and When to Choose Each

htmlbrowserwebsocketserver-sent-events

Question

Both WebSockets and Server-Sent Events (SSE, via EventSource) can push data from a server to a browser. They appear to solve similar problems.

What are the practical differences between WebSockets and Server-Sent Events?

When should you choose one over the other?

Please focus on factual, technical differences such as communication model, protocol behavior, browser support considerations, and common use cases.

Short Answer

By the end of this page, you will understand how WebSockets and Server-Sent Events (SSE) differ, what problem each one solves best, and how to choose the right option for real applications. You will also see simple JavaScript examples, common mistakes, and a small project that demonstrates server-to-browser streaming with SSE.

Concept

WebSockets and Server-Sent Events are both used for real-time communication between a browser and a server, but they are not the same tool.

WebSockets

WebSockets provide a full-duplex connection. That means:

  • the client can send messages to the server
  • the server can send messages to the client
  • both directions can happen over the same long-lived connection

A WebSocket connection begins as an HTTP request and then upgrades to the WebSocket protocol. After that upgrade, communication is no longer normal HTTP request/response.

This makes WebSockets a strong choice for features like:

  • chat apps
  • multiplayer games
  • collaborative editing
  • live dashboards where clients also send frequent updates

Server-Sent Events (SSE)

SSE is designed for one-way streaming from server to browser over regular HTTP. The browser opens a connection using EventSource, and the server keeps sending text-based events over time.

With SSE:

  • the server can push updates to the browser
  • the browser does not send messages back through the same SSE connection
  • if the browser needs to send data, it uses normal HTTP requests such as fetch() or form submissions

SSE is often a good fit for:

  • notifications
  • live news feeds
  • status updates
  • log streaming
  • progress updates

Why this matters

Choosing the wrong tool can add complexity.

  • If you only need server → browser updates, SSE is often simpler.
  • If you need two-way low-latency messaging, WebSockets are usually the better choice.

Key factual difference

The biggest conceptual difference is:

  • WebSockets: two-way persistent messaging
  • SSE: one-way server-to-client event stream

That single difference influences architecture, error handling, scaling, and implementation details in real systems.

Mental Model

Think of these two technologies like communication channels:

  • WebSocket is like a phone call. Both sides can talk at any time.
  • SSE is like a radio broadcast. The server keeps talking, and the browser listens.

If your app only needs to listen for updates, a radio broadcast is simpler. If your app needs a conversation, you need the phone call.

Take Quiz

Syntax and Examples

WebSocket in JavaScript

const socket = new WebSocket('ws://localhost:3000');

socket.addEventListener('open', () => {
  console.log('Connected');
  socket.send('Hello server');
});

socket.addEventListener('message', (event) => {
  console.log('Received:', event.data);
});

socket.addEventListener('close', () => {
  console.log('Connection closed');
});

This creates a persistent two-way connection. The browser can both send and receive messages.

Server-Sent Events in JavaScript

const source = new EventSource('/events');

source.addEventListener('message', (event) => {
  console.log('Update:', event.data);
});

source.addEventListener('error', (error) => {
  console.error('SSE error:', error);
});

This opens a one-way stream from the server to the browser. The browser listens for updates, but does not send messages through EventSource.

Example: sending data back when using SSE

const source = new EventSource('/events');

source.onmessage = (event) => {
  console.log('Server says:', event.data);
};

async function sendPreference() {
  await fetch('/preferences', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ theme: 'dark' })
  });
}

With SSE, sending data back usually happens through separate HTTP requests.

Minimal SSE server format

An SSE response must be sent with the correct content type and event format:

data: Hello client

Each event ends with a blank line. The data: prefix is required for standard message data.

Step by Step Execution

Consider this SSE example:

const source = new EventSource('/events');

source.onmessage = (event) => {
  console.log('Message from server:', event.data);
};

Here is what happens step by step:

  1. new EventSource('/events') tells the browser to open an HTTP connection to /events.

  2. The server responds with headers such as:

    Content-Type: text/event-stream
    Cache-Control: no-cache
    Connection: keep-alive
    
  3. The server keeps the connection open instead of ending the response.

  4. When the server writes:

    data: Build complete
    
    

    the browser receives one SSE message.

  5. The browser triggers source.onmessage.

  6. event.data contains the string Build complete.

  7. If the connection drops, the browser will usually try to reconnect automatically.

Now compare that with WebSocket:

const socket = new WebSocket('ws://localhost:3000');

socket.onopen = () => {
  socket.send('ping');
};

socket.onmessage = (event) => {
  console.log(event.data);
};

Step by step:

  1. The browser starts with an HTTP request that asks to upgrade the connection.
  2. If the server accepts, the protocol switches to WebSocket.
  3. The browser gets the open event.
  4. The client sends ping over the socket.
  5. The server can reply with a message.
  6. The browser receives the message in onmessage.
  7. Either side can continue sending more messages until the connection closes.

The important difference is that SSE is a stream of server events, while WebSocket is an ongoing conversation.

Real World Use Cases

Good use cases for SSE

SSE is usually a strong choice when updates only need to flow from the server to the browser:

  • Notifications: new alerts, messages, or reminders
  • Live logs: deployment logs, job output, monitoring streams
  • Status updates: background task progress, queue progress, report generation
  • News or price tickers: simple feed-style updates
  • Admin dashboards: server health, counts, or activity feeds

Good use cases for WebSockets

WebSockets are better when both sides need to send data frequently or with low latency:

  • Chat applications
  • Multiplayer games
  • Collaborative editors
  • Real-time whiteboards
  • Trading interfaces where the client also sends actions quickly
  • Remote control systems where commands and updates happen continuously

Rule of thumb

  • Choose SSE for simple server push.
  • Choose WebSocket for interactive two-way communication.
Take Quiz

Real Codebase Usage

In real projects, developers usually choose based on communication direction, infrastructure, and simplicity.

Common SSE patterns

  • Streaming background job progress
  • Pushing notifications after database changes
  • Sending log lines to an admin page
  • Keeping implementation simple using standard HTTP

A common pattern is:

  1. Browser opens an EventSource
  2. Server emits updates as events
  3. Browser sends user actions back separately with fetch()

This works well when the app does not need a custom bidirectional protocol.

Common WebSocket patterns

  • Message hubs for chat rooms
  • Publish/subscribe systems for real-time channels
  • Presence tracking such as online/offline users
  • Low-latency event handling for collaborative apps

Related codebase patterns

Guard clauses

When handling incoming WebSocket messages, code often validates the message early:

function handleMessage(raw) {
  let message;

  try {
    message = JSON.parse(raw);
  } catch {
    return;
  }

  if (!message.type) return;

  // process valid message
}

Validation

WebSocket servers often validate every incoming message because clients can send arbitrary data.

SSE usually reduces this complexity because the browser is only consuming events.

Error handling

  • SSE often relies on built-in reconnection behavior.
  • WebSocket apps often implement custom reconnect logic, heartbeat checks, and retry backoff.

Configuration

In production, teams also consider:

  • reverse proxy support
  • timeouts
  • load balancer behavior
  • connection limits
  • message format choices such as plain text or JSON

Common Mistakes

1. Using WebSockets when SSE is enough

If the browser only needs to receive updates, WebSockets may add unnecessary complexity.

Better choice: use SSE for one-way event streams.

2. Expecting SSE to send client messages

This is a very common misunderstanding.

Broken expectation:

const source = new EventSource('/events');
source.send('hello'); // ❌ EventSource does not have send()

EventSource is receive-only.

3. Forgetting the correct SSE response format

Broken SSE output:

Hello client

Correct SSE output:

data: Hello client

The data: field and blank line are important.

4. Assuming WebSockets are just faster HTTP

WebSockets are a different protocol after the upgrade. They are not the same as repeatedly calling fetch().

5. Ignoring reconnection behavior

SSE clients often reconnect automatically. Beginners sometimes forget this and accidentally duplicate state handling.

6. Not handling connection close events in WebSockets

Broken example:

const socket = new WebSocket('ws://localhost:3000');
socket.onmessage = (event) => console.log(event.data);

This receives data, but has no logic for disconnects, retries, or errors.

7. Sending the wrong data format

For WebSockets, teams often send JSON. If you expect JSON, parse and validate it carefully.

socket.onmessage = (event) => {
  const data = JSON.parse(event.data); // can throw if invalid
  console.log(data);
};

Safer version:

socket.onmessage = (event) => {
  try {
    const data = JSON.parse(event.data);
    console.log(data);
  } catch (error) {
    console.error('Invalid JSON:', error);
  }
};

Comparisons

FeatureWebSocketsServer-Sent Events (SSE)
Communication directionTwo-wayServer to client only
ProtocolWebSocket protocol after HTTP upgradeStandard HTTP streaming
Browser APIWebSocketEventSource
Client can send messages on same connectionYesNo
Server can push updatesYesYes
Message formatBinary or textText-based event stream
Auto-reconnect supportUsually customTypically built in by browser
SimplicityMore complexSimpler for one-way updates
Good for chat/collaborationYesUsually no
Good for notifications/log streamsCan workExcellent fit

SSE vs polling

ApproachHow it worksBest for
PollingBrowser repeatedly asks for updatesSimple systems with low update frequency
SSEServer pushes updates over one open HTTP responseReal-time server-to-client updates
WebSocketPersistent two-way channelInteractive real-time apps

Which should you choose?

  • Use SSE if:

    • updates flow mostly from server to browser
    • you want simpler implementation
    • text-based event streams are enough
  • Use WebSockets if:

    • both sides need to send frequent messages
    • low-latency interaction matters
    • your app behaves more like a conversation than a feed
Take Quiz

Cheat Sheet

Quick decision

  • Need server → browser only? Use SSE.
  • Need browser ↔ server both ways? Use WebSocket.

WebSocket basics

const socket = new WebSocket('ws://localhost:3000');
socket.send('hello');
socket.onmessage = (event) => console.log(event.data);
  • Persistent two-way connection
  • Supports text and binary data
  • Requires connection upgrade
  • Usually needs custom reconnect logic

SSE basics

const source = new EventSource('/events');
source.onmessage = (event) => console.log(event.data);
  • One-way server-to-client stream
  • Built on HTTP
  • Text-based only
  • Browser usually handles reconnection automatically

SSE event format

data: some message

Optional fields can include:

event: status
data: done
id: 42

Common rules

  • EventSource cannot send data back
  • WebSockets can send and receive on the same connection
  • SSE is often easier for notifications, logs, and progress updates
  • WebSockets are better for chat, collaboration, and game state

Watch out for

  • connection timeouts in proxies
  • reconnection behavior
  • duplicate event handling after reconnect
  • validating incoming WebSocket messages

FAQ

What is the main difference between WebSockets and SSE?

WebSockets support two-way communication, while SSE only sends events from the server to the browser.

Is SSE faster than WebSockets?

Not in a universal sense. SSE can be simpler and efficient for one-way updates, while WebSockets are better suited for continuous two-way messaging.

Can Server-Sent Events replace WebSockets?

Only when your app needs server-to-client updates only. If the client must send frequent real-time messages, SSE is not a full replacement.

Can I send data from the browser when using SSE?

Yes, but not through the EventSource connection. You usually send data with fetch() or another HTTP request.

Are WebSockets over HTTP?

A WebSocket connection starts with HTTP, then upgrades to the WebSocket protocol.

Do Server-Sent Events reconnect automatically?

In many cases, yes. Browsers typically try to reconnect automatically when the stream is interrupted.

Should I use SSE for chat applications?

Usually no. Chat needs two-way communication, so WebSockets are generally a better fit.

Is SSE text-only?

Yes, SSE sends text-based event data. If needed, structured data is commonly sent as JSON strings.

Take Quiz

Mini Project

Description

Build a small real-time status feed where the browser receives live updates from the server using Server-Sent Events. This demonstrates when SSE is a good fit: the server pushes information continuously, and the browser only needs to listen.

Goal

Create a page that shows a stream of server-generated messages in real time using EventSource.

Requirements

  1. Create an HTTP endpoint that returns an SSE stream.
  2. Send a new message from the server every few seconds.
  3. Create a browser page that connects with EventSource.
  4. Display each incoming message in a list on the page.
  5. Handle connection errors in the browser.
Take Quiz

Keep learning

Related questions

View more