Fact-checked by Grok 2 weeks ago

Server-sent events

Server-Sent Events (SSE) is a web technology standard that enables a server to push real-time updates to a over a persistent HTTP connection, allowing for unidirectional communication from server to client without requiring the browser to repeatedly poll the server. Introduced as part of , SSE uses the EventSource interface in to establish this connection, where the server responds with the MIME type text/event-stream and sends data as encoded text lines formatted into events. Each event consists of optional fields such as event (specifying the event type), data (the message content, which can span multiple lines), id (a for reconnection), and retry (custom reconnection timeout in milliseconds), terminated by a blank line to trigger dispatching as a MessageEvent. The technology supports automatic reconnection with in case of network failures, sending the last known event ID via the Last-Event-ID header to resume from the correct point, ensuring reliable delivery of updates like live news feeds, stock prices, or chat notifications. Unlike bidirectional protocols such as WebSockets, SSE is simpler and leverages standard HTTP features like redirects (/307) and caching directives, but it is limited to one-way data flow and typically supports up to six concurrent connections per browser and domain (excluding multiplexing). SSE is widely supported across modern browsers, including since version 26, since 11, since 5.0, and since 79, with polyfills available for older environments. In practice, client-side implementation involves creating an EventSource object with a URL to the event stream endpoint, registering event listeners (e.g., addEventListener('message', handler) for default messages or custom types like 'ping'), and handling errors via the onerror callback, while server-side scripts must flush output regularly and include periodic comments (e.g., ':' lines) to prevent proxy timeouts. As a W3C Recommendation since 2015, SSE provides a lightweight alternative to more complex real-time technologies, particularly suited for scenarios where the server initiates updates and low latency is needed without full-duplex communication.

Overview

Definition and purpose

Server-sent events (SSE) is a web standard that enables servers to push real-time updates to web browsers via a long-lived HTTP connection, allowing for efficient, unidirectional data transmission from server to client. Defined in the HTML Living Standard by the , SSE introduces the EventSource interface, which facilitates the reception of server-initiated notifications as DOM events without the need for client polling or full page reloads. This leverages the text/event-stream type to stream events over standard HTTP, making it compatible with existing web infrastructure. The primary purpose of is to support dynamic, live content delivery in web applications, such as news tickers, live stock price updates, or instant notifications, by permitting servers to send data asynchronously as it becomes available. Unlike traditional request-response models, SSE reduces and usage by maintaining an open connection through which the server can dispatch events at any time, optimizing for scenarios where real-time information flow is essential but bidirectional communication is not required. This approach contrasts with emulated techniques like polling, allowing user agents to better manage network resources and extend battery life on mobile devices. Key benefits of SSE include its straightforward setup using familiar HTTP mechanisms, built-in automatic reconnection upon connection failure, and inherent support for event parsing directly in the browser without custom protocol handling. Emerging around as part of efforts, SSE was developed as a simple, lightweight option for server-push functionality, serving as an accessible alternative to more resource-intensive bidirectional protocols in unidirectional update use cases.

Key characteristics

Server-sent events (SSE) establish a unidirectional communication channel, allowing servers to push data to clients over HTTP without enabling client-to-server messaging on the same connection. This design simplifies real-time updates by focusing solely on server-initiated streams, making it suitable for scenarios like live notifications or progress reporting. SSE maintains a persistent, long-lived HTTP that remains open for the duration of the stream, with clients automatically attempting reconnection upon failure after a delay equal to the reconnection time (initially implementation-defined, typically around 3 seconds), and user agents possibly applying for subsequent failures if the previous attempt failed. This persistence reduces the need for repeated connection setups, enhancing reliability for ongoing data delivery. The protocol uses a text-based format where events are transmitted as UTF-8 encoded lines, delimited by newlines in a structured key-value format (e.g., "data:", "event:", "id:"). This newline-delimited structure supports named event types, such as the default "message" or custom types, along with optional ID fields that enable clients to resume interrupted streams from the last acknowledged event.

Technical specification

Connection mechanism

Server-sent events (SSE) connections are initiated by the client using the in , where a developer creates an instance with const eventSource = new EventSource('/events');. This triggers a GET request to the specified , including the Accept: text/event-stream header to indicate the client's intent to receive an event stream, along with a mode of no-store to prevent caching of the response. Upon receiving the request, the server must respond with an HTTP 200 OK status and set the Content-Type: text/event-stream header to confirm the stream format, while also including Cache-Control: no-cache to ensure the connection remains fresh and avoids intermediary caching. The response uses a persistent HTTP connection, typically over HTTP/1.1 with Connection: keep-alive, though it can upgrade to or later protocols if supported by the client and server, falling back to HTTP/1.1 streaming for compatibility. The lifecycle begins in the CONNECTING state (readyState 0) upon initiation, transitions to OPEN (readyState 1) once the stream is established, allowing events to be dispatched, and ends in CLOSED (readyState 2) on termination. To maintain the and prevent timeouts from proxies or load balancers, servers periodically send heartbeat messages as comment lines prefixed with a single colon (:) followed by optional whitespace, recommended at intervals of about 15 seconds. SSE includes built-in reconnection logic: if the connection closes unexpectedly, the client automatically attempts to reconnect after the reconnection time (an implementation-defined value, typically a few seconds), optionally waiting longer with if the previous attempt failed. During reconnection, the client includes the Last-Event-ID header with the ID of the last received , enabling the server to resume the stream from that point if supported. Developers can set a custom reconnection time by including a retry: field in the event stream, specified in milliseconds as a base-ten . Error handling in SSE triggers the onerror event for issues such as network failures or invalid responses, after which the connection closes and enters the CLOSED state. The client does not reconnect for fatal errors like or 500 status codes, but retries for transient issues like network interruptions, with reconnection suppressed if the developer calls eventSource.close() or if retries are deemed futile after multiple failures.

Event stream protocol

The event stream protocol for Server-Sent Events (SSE) defines a simple, text-based format for transmitting unidirectional updates from server to client over a persistent HTTP . The is encoded exclusively in and uses newline-separated fields to structure each event, with events delimited by two consecutive newlines (a blank line). This format allows the server to send a continuous sequence of events without closing the connection, enabling real-time push notifications. The protocol supports only text data, precluding binary payloads, and relies on standard HTTP headers like Content-Type: text/event-[stream](/page/Stream) to initiate the . Each event consists of zero or more field lines, where fields are identified by a name followed by a colon and space (e.g., "field: value"), followed by the end-of-line marker (CRLF, LF, or CR). The recognized fields are "event:", "data:", "id:", and "retry:". The "data:" field carries the event's payload, which can extend across multiple lines; additional "data:" lines are concatenated to the previous data with an intervening newline. The "event:" field specifies the event type as a string (e.g., "update" or "error"), defaulting to "message" if absent or empty. The "id:" field assigns a to the event, which must not contain null bytes (U+0000), line feeds (U+000A), or carriage returns (U+000D), and is used by clients for reconnection and last-event tracking. The "retry:" field, if consisting only of ASCII digits, sets the reconnection time to the parsed base-ten value in milliseconds; otherwise, it is ignored. The initial reconnection time is implementation-defined. Unknown fields are discarded during parsing. Parsing occurs line by line after UTF-8 decoding and removal of any leading (BOM). The client buffers fields until a blank line is encountered, at which point the accumulated data dispatches as a complete ; standalone blank lines or those following a complete event are ignored. Lines beginning with a single colon (":") are treated as comments and skipped, providing a for server-side annotations without affecting the stream. For multi-line "data:" fields, a line that starts without a field name (i.e., indented or empty after the colon in prior lines) continues the data accumulation. This line-oriented approach ensures robust handling of varying conventions across systems. The protocol's design prioritizes simplicity and compatibility with HTTP, supporting payloads in plain text or structured formats like within "data:" lines (e.g., data: {"key": "value"}). For illustration, a sample event stream might appear as:
event: [update](/page/Update)
data: Current [temperature](/page/Temperature): 22°C
data: Location: Living room

id: 123
data: Alert: Door opened
retry: 5000
Here, the first event is of type "" with multi-line , followed by a "" event with and custom retry. Event sizes are constrained by implementations and HTTP limits, with no support for due to the text-only encoding.

Client-side handling

Client-side handling of server-sent events (SSE) primarily occurs through the EventSource interface in web browsers, which provides a standardized for establishing and managing persistent connections to receive event streams from a server. This interface allows developers to create an EventSource object by passing the URL of the event stream endpoint, optionally with configuration options such as credentials for cross-origin requests. The EventSource API exposes several key properties for inspecting the connection state. The [url](/page/URL) property returns the absolute URL of the event source as a read-only string, while withCredentials is a read-only indicating whether credentials (such as cookies or HTTP ) are included in cross-origin requests, defaulting to false unless specified in the constructor. The readyState property, also read-only, reflects the current connection status as an unsigned short integer: 0 for (initializing or reconnecting), 1 for OPEN (connection established and events being dispatched), and 2 for CLOSED (connection terminated). These properties enable developers to monitor and respond to the lifecycle of the SSE connection without additional polling. Event handling is facilitated through event listeners and dedicated handler properties. The onmessage property sets a callback for the default 'message' event, which fires when the server sends data without a specific event type; this dispatches a MessageEvent object containing the data (the concatenated lines of event data), origin (the source origin of the event), and lastEventId (the ID from the 'id' field if present). For custom events specified by the server's 'event' field in the stream, developers use the addEventListener method to register handlers, such as addEventListener('ping', handler), allowing targeted responses to named event types. Errors, including connection failures, network issues, or parsing problems, trigger the 'error' event via the onerror property, which also dispatches an ErrorEvent; this enables graceful degradation, such as retry logic or user notifications. Additionally, an 'open' event signals a successful connection establishment. These events integrate seamlessly with the DOM event system, allowing SSE to interact with other web APIs like the Fetch API for credential management. To terminate a connection manually, the close() method aborts the underlying fetch request and sets readyState to CLOSED, preventing further events or automatic reconnection. This method is essential for resource cleanup, such as when a user navigates away or the application state changes. The API's event dispatching ensures that MessageEvent objects are created only when a complete event (terminated by a blank line in the text/event-stream format) is parsed, maintaining efficiency in unidirectional data flow from server to client. Cross-origin requests are supported through integration with the (CORS) protocol. By default, EventSource uses an anonymous CORS mode, but setting withCredentials: true in the constructor switches to credentials mode "include," allowing the inclusion of user credentials across origins if the server responds with appropriate CORS headers like Access-Control-Allow-Origin and Access-Control-Allow-Credentials: true. This enables secure SSE usage in multi-domain applications, such as dashboards aggregating data from APIs on different domains. For browsers lacking native EventSource support, polyfills provide fallback implementations using to simulate the streaming connection. These polyfills parse the incoming text/event-stream response manually, buffering data lines and dispatching based on field delimiters like 'data:', 'event:', and 'id:', while handling reconnection logic with . Such polyfills ensure broader compatibility but may introduce minor performance overhead due to the polling-like nature of .

Comparison to alternatives

Versus WebSockets

Server-Sent Events (SSE) and WebSockets represent two distinct approaches to real-time web communication, differing fundamentally in their protocols and capabilities. SSE operates as a unidirectional stream over HTTP(S), where the server pushes text-based events to the client using the text/event-stream MIME type, formatted as simple newline-delimited fields such as data:, event:, and id:. In contrast, WebSockets establish a bidirectional, full-duplex connection via an HTTP upgrade mechanism, transitioning to a custom framing protocol over TCP that supports both text and binary data through opcodes and optional masking for security. Regarding setup and overhead, SSE requires only a HTTP GET request with an Accept: text/event-stream header, enabling a persistent without additional , which results in lower initial complexity and latency for server-push scenarios. WebSockets, however, involve a more involved process, including the exchange of Sec-WebSocket-Key and Sec-WebSocket-Accept headers, potential subprotocol , and frame-level overhead for all messages, leading to higher setup costs but enabling seamless two-way data flow thereafter. SSE excels in use cases focused exclusively on server-to-client updates, such as delivering notifications, live feeds, or status changes, where the simplicity of one-way streaming aligns with the needs of content like news tickers or monitoring dashboards. WebSockets are preferable for interactive applications requiring client-to-server responses, including collaborative tools, online gaming, or chat systems, as their bidirectional nature supports low-latency exchanges in both directions without repeated HTTP requests. For reliability, SSE incorporates automatic reconnection logic with and the Last-Event-ID header, allowing clients to resume streams from the point of interruption and avoid in unstable networks. WebSockets lack native reconnection or resume features, necessitating custom implementation of ping/pong control frames for detection and manual reconnection protocols to maintain health. In terms of resource utilization, SSE offers lighter bandwidth consumption for unidirectional traffic due to its efficient, text-only HTTP streaming without framing overhead, making it suitable for high-volume push updates; however, it faces browser-imposed limits of roughly 6 concurrent per in non-HTTP/2 setups. WebSockets, while incurring more overhead from their framing and bidirectional support, provide greater flexibility without such connection restrictions, though they may be less efficient for purely one-way data flows.

Versus AJAX polling and long polling

Server-Sent Events (SSE) offer a more efficient alternative to traditional polling techniques for delivering real-time updates from server to client over HTTP. AJAX polling, or short polling, relies on the client periodically sending HTTP GET requests—typically via XMLHttpRequest or Fetch API—to query the server for new data, often resulting in empty responses when no updates are available, which wastes bandwidth and server resources. Long polling addresses some inefficiencies by keeping the client's request open until data becomes available or a timeout elapses, after which the server responds, and the client issues a new request to maintain the cycle. Both polling approaches suffer from inherent efficiency drawbacks, including repeated HTTP overhead from connection handshakes, headers, and potential latency introduced by polling intervals. Short polling exacerbates this with frequent empty exchanges, while long polling, though reducing idle requests, consumes server connection slots continuously and remains strictly unidirectional, limiting its suitability for scalable applications. In performance evaluations, polling methods show higher CPU utilization and poorer compared to SSE. SSE mitigates these issues through a single, long-lived HTTP that remains open, allowing the to events as they occur without client-initiated polls or timers. This persistent —leveraging HTTP/1.1 or HTTP/2 —drastically cuts down on request volume, enabling lower latency and reduced overhead for unidirectional data flows. SSE outperforms polling in CPU efficiency for update-heavy workloads. Compared to polling, SSE's drawbacks include dependency on browser-native support via the EventSource API, though it provides built-in reconnection logic—defaulting to a 3-second retry interval—to gracefully recover from network disruptions without custom implementation. Polling, by contrast, offers broader compatibility across legacy environments but scales poorly, leading to increased server load and potential bottlenecks in resource-constrained systems. For applications such as live dashboards or notification feeds, migrating from polling to SSE simplifies code by replacing timer-based requests with event listeners, significantly cutting unnecessary traffic and enhancing real-time responsiveness. This shift often yields measurable gains in scalability and reduced bandwidth usage.

Development and standards

Origins and evolution

Server-Sent Events originated from early efforts to enable efficient server-to-client push notifications in web applications, drawing inspiration from Comet techniques that utilized long-lived HTTP connections for real-time updates. The API was proposed by WHATWG editor Ian Hickson as part of the Web Applications 1.0 specification, with initial discussions appearing in mailing lists as early as 2005 and formal inclusion around 2006. Key milestones in its development included integration into the broader HTML specification by , coinciding with the first W3C Working Draft for the EventSource API. Early browser implementations began with Opera's experimental support in 2006 using the non-standard "text/x-dom-event-stream" type, followed by more standardized support in 6 in 2011, marking the transition from proprietary experiments to wider adoption. The technology evolved significantly in the , with built-in reconnection logic using the "retry:" field to automatically re-establish connections after interruptions, addressing reliability in dynamic environments. This development was driven by growing demands for delivery in applications like live news feeds and collaborative tools. contributions played a crucial role in early adoption, particularly through open-source polyfills for the EventSource interface that provided compatibility for browsers lacking native support, such as Remy Sharp's polyfill released around 2010, which emulated the API using fallbacks. These efforts bridged the gap until native implementations became ubiquitous, facilitating broader experimentation and integration in .

Standardization process

Server-sent events (SSE) are formally standardized through the WHATWG's HTML Living Standard, where the EventSource interface is defined in section 9.2, enabling clients to receive push notifications from servers over HTTP connections. This specification originated in the first HTML5 working draft published by the W3C in January 2008, introducing SSE as a mechanism for server-push events. The EventSource specification progressed through W3C drafts: First Public Working Draft in April 2009, Last Call Working Draft in December 2009, further Working Drafts in 2011 and 2012, Proposed Recommendation in December 2014, and became a W3C Recommendation in February 2015. The HTML5 Recommendation of October 2014 referenced this separate Eventsource specification. However, since 2012, the has maintained the primary, continuously evolving version as a living standard, diverging from the W3C's snapshot-based approach to allow for ongoing refinements aligned with needs. SSE relies on HTTP semantics without a dedicated IETF RFC, building on the foundational HTTP/1.1 protocol outlined in RFC 2616 for connection management and response handling. It aligns with contemporary HTTP practices in RFC 9110, which updates core semantics for message routing, status codes, and content negotiation as of June 2022. Compatibility with HTTP/2, standardized in RFC 7540 in May 2015, was enabled through the protocol's inherent support for persistent streams, allowing SSE to leverage multiplexing without major specification changes. As a living standard, undergoes iterative maintenance by the , facilitating updates such as enhanced keep-alive message definitions discussed in 2022 to improve connection reliability. Security considerations, including (CORS) requirements and credential handling via the withCredentials attribute, have been refined in recent years to address potential vulnerabilities in cross-origin requests.

Implementation and support

Browser compatibility

Server-Sent Events (SSE), implemented via the EventSource , enjoy broad support in modern desktop browsers. Chrome has provided full support since version 6, released in 2010. Firefox added full support starting with version 6 in 2011. Safari has supported SSE since version 5 in 2010, and Microsoft Edge (Chromium-based) since version 79 in 2020. Internet Explorer, across all versions from 6 to 11, lacks native support for the EventSource . Polyfills are available for unsupported browsers like Internet Explorer. On mobile platforms, SSE compatibility is similarly strong in contemporary browsers. The Android Browser has supported it since version 4.4 (KitKat) in 2013. for Android provides full support since version 18 in 2012. on has included support since version 4.0 in 2010. However, older mobile versions, particularly pre-2015 releases, may exhibit partial issues such as unreliable automatic reconnection after interruptions. Despite widespread adoption, SSE faces certain browser-imposed limitations. Proxies and firewalls can interfere with long-lived , potentially blocking or terminating SSE streams due to their persistent nature. Additionally, browsers typically restrict concurrent SSE to six per domain (across all tabs and windows) when using HTTP/1.1, a limit that persists in and as a "won't fix" ; mitigates this by allowing up to 100 simultaneous streams by default. As of November 2025, achieves approximately 94.92% global browser coverage according to usage statistics, reflecting its maturity across devices but highlighting persistent gaps in legacy systems like and pre-Chromium versions. Developers can verify compatibility using resources like Can I Use for real-time testing and planning.

Server-side implementations

Server-side implementations of Server-Sent Events () typically involve configuring HTTP responses to stream data unidirectionally from the to the client, leveraging asynchronous programming to handle long-lived without blocking. This requires setting specific headers such as Content-Type: text/event-stream, Cache-Control: no-cache, and Connection: keep-alive to maintain the stream and prevent caching. Common patterns include using async generators or iterators to produce event data incrementally, flushing the response buffer after each event to ensure timely delivery, and managing connection lifecycle to handle disconnections gracefully. In , SSE can be implemented using the native http module by creating a server that responds with the required headers and writes event data in the format data: message\n\n to the response stream. For integration with , libraries like sse-express simplify the process by providing to handle SSE endpoints, automatically setting headers and managing event emission. NestJS, a progressive Node.js framework, also supports SSE natively through its @Sse decorator, enabling reactive event propagation in controllers. Python implementations often rely on asynchronous web frameworks to support non-blocking I/O during streaming. In Flask, the Flask-SSE extension facilitates by decorating routes to return event streams, handling header setup and event formatting automatically. For , while core support is limited, extensions like django-sse or integration with Django Channels (primarily for WebSockets) can adapt for , though Channels is better suited for bidirectional needs. excels in async handling due to its non-blocking architecture, using RequestHandler methods to yield events from coroutines, making it ideal for high-concurrency scenarios. Java frameworks provide robust SSE support through reactive and asynchronous APIs. Spring WebFlux enables SSE via the SseEmitter class or Flux publishers, allowing servers to stream events reactively while integrating with Spring Boot's web layer for endpoint configuration. In JAX-RS, asynchronous servlets or the ServerSentEvent API (introduced in JAX-RS 2.1) support streaming by returning OutboundSseEvent instances, with low-level options like Grizzly for custom HTTP handling. Other languages offer similar capabilities through async libraries or standard HTTP packages. In , ReactPHP provides an for non-blocking SSE implementation, where servers flush responses with event data using its Server component. Ruby on Rails supports SSE via ActionController::Live, enabling streaming responses in controllers, while ActionCable can be configured in SSE mode for real-time updates without full overhead. Go's net/http package implements SSE by writing to http.ResponseWriter with manual header setting and periodic flushes, often augmented by libraries like r3labs/sse for simplified client-server management.

Security and best practices

Potential risks

Server-Sent Events (SSE) introduce several security vulnerabilities due to their reliance on persistent, unidirectional HTTP connections, which can expose systems to attacks if not carefully managed. One primary risk is denial-of-service () attacks through resource exhaustion, as SSE maintains long-lived connections without inherent mechanisms, allowing attackers to open numerous simultaneous streams that consume server memory and CPU resources. For instance, improper handling of concurrent SSE connections has been shown to lead to scenarios where servers stop accepting new connections while existing ones persist, effectively halting service availability. Another significant concern is (XSS), where unsanitized data in event payloads can introduce malicious scripts that execute within the client's context if the receiving application inserts the data directly into the DOM without proper escaping. The SSE protocol decodes incoming data as and dispatches it via DOM events, meaning any embedded in the data: field could be interpreted by code, amplifying the impact of server-side injection flaws. Connection poses a further , particularly in setups lacking robust , as SSE streams can be accessed by unauthorized parties who simply connect to the , potentially intercepting sensitive updates. SSE implementations do not include built-in authentication headers beyond optional cookies or credentials, making it straightforward for attackers to impersonate legitimate clients and subscribe to private streams. Browsers store the Last-Event-ID value in the EventSource object's internal state until explicitly overwritten, which persists across reconnections and could facilitate unauthorized resumption of streams if the ID is compromised or predictable. Privacy risks arise from the use of unencrypted HTTP , which expose transmitted event data to interception, with the persistent nature of SSE heightening the potential for prolonged man-in-the-middle (MITM) attacks compared to short-lived requests. Long-lived streams over plain HTTP allow eavesdroppers to capture ongoing data flows, including potentially sensitive information like user updates or notifications, without the immediate termination typical of standard HTTP exchanges.

Mitigation strategies

To mitigate security risks associated with server-sent events (SSE), developers should implement robust mechanisms that leverage standard HTTP features without exposing sensitive information. can be achieved using in the initial GET request to the SSE endpoint, with the withCredentials option in the EventSource constructor for cross-origin scenarios. For bearer tokens, use query parameters (avoiding secrets due to logging risks) or polyfills to enable custom headers. This approach ensures that session-based or token-based is handled securely during connection establishment, while avoiding the use of query parameters for secrets, as they may be logged by proxies or servers, potentially leading to exposure. Additionally, validating the of incoming connections with an allow-list helps prevent unauthorized access from untrusted domains. Encryption is essential for protecting SSE streams from eavesdropping and tampering during transmission. All SSE implementations must use to encrypt , as unencrypted connections expose event payloads to interception by attackers on shared networks. To further enforce secure transport, servers should implement (HSTS) headers, which instruct browsers to only connect over and prevent downgrade attacks to HTTP. This combination ensures that the unidirectional event stream remains confidential and integral, aligning with broader web security standards. Managing resource consumption is critical to prevent denial-of-service (DoS) attacks through excessive connections in SSE deployments. Servers should enforce timeouts, such as closing idle connections after 30 seconds of inactivity, and detect client disconnections using mechanisms like checking for aborted requests to free up resources promptly. Implementing connection pooling allows multiple event streams to share underlying resources efficiently, while IP-based rate limiting or throttling—such as capping concurrent connections per IP address—helps mitigate abuse by limiting the impact of a single malicious client. These controls ensure scalability without compromising availability, particularly in high-traffic environments. Data sanitization prevents injection attacks when processing SSE payloads on the client side. Server-side validation should include checking event types and IDs against predefined allow-lists to reject malformed or unexpected inputs, while escaping any or in the data field using appropriate output encoding to avoid (XSS) if the data is later inserted into the DOM. On the client side, validate event.origin against a predefined allow-list and process event.data strictly as or parsed data (e.g., ), never inserting it directly into the DOM without escaping or evaluating it as code. Clients must treat event.data strictly as or parsed , never evaluating it as executable code, to block potential script execution. This layered approach maintains the integrity of event handling across the stack. Effective monitoring enhances the reliability and security of SSE connections under load. Servers should log connection events, including establishment, disconnections, and errors, to detect anomalies such as unusual spike patterns indicative of attacks. Implementing circuit breakers can automatically pause new connections during overloads, allowing the system to recover without cascading failures. For distributed setups, leveraging content delivery networks (CDNs) with native SSE support, such as those providing edge-side streaming, offloads traffic management and improves global performance while maintaining security headers.

Practical examples

Basic implementation

Server-Sent Events (SSE) provide a straightforward way to implement unidirectional communication from server to client over a persistent HTTP connection. A basic setup involves the client using the EventSource API to establish the connection and handle incoming messages, while the server streams data in a specific text/event-stream format. This approach requires no additional libraries on the client side and minimal configuration on the server.

Client-Side Implementation

On the client, JavaScript's EventSource interface handles the connection and event reception. The following example connects to an SSE endpoint, listens for default 'message' events, and updates a DOM element with the received data, such as a timestamp.
javascript
const eventSource = new EventSource('/events');
const output = document.getElementById('output');

eventSource.onmessage = function(event) {
  const data = event.data;
  output.innerHTML += data + '<br>';
};

eventSource.onerror = function(event) {
  console.error('SSE error:', event);
};
This code creates an EventSource object pointing to the '/events' endpoint, appends each incoming message to an with id 'output', and logs errors if the connection fails. The EventSource automatically reconnects on network interruptions.

Server-Side Implementation

For the , a example using the built-in http module demonstrates streaming events. The sets appropriate headers for the event stream and sends timestamp data every two seconds in a .
javascript
const http = require('http');

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

    const interval = setInterval(() => {
      const data = `data: ${new Date().toISOString()}\n\n`;
      res.write(data);
    }, 2000);

    req.on('close', () => {
      clearInterval(interval);
      res.end();
    });
  } else {
    res.writeHead(404);
    res.end();
  }
}).listen(3000, () => {
  console.log('Server listening on port 3000');
});
This script creates an HTTP server on port 3000, responds to '/events' requests with SSE headers including Content-Type 'text/event-stream' and no-cache controls, and writes events formatted as 'data: [message]\n\n'. The interval sends a new every 2000 milliseconds, and the connection cleans up on client close.

Testing the Implementation

To test locally, save the server code as 'server.js' and run it with using node server.js. Open a and navigate to http://localhost:3000, ensuring an file with the client and a
element is served (or embed the script directly). Events should appear in the output element every two seconds. Use browser developer tools' Network tab to verify the persistent connection under '/events', showing a of 200 and incremental chunks.

Common Pitfalls

A frequent issue is omitting the double (\n\n) after each 'data:' line, which prevents the client from parsing events correctly. Similarly, neglecting Cache-Control: no-cache or : keep-alive headers can cause browsers to or close the stream prematurely. Always include Access-Control-Allow-Origin for cross-origin requests during development.

Real-world applications

Server-sent events (SSE) facilitate real-time notifications in various applications, enabling servers to push updates such as live alerts without requiring client-initiated requests. In social media platforms, SSE supports streaming updates for user feeds and notifications, allowing immediate delivery of new mentions, likes, or messages. Third-party integrations with collaboration tools can leverage SSE for real-time alert delivery, such as bot notifications or channel updates in custom workflows. In data dashboards, SSE powers real-time metrics visualization by streaming updates from servers to clients, reducing the need for frequent refreshes. For example, employs in its production systems to deliver scalable, load-balanced streams for merchant analytics and performance monitoring, simplifying visualization of live sales and inventory metrics. Tools like can integrate via plugins for pushing dynamic metrics, enabling dashboards to display evolving data such as system health or user activity without polling. SSE finds application in online gaming for unidirectional server updates, such as leaderboards or multiplayer status changes, where full-duplex communication is unnecessary. In these scenarios, SSE streams score rankings or game state notifications to clients, maintaining low for non-interactive elements while avoiding the complexity of WebSockets. A notable in financial applications involves SSE for stock tickers, where it streams live price updates to trading interfaces. This approach significantly outperforms traditional polling; benchmarks demonstrate that SSE can reduce backend CPU overhead by up to 100% compared to continuous polling under high user loads (e.g., 10,000 concurrent connections), while maintaining sub-second for 95th percentile responses. In production financial systems, this translates to efficient, scalable delivery of , minimizing resource waste and enabling responsive user experiences.

References

  1. [1]
    9.2 Server-sent events - HTML Standard - whatwg
    This specification introduces the EventSource interface. Using this API consists of creating an EventSource object and registering an event listener.
  2. [2]
  3. [3]
    Using server-sent events - Web APIs | MDN
    May 15, 2025 · The server-side script that sends events needs to respond using the MIME type text/event-stream. Each notification is sent as a block of text terminated by a ...
  4. [4]
    Server-sent events | Can I use... Support tables for HTML5, CSS3, etc
    ### Browser Support History for Server-Sent Events (2006-2010)
  5. [5]
    EventSource - Web APIs | MDN
    Mar 13, 2025 · Unlike WebSockets, server-sent events are unidirectional; that is, data messages are delivered in one direction, from the server to the client ...
  6. [6]
    Server-sent events - Web APIs - MDN Web Docs
    Mar 20, 2025 · With server-sent events, it's possible for a server to send new data to a web page at any time, by pushing messages to the web page.
  7. [7]
    Server-Sent Events - W3C
    Apr 26, 2012 · This specification defines an API for opening an HTTP connection for receiving push notifications from a server in the form of DOM events.Introduction · Interpreting an event stream · Notes · Connectionless push and...
  8. [8]
    Server-Sent Events: A WebSockets alternative ready for another look
    Jun 28, 2023 · The EventSource interface is described by the WHATWG specification and implemented by all modern browsers. It provides a convenient way to ...Missing: definition | Show results with:definition
  9. [9]
  10. [10]
  11. [11]
  12. [12]
  13. [13]
  14. [14]
    EventSource: message event - Web APIs | MDN
    May 2, 2025 · The message event of the EventSource interface is fired when data is received through an event source. This event is not cancelable and does not bubble.
  15. [15]
  16. [16]
  17. [17]
    Yaffle/EventSource: a polyfill for http://www.w3.org/TR ... - GitHub
    Browser support: IE 10+, Firefox 3.5+, Chrome 3+, Safari 4+, Opera 12+ · Advantages: · Server-side requirements: · Specification: · Build: · Notes: · Custom query ...
  18. [18]
  19. [19]
  20. [20]
    The WebSocket API (WebSockets) - Web APIs - MDN Web Docs
    Sep 9, 2025 · The WebSocket API makes it possible to open a two-way interactive communication session between the user's browser and a server.Writing WebSocket client... · Writing WebSocket servers · Streams API concepts
  21. [21]
  22. [22]
  23. [23]
  24. [24]
    Stream updates with server-sent events | Articles - web.dev
    Server-sent events (SSEs) send automatic updates to a client from a server, with an HTTP connection. Once the connection is established, servers can initiate ...
  25. [25]
  26. [26]
    [whatwg] WhatWG and event-source design
    Sep 20, 2005 · 1. The event-source element" the approach is to introduce a new element. I'd like to consider whether more than one event-source element is ...
  27. [27]
    Server-Sent Events - W3C
    Oct 29, 2009 · This specification defines an API for opening an HTTP connection for receiving push notifications from a server in the form of DOM events.
  28. [28]
    How exactly does Server-Sent Events work? - Stack Overflow
    May 24, 2011 · Clients are connected with the SSE server by keep-alive event stream, uni-directional connection which isn't closed until browser/tab is closed.Missing: Dean | Show results with:Dean
  29. [29]
  30. [30]
    A Look at the First HTML 5 Working Draft - InfoQ
    Server-sent events in combination with the new event-source element which will facilitate persistent connections to remote data sources and ...
  31. [31]
    HTML5 Recommendation - W3C
    This specification defines the 5th major revision of the core language of the World Wide Web: the Hypertext Markup Language (HTML).
  32. [32]
    Two HTML Standards Diverge in a Wood - WIRED
    Jul 23, 2012 · The W3C will continue to develop its fixed-in-time snapshot of HTML5 and the WHATWG will keep going with the "living standard" approach.
  33. [33]
    RFC 9110 - HTTP Semantics - IETF Datatracker
    This document describes the overall architecture of HTTP, establishes common terminology, and defines aspects of the protocol that are shared by all versions.Table of Contents · Identifiers in HTTP · Fields · Routing HTTP Messages
  34. [34]
    Server-Sent Events (SSE) - add Keep-Alive Messages definition
    Feb 3, 2022 · The SSE client can detect if keep-alive mechanism is used by checking if it received a keep-alive message as defined.
  35. [35]
  36. [36]
  37. [37]
    How To Use Server-Sent Events in Node.js to Build a Realtime App
    Mar 22, 2021 · In this article, you will build a complete solution for both the backend and frontend to handle real-time information flowing from server to client.
  38. [38]
    Server-Sent Events | NestJS - A progressive Node.js framework
    In the example above, we defined a route named sse that will allow us to propagate real-time updates. These events can be listened to using the EventSource API.
  39. [39]
    Server-Sent Events (SSE) in JAX-RS | Baeldung
    Jan 8, 2024 · Server-Sent Events (SSE) is an HTTP based specification that provides a way to establish a long-running and mono-channel connection from the ...
  40. [40]
    r3labs/sse: Server Sent Events server and client for Golang - GitHub
    SSE - Server Sent Events Client/Server Library for Go. Synopsis: SSE is a client/server implementation for Server Sent Events for Golang.
  41. [41]
    Denial Of Service mitigations — Hypercorn 0.17.3 documentation
    Denial Of Service mitigations#. There are multiple ways a ... This is to allow for responses that purposely take a long time, e.g. server sent events.
  42. [42]
  43. [43]
    HTML5 Security - OWASP Cheat Sheet Series
    Server-Sent Events¶ · Validate URLs passed to the EventSource constructor, even though only same-origin URLs are allowed. · As mentioned before, process the ...
  44. [44]
    Cross Site Scripting Prevention - OWASP Cheat Sheet Series
    Prevent XSS by validating and escaping variables, using output encoding, HTML sanitization, and framework security protections. No single technique is enough.
  45. [45]
    Using Server Sent Events to Simplify Real-time Streaming at Scale
    Nov 30, 2022 · SSE is a unidirectional server push technology that enables a web client to receive automatic updates from a server via an HTTP connection.
  46. [46]
    Developing Real-Time Web Applications with Server-Sent Events
    Server-Sent Events (SSE) is a standard that enables Web servers to push data in real time to clients asynchronously, without explicit requests.<|control11|><|separator|>
  47. [47]
    Announcing support for Server-Sent Events (SSE) - Ably Realtime
    Subscribing to a Twitter feed; Receiving live sports scores; News updates ... Introducing batch push notifications: send thousands with one API call. Ably ...<|separator|>
  48. [48]
    Slack MCP Server with SSE transport - GitHub
    A Model Context Protocol (MCP) server that provides Slack API integration using Server-Sent Events (SSE) transport.
  49. [49]
    HTTP SSE (Server-Sent Event) support for k6 · Issue #746 - GitHub
    Aug 18, 2018 · Server-Sent Events (SSE) : a lightweight and standardized technology for pushing notifications from a HTTP server to a HTTP client (One way ...
  50. [50]
    Leaderboard System Design
    Mar 18, 2023 · The server-sent events (SSE) or WebSockets can be used for real-time updates on the leaderboard 10.
  51. [51]
    How Amazon Uses Real-Time Data And Dynamic Pricing to ... - Pricefy
    Aug 11, 2024 · Amazon, the e-commerce giant, leverages real-time data analytics and dynamic pricing to dynamically adjust prices across millions of products.
  52. [52]
    Benchmarks of Server-sent events versus polling - Axway Blog
    Sep 14, 2015 · Benchmark architecture with server-sent events versus continuous polling: CPU, client-side, Latency.2. Setup · 3. Cpu · 3.1 Backend
  53. [53]
    Server-Sent Events vs WebSockets – How to Choose a Real-Time ...
    Jan 3, 2025 · Server-Sent Events (SSE) is a technology that enables a web server to push updates to a web page. As part of the HTML5 specification, it ...