HTML SSE

Server-Sent Events (SSE) let a web server push real-time updates to a browser page automatically, without the page asking repeatedly. Once the page opens a connection, the server keeps it open and sends new data whenever something changes — like live scores, stock prices, news feeds, or notification alerts.

How SSE Compares to Other Real-Time Approaches

Visual Diagram — Three Approaches to Real-Time Data

Polling (the old way — inefficient):
Browser: "Any new data?" → Server: "No"
Browser: "Any new data?" → Server: "No"
Browser: "Any new data?" → Server: "Yes! Here it is"
Browser: "Any new data?" → Server: "No"
(Lots of unnecessary requests. Wastes bandwidth.)

WebSockets (two-way communication):
Browser ←→ Server  (full duplex, both sides send messages)
(Good for chat apps, games — complex to set up)

Server-Sent Events (one-way push — simplest):
Browser → Server: "Open SSE connection"
Server  → Browser: "New score: 2-1"   (whenever it wants)
Server  → Browser: "New score: 2-2"
Server  → Browser: "Match ended"
(Simple, built into browsers, uses regular HTTP)

The EventSource Object

The browser side of SSE uses the EventSource object. You create it with the URL of your server endpoint. The browser automatically connects and stays connected.

<p id="liveUpdate">Waiting for updates...</p>

<script>
  // Check for browser support
  if (typeof EventSource !== "undefined") {

    const source = new EventSource("updates.php");

    // Fires when the server sends a message
    source.onmessage = function(event) {
      document.getElementById("liveUpdate").textContent = event.data;
    };

    // Fires when connection opens
    source.onopen = function() {
      console.log("SSE connection opened");
    };

    // Fires when an error occurs
    source.onerror = function() {
      console.log("SSE connection error");
    };

  } else {
    document.getElementById("liveUpdate").textContent =
      "Your browser does not support Server-Sent Events.";
  }
</script>

The Server Side — What SSE Looks Like

The server sends responses in a specific plain-text format. Each message starts with data: and ends with two blank lines. The server must set the content type to text/event-stream.

Example Server Response (PHP)

<?php
// updates.php

// Set required headers
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
header("Connection: keep-alive");

// Keep sending data
while (true) {
  $time = date("H:i:s");
  echo "data: Current time is " . $time . "\n\n";   // two newlines required
  ob_flush();
  flush();
  sleep(2);   // wait 2 seconds before next update
}
?>

SSE Message Format

Basic message (just data):
  data: Hello from server\n\n
          ↑                 ↑↑
          the message text  two newlines end the message

Message with ID (browser tracks last received ID):
  id: 42\n
  data: Update number 42\n\n

Named event type:
  event: score-update\n
  data: Team A: 3, Team B: 2\n\n

Message with retry interval (milliseconds):
  retry: 5000\n
  data: Try to reconnect every 5 seconds\n\n

Comment (ignored by browser — useful for keepalive):
  : this is a comment\n\n

Receiving Named Events

When the server sends a named event (using the event: field), the browser handles it with a specific event listener instead of the generic onmessage.

// Server sends:
// event: stock-update
// data: {"symbol": "AAPL", "price": 182.50}

// Browser listens for the named event:
source.addEventListener("stock-update", function(event) {
  const stock = JSON.parse(event.data);
  console.log(stock.symbol + ": $" + stock.price);
});

// The generic onmessage only fires for messages WITHOUT an event: field
source.onmessage = function(event) {
  console.log("Generic message:", event.data);
};

Automatic Reconnection

One of the best features of SSE is automatic reconnection. If the connection drops — due to network problems or server restarts — the browser automatically tries to reconnect after a short delay (default: 3 seconds).

Visual Diagram — Auto-Reconnect

Connection open ✓
  Server: "data: Score 1-0"
  Server: "data: Score 2-0"

Network drops...
  Browser waits 3 seconds
  Browser reconnects automatically

Connection restored ✓
  Browser sends: "Last-Event-ID: 12" (if server sent IDs)
  Server resumes from where it left off

The browser sends the Last-Event-ID header when reconnecting if the server previously sent message IDs. The server uses this to avoid sending duplicate updates.

Customizing Retry Interval

// Server sets retry delay:
retry: 10000\n    ← browser waits 10 seconds before reconnecting
data: Some message\n\n

Closing the Connection

<script>
  const source = new EventSource("updates.php");

  // Close when done
  function stopListening() {
    source.close();
    console.log("SSE connection closed");
  }
</script>

<button onclick="stopListening()">Stop Updates</button>

Practical Example — Live Score Ticker

<h3>Live Match Score</h3>
<p id="score" style="font-size:24px; font-weight:bold;">Loading...</p>
<ul id="events"></ul>

<script>
  const source = new EventSource("cricket-feed.php");

  source.addEventListener("score", function(e) {
    document.getElementById("score").textContent = e.data;
  });

  source.addEventListener("wicket", function(e) {
    const li = document.createElement("li");
    li.textContent = "🏏 Wicket! " + e.data;
    document.getElementById("events").prepend(li);
  });

  source.addEventListener("boundary", function(e) {
    const li = document.createElement("li");
    li.textContent = "🔵 Four! " + e.data;
    document.getElementById("events").prepend(li);
  });
</script>

SSE Connection States

source.readyState value    Meaning
----------------------     ---------------------------
0 (CONNECTING)             Opening the connection
1 (OPEN)                   Connection active, receiving events
2 (CLOSED)                 Connection closed (source.close() called)
console.log(source.readyState);   // 0, 1, or 2

When to Use SSE vs WebSockets

Choose SSE when:                          Choose WebSockets when:
-------------------------------           ------------------------------
Server pushes data to browser only        Both sides send messages
News feeds, notifications, dashboards     Chat apps, multiplayer games
Simple HTTP setup needed                  Complex real-time interaction
Automatic reconnect is important          Custom reconnect logic needed
Works through HTTP/2 efficiently          Separate protocol overhead

Browser Support and HTTPS

SSE works in all modern browsers. Like geolocation, SSE requires HTTPS on production websites — most browsers block mixed-content SSE connections from HTTP pages. On localhost for development, HTTP works fine.

Server-Sent Events are the simplest path to real-time data from a server to a browser. When your page needs live updates but does not need to send messages back to the server, SSE is the right tool — simpler to set up than WebSockets and more efficient than polling.

Leave a Comment

Your email address will not be published. Required fields are marked *