SSE — what it is, Server-Sent Events and one-way streaming

Author: IT Sectr Published: 2026-06-02 Reading time: 8 min

SSE (Server-Sent Events) is a W3C standard that allows the server to send streaming data to the client over a single HTTP connection in one-way mode. Unlike WebSocket, SSE works over regular HTTP and does not require a special protocol or library on the client side. According to the W3C HTML Living Standard specification (2025), the EventSource API is supported in all modern browsers, including Chrome, Firefox, Safari and Edge.

Key Takeaways

  • SSE is a standard for one-way data transfer from server to client over an HTTP connection.
  • EventSource API is a built-in browser interface for receiving SSE without external libraries.
  • Automatic reconnection — the browser automatically restores the connection when it drops.
  • Text protocol — data is transmitted in text/event-stream format with a simple text format.
  • One-way communication — SSE is suitable for notifications, news feeds, tickers and monitoring, but not for chats.

What is SSE?

SSE (Server-Sent Events) is a technology that allows a web server to send data to the client at any time after establishing a connection. It is standardized by WHATWG as part of the HTML Living Standard and uses the MIME type text/event-stream. SSE supports transmitting text data with the ability to specify a message identifier, event type and reconnection delay.

Unlike WebSocket, which requires a bidirectional protocol and an upgrade request, SSE works over regular HTTP. The server sets the Content-Type: text/event-stream header, sends data in chunks and keeps the connection open. The client receives data through the browser's EventSource API, which automatically parses the stream and generates events.

According to CanIUse (2025), the EventSource API is supported in 97.5% of browsers globally. It is not supported in Internet Explorer and some mobile browsers (Samsung Internet before version 7.0). For these cases, there are polyfills that emulate EventSource via XHR streaming. SSE does not work with HTTP/1.1 pipelining but is fully compatible with HTTP/2 server push.

History and standardization

SSE was proposed as part of the HTML5 specification in 2009 under the name Server-Sent DOM Events. The first implementation appeared in Opera 9.0, then in Firefox 6.0 (2011), Chrome 9.0 (2011) and Safari 5.0 (2010). In 2015, the specification was moved to a separate section of the HTML Living Standard. Despite a decade-long history, SSE remains less popular than WebSocket due to its one-way nature.

How SSE works

How SSE works is as follows: the client creates an EventSource instance with the URL of the server endpoint. The browser sends a GET request with the Accept: text/event-stream header. The server responds with status 200 OK and the Content-Type: text/event-stream header, then starts sending data in event-stream format. The connection remains open until the server sends a terminate signal or the client calls close().

On the server side, data is sent in chunks (chunked transfer encoding). Each data chunk is a text message consisting of field lines (event, data, id, retry). The server can send messages at any time, making SSE ideal for notifications and status updates. The connection does not require constant heartbeat packet exchange (like WebSocket), although the retry field controls the reconnection frequency.

According to performance tests (2024), SSE provides throughput of up to 10,000 messages per second per connection with a message size of 256 bytes. On the server side, each SSE connection consumes approximately 5–10 KB of memory, allowing one server to support 50,000+ simultaneous connections with 1 GB RAM. This is significantly less than WebSocket due to the absence of a binary protocol.

Event-stream format

The text/event-stream format is a simple text protocol where each message consists of named fields separated by newline characters. Each field has the format “FieldName: value”. Messages are separated by two newline characters (\n\n).

Supported fields: event (event type, defaults to message), data (data string, can be multiline), id (last event identifier, stored in Last-Event-ID), retry (reconnection time in milliseconds). Comments start with a colon (:) and are ignored by the parser, but can be used for heartbeat.

FieldRequiredPurpose
eventNoEvent type (message by default)
dataYesMessage data string
idNoEvent identifier for Last-Event-ID
retryNoReconnection delay in ms

Event-stream example

text
: heartbeat comment
event: update
data: {"user": "Alice", "action": "typing"}
id: 1001

event: notification
data: {"type": "info", "text": "New version available"}
data: {"type": "action", "url": "/upgrade"}
retry: 3000

event: close
data: Session ended

EventSource API on the client

EventSource API is a built-in browser interface for receiving SSE. To create a connection, simply call the constructor with the endpoint URL. EventSource automatically establishes the connection, handles reconnection and parses incoming messages into JavaScript events.

EventSource events: open (connection established), message (message received without event specified), error (connection error). For custom events (event: custom), you can use addEventListener with the event name. EventSource automatically sends the Last-Event-ID header when reconnecting, allowing the server to resume the stream from where it was interrupted.

According to MDN documentation (2025), EventSource supports CORS and credential transmission (withCredentials). EventSource is not suitable for sending custom headers or request bodies — you need a manual implementation via fetch + ReadableStream. EventSource does not support binary data — only text and JSON.

Client-side JavaScript code

js
const eventSource = new EventSource('/api/events/stream');

eventSource.addEventListener('open', () => {
    console.log('SSE connection opened');
});

eventSource.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    console.log('Received:', data);
    renderUpdate(data);
});

eventSource.addEventListener('notification', (event) => {
    const notification = JSON.parse(event.data);
    showNotification(notification.text);
});

eventSource.addEventListener('error', (error) => {
    console.error('SSE error:', error);
    // Browser auto-reconnects
});

// Close connection
eventSource.close();

SSE vs WebSocket: comparison

SSE and WebSocket are different technologies for real-time communication, each with its own strengths. WebSocket is suitable for bidirectional data exchange (chats, games, collaborative editing), while SSE is for one-way streams from server to client (notifications, news feeds, tickers).

The key difference is that WebSocket requires an upgrade request from HTTP/1.1 to the WebSocket protocol (ws://), which can be blocked by corporate proxies. SSE works over regular HTTP, passes through any proxy and does not require special server configuration. SSE is also simpler to implement — the server does not need an additional library, just to form the HTTP response correctly.

According to comparative testing (2024), on a single server process SSE supports 30–50% more connections than WebSocket due to the simpler protocol. However, SSE has higher latency (50–200 ms vs 10–50 ms for WebSocket) because SSE uses chunked HTTP rather than a full bidirectional stream with binary frames.

CharacteristicSSEWebSocket
DirectionServer → clientBidirectional
ProtocolHTTP (text/event-stream)ws:// / wss:// (RFC 6455)
Browsers97.5% (built-in EventSource)97% (built-in WebSocket)
DataText / JSON onlyText + binary (Blob, ArrayBuffer)
Proxy handlingPasses through any proxyRequires proxy configuration
ReconnectionAutomatic (browser)Manual implementation
HistoryLast-Event-IDNo built-in history

How to implement SSE on the server

Implementing SSE on the server does not require libraries — just set the correct HTTP headers and send data in text/event-stream format. Let's look at an example in Node.js using the built-in http module. The server sets the Content-Type and Cache-Control headers, then sends messages every N seconds.

According to MDN Web Docs (2025), the required headers for SSE are: Content-Type: text/event-stream, Cache-Control: no-cache and Connection: keep-alive. Without Cache-Control, the browser may cache the SSE stream, which will stop delivery. Connection: keep-alive explicitly tells the browser to keep the connection open.

Server-side code in Node.js

js
const http = require('http');

http.createServer((req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });

    let eventId = 0;
    const interval = setInterval(() => {
        eventId++;
        res.write(`id: ${eventId}\n`);
        res.write(`event: update\n`);
        res.write(`data: {"time": "${new Date().toISOString()}", "id":${eventId}}\n\n`);
    }, 2000);

    req.on('close', () => {
        clearInterval(interval);
    });
}).listen(3000);

SSE in Python (Flask)

python
from flask import Response, Flask
import time
import json

app = Flask(__name__)

@app.route('/stream')
def stream():
    def generate():
        event_id = 0
        while True:
            event_id += 1
            data = json.dumps(
                {'ticker': 'AAPL', 'price': 150.25})
            yield f'id: {event_id}\nevent: price\ndata: {data}\n\n'
            time.sleep(1)
    return Response(generate(),
        mimetype='text/event-stream')

SSE in mobile applications

Using SSE in mobile applications is limited by the lack of native EventSource implementation for iOS and Android. On mobile platforms, SSE is implemented through third-party libraries: on iOS — via URLSession with NSURLProtocol, on Android — via OkHttp with SSE support (okhttp-sse). For React Native and Flutter, there are packages that emulate EventSource.

On iOS, native SSE implementation is possible via URLSessionDataDelegate. When receiving data in the urlSession(_:dataTask:didReceive:) method, the application accumulates a buffer and parses the event-stream format manually. According to iOS development blog (2024), battery consumption with SSE on iOS is 40% lower than with a constant WebSocket connection due to the absence of heartbeat packets.

On Android, OkHttp provides the EventSource.Factory class for subscribing to SSE streams. Android applications can use SSE for notifications when FCM is unavailable, or for data synchronization in the background. SSE on Android works well with WorkManager for long-lived background tasks. According to OkHttp documentation (2025), okhttp-sse supports automatic reconnection with a custom listener.

Frequently Asked Questions

How is SSE different from WebSocket?

SSE is one-way transmission (server → client) over HTTP, no libraries needed on the client. WebSocket is bidirectional transmission with a binary protocol. SSE is simpler to implement, WebSocket is suitable for tasks where the client also sends data.

Does SSE support binary data?

No, SSE only transmits text data. For binary data (images, audio), Base64 encoding is required, which increases the size by 33%. For binary streams, it is better to use WebSocket.

How does SSE handle connection drops?

EventSource automatically reconnects when a drop occurs. The delay time is set by the retry field in the stream (default 1000 ms). When reconnecting, the browser sends the Last-Event-ID header, allowing the server to restore the stream from where it was interrupted.

How many SSE connections can a browser hold?

Each browser has a limit on the number of simultaneous HTTP connections to one domain. For HTTP/1.1 — 6–8 connections per domain, for HTTP/2 — up to 100. SSE uses one connection, so there is no competition with other requests.

Can SSE be used for chat?

SSE is suitable only for receiving messages (incoming). To send messages (outgoing), a separate HTTP request (POST) is required. For a full-featured chat, it is more convenient to use WebSocket or Socket.IO with bidirectional communication in a single connection.

Summary

  • SSE is a standard for one-way data transfer from server to client over a regular HTTP connection without additional libraries.
  • EventSource API is a built-in browser interface supported by 97.5% of modern browsers.
  • Simple text protocol text/event-stream with event, data, id and retry fields.
  • Automatic reconnection with Last-Event-ID support for restoring the stream from where it was interrupted.
  • Efficiency — SSE supports more server connections (50,000+) compared to WebSocket due to the simpler protocol.
  • On mobile platforms SSE is implemented via OkHttp (Android) or URLSession (iOS) with manual stream parsing.
  • For one-way streams (notifications, feeds, tickers) choose SSE, for bidirectional communication — WebSocket or Socket.IO.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also