← Back to DevBytes

SSE Protocol: A Complete Reference Guide

Introduction to Server-Sent Events (SSE)

Server-Sent Events (SSE) is a standard that allows a web server to push real-time updates to the client over a single, long-lived HTTP connection. Unlike WebSockets, which provide bidirectional communication, SSE is strictly unidirectional—data flows from the server to the client. This makes it an ideal choice for applications that require real-time updates but do not need the client to send continuous data back to the server over the same channel.

Why SSE Matters

Before SSE, developers relied on workarounds like long polling or forever iframes to simulate server push functionality. SSE standardizes this process, offering several distinct advantages:

Understanding the SSE Protocol

At its core, the SSE protocol is incredibly simple. The client makes a standard HTTP GET request to the server. The server responds with a specific content type and keeps the connection open, sending messages as they become available.

HTTP Headers

To initiate an SSE stream, the server must respond with the following HTTP headers:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

The text/event-stream header tells the browser to treat the incoming data as an event stream rather than a standard HTTP response that should be downloaded and closed.

Message Format

Messages in SSE are plain text. Each message consists of one or more lines containing a field name, a colon, and a value. A message is terminated by a blank line (a double newline, \n\n). The protocol defines four standard fields:

Here is an example of a raw SSE message:

event: userUpdate
id: 12345
data: {"name": "Alice", "status": "online"}

Implementing an SSE Server

Implementing an SSE server is straightforward in almost any backend language. Below is a complete example using Node.js and its built-in http module. This server sends a timestamp to the client every second and demonstrates how to handle the Last-Event-ID header for reconnections.

const http = require('http');

const server = http.createServer((req, res) => {
  // Check if the client is requesting the SSE endpoint
  if (req.url === '/events') {
    // Set the required SSE headers
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive'
    });

    // Check for Last-Event-ID to resume a dropped connection
    const lastEventId = req.headers['last-event-id'];
    let messageId = lastEventId ? parseInt(lastEventId, 10) : 0;

    // Send a heartbeat comment every 15 seconds to keep the connection alive
    const heartbeatInterval = setInterval(() => {
      res.write(': heartbeat\n\n');
    }, 15000);

    // Send a new event every 1 second
    const eventInterval = setInterval(() => {
      messageId++;
      const payload = {
        time: new Date().toISOString(),
        message: `Hello from server! Event ID: ${messageId}`
      };

      // Format the SSE message
      res.write(`id: ${messageId}\n`);
      res.write(`event: timeUpdate\n`);
      res.write(`data: ${JSON.stringify(payload)}\n\n`);
    }, 1000);

    // Clean up intervals when the client disconnects
    req.on('close', () => {
      clearInterval(heartbeatInterval);
      clearInterval(eventInterval);
      res.end();
    });

  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Not Found');
  }
});

server.listen(3000, () => {
  console.log('SSE server running on http://localhost:3000');
});

Consuming SSE on the Client

On the client side, the browser provides the EventSource API, which handles the connection, parsing, and automatic reconnection logic for you. You simply instantiate it with the URL of your SSE endpoint and attach event listeners.

JavaScript EventSource API

The following HTML and JavaScript code connects to the Node.js server defined above, listens for the custom timeUpdate event, and appends the data to the DOM.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>SSE Client Example</title>
</head>
<body>
  <h1>Server-Sent Events Demo</h1>
  <ul id="event-list"></ul>

  <script>
    const eventList = document.getElementById('event-list');

    // Connect to the SSE endpoint
    const eventSource = new EventSource('/events');

    // Listen for the custom 'timeUpdate' event
    eventSource.addEventListener('timeUpdate', (event) => {
      const data = JSON.parse(event.data);
      const listItem = document.createElement('li');
      listItem.textContent = `[${data.time}] ${data.message}`;
      eventList.appendChild(listItem);
    });

    // Handle generic errors (EventSource will auto-reconnect)
    eventSource.onerror = (error) => {
      console.error('EventSource failed:', error);
      // You can close the connection manually if desired:
      // eventSource.close();
    };

    // Optional: Listen for the default 'message' event
    eventSource.onmessage = (event) => {
      console.log('Generic message received:', event.data);
    };
  </script>
</body>
</html>

Best Practices for SSE

While SSE is simple to implement, following best practices ensures your application remains robust, scalable, and reliable in production environments.

Conclusion

Server-Sent Events provide a powerful, efficient, and standardized way to push real-time data from the server to the browser. By leveraging standard HTTP, SSE bypasses the complexities of WebSockets while offering built-in reconnection and a simple message format. Whether you are building a live news feed, a stock ticker, or a notification system, SSE is often the most pragmatic choice for unidirectional data streaming. By understanding the protocol details and adhering to best practices like heartbeats and event ID tracking, you can build highly responsive and resilient real-time features into your web applications.

— Ad —

Google AdSense will appear here after approval

← Back to all articles