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.
