HTML Server-Sent Events API
Receive automatic updates from servers using the EventSource API. Build real-time applications with one-way data streaming from server to client.
Server-Sent Events (SSE) provide a simple way for servers to push data to web pages over HTTP. Unlike WebSockets which enable two-way communication, SSE offers a lightweight solution for one-directional updates perfect for live feeds, notifications, and continuous data streams.
What are Server-Sent Events?
Server-Sent Events create a persistent connection between your webpage and the server. Once established, the server can send messages whenever new data becomes available without the client requesting it. This approach works exceptionally well for applications displaying real-time information like stock prices, social media feeds, or live sports scores.
Key Benefits of SSE
- Automatic reconnection when connection drops
- Works over standard HTTP/HTTPS protocols
- Simple text-based format easy to implement
- Lower overhead compared to polling
- Built-in event tracking with IDs
- Native browser support without libraries
Creating Your First EventSource Connection
The EventSource interface handles all connection management automatically. You provide a URL endpoint, and the browser maintains the connection, processes incoming messages, and reconnects if needed.
Basic EventSource Example
<div id="updates"></div>
<script>
// Create connection to server endpoint
const eventSource = new EventSource('/api/stream');
// Listen for messages
eventSource.onmessage = function(event) {
const updateDiv = document.getElementById('updates');
const newMessage = document.createElement('p');
newMessage.textContent = event.data;
updateDiv.appendChild(newMessage);
};
// Handle connection opened
eventSource.onopen = function() {
console.log('Connection established');
};
// Handle errors
eventSource.onerror = function(error) {
console.error('Connection error:', error);
};
</script>
Server Response Format
Servers send data as plain text with specific formatting. Each message consists of fields separated by newlines, with a blank line marking the message boundary. The format remains straightforward and easy to generate from any backend language.
Server-Side Format
// HTTP Headers (required)
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
// Message format
data: This is a simple message
data: You can also send
data: multi-line messages
data: like this
id: 123
event: customEvent
data: {"user": "John", "action": "login"}
retry: 10000
Field Descriptions:
data:- The actual message content (required)id:- Unique identifier for message trackingevent:- Custom event name (defaults to "message")retry:- Reconnection time in milliseconds
Working with Custom Events
Beyond the default message event, you can define custom event types to organize different data streams. This approach helps separate concerns when handling multiple types of updates from the same connection.
Custom Event Handlers
const source = new EventSource('/api/notifications');
// Handle different event types
source.addEventListener('userJoined', function(e) {
const data = JSON.parse(e.data);
console.log(`${data.username} joined the chat`);
updateUserList(data);
});
source.addEventListener('newMessage', function(e) {
const message = JSON.parse(e.data);
displayMessage(message);
});
source.addEventListener('userLeft', function(e) {
const data = JSON.parse(e.data);
console.log(`${data.username} left`);
removeFromUserList(data.userId);
});
// Still handle generic messages
source.onmessage = function(e) {
console.log('Generic message:', e.data);
};
Managing Connections
Proper connection management ensures your application remains responsive and doesn't waste resources. Always close connections when they're no longer needed, and handle errors gracefully to maintain a good user experience.
Connection Control
let eventSource = null;
function startConnection() {
// Check if already connected
if (eventSource && eventSource.readyState !== EventSource.CLOSED) {
console.log('Already connected');
return;
}
eventSource = new EventSource('/stream');
eventSource.onopen = function() {
document.getElementById('status').textContent = 'Connected';
document.getElementById('status').className = 'status-online';
};
eventSource.onerror = function() {
document.getElementById('status').textContent = 'Connection lost';
document.getElementById('status').className = 'status-offline';
};
eventSource.onmessage = function(e) {
processUpdate(e.data);
};
}
function stopConnection() {
if (eventSource) {
eventSource.close();
eventSource = null;
document.getElementById('status').textContent = 'Disconnected';
document.getElementById('status').className = 'status-offline';
}
}
// Clean up when page unloads
window.addEventListener('beforeunload', stopConnection);
Connection States
The EventSource object maintains a readyState property indicating the current connection status. Understanding these states helps you build robust applications that respond appropriately to connection changes.
Checking Connection State
function checkConnectionState(source) {
switch(source.readyState) {
case EventSource.CONNECTING:
console.log('Connecting to server...');
return 'connecting';
case EventSource.OPEN:
console.log('Connection active');
return 'open';
case EventSource.CLOSED:
console.log('Connection closed');
return 'closed';
default:
console.log('Unknown state');
return 'unknown';
}
}
// Monitor connection
const monitor = new EventSource('/updates');
setInterval(function() {
const state = checkConnectionState(monitor);
updateStatusIndicator(state);
}, 5000);
| State | Value | Description |
|---|---|---|
| CONNECTING | 0 | Connection being established |
| OPEN | 1 | Connection active and receiving events |
| CLOSED | 2 | Connection closed, won't reconnect |
Real-World Example: Live Notifications
This complete example demonstrates a notification system that receives live updates from a server. The implementation includes connection status indicators, automatic reconnection, and proper cleanup.
Live Notification System
<!DOCTYPE html>
<html lang="en">
<head>
<style>
#notifications {
max-width: 600px;
margin: 20px auto;
}
.notification {
padding: 15px;
margin: 10px 0;
border-radius: 5px;
background: #f0f0f0;
border-left: 4px solid #3498db;
}
.notification.error {
border-left-color: #e74c3c;
background: #fee;
}
.notification.success {
border-left-color: #2ecc71;
background: #efe;
}
#status {
padding: 10px;
text-align: center;
font-weight: bold;
}
.status-online { color: #2ecc71; }
.status-offline { color: #e74c3c; }
</style>
</head>
<body>
<div id="status" class="status-offline">Disconnected</div>
<div id="notifications"></div>
<button onclick="toggleConnection()">Toggle Connection</button>
<script>
let eventSource = null;
let isConnected = false;
function addNotification(message, type = 'info') {
const container = document.getElementById('notifications');
const notification = document.createElement('div');
notification.className = `notification ${type}`;
notification.innerHTML = `
<small>${new Date().toLocaleTimeString()}</small>
<p>${message}</p>
`;
container.insertBefore(notification, container.firstChild);
// Keep only last 10 notifications
while (container.children.length > 10) {
container.removeChild(container.lastChild);
}
}
function connect() {
eventSource = new EventSource('/api/notifications');
eventSource.onopen = function() {
document.getElementById('status').textContent = 'Connected';
document.getElementById('status').className = 'status-online';
isConnected = true;
};
eventSource.addEventListener('notification', function(e) {
const data = JSON.parse(e.data);
addNotification(data.message, data.type);
});
eventSource.onerror = function() {
document.getElementById('status').textContent = 'Connection Error';
document.getElementById('status').className = 'status-offline';
};
}
function disconnect() {
if (eventSource) {
eventSource.close();
isConnected = false;
document.getElementById('status').textContent = 'Disconnected';
document.getElementById('status').className = 'status-offline';
}
}
function toggleConnection() {
if (isConnected) {
disconnect();
} else {
connect();
}
}
// Auto-connect on page load
connect();
</script>
</body>
</html>
Browser Compatibility
Server-Sent Events work in all modern browsers. Internet Explorer doesn't support SSE, but polyfills exist for older browsers if needed. For production applications, always check compatibility and provide fallbacks when necessary.
Feature Detection
// Check for SSE support
if (typeof EventSource !== 'undefined') {
// SSE is supported
const source = new EventSource('/stream');
// ... handle events
} else {
// Fall back to polling or WebSockets
console.warn('SSE not supported, using fallback');
startPolling();
}
function startPolling() {
setInterval(function() {
fetch('/api/updates')
.then(response => response.json())
.then(data => processUpdates(data))
.catch(error => console.error('Polling error:', error));
}, 5000);
}
Best Practices
Server Implementation
- Set proper HTTP headers (Content-Type: text/event-stream)
- Disable caching with Cache-Control: no-cache
- Keep connections alive with periodic heartbeat messages
- Include message IDs for client-side tracking
- Implement connection limits per user to prevent abuse
Client Implementation
- Always close connections when leaving the page
- Handle errors gracefully with user feedback
- Limit the number of simultaneous connections
- Parse JSON data safely with try-catch blocks
- Monitor memory usage when displaying large data streams
Common Pitfalls
- Forgetting to close connections causes memory leaks
- Not handling errors leads to poor user experience
- Missing CORS headers prevents cross-origin connections
- Blocking server processes while waiting for data
- Sending binary data (SSE only supports text)
SSE vs WebSockets
Choosing between Server-Sent Events and WebSockets depends on your specific needs. SSE excels in scenarios where the server primarily sends data to clients, while WebSockets suit applications requiring bidirectional communication.
| Feature | Server-Sent Events | WebSockets |
|---|---|---|
| Communication | One-way (server to client) | Two-way (bidirectional) |
| Protocol | HTTP/HTTPS | WS/WSS |
| Data Format | Text only (UTF-8) | Text and binary |
| Auto Reconnect | Built-in | Manual implementation |
| Complexity | Simple | More complex |
| Use Cases | News feeds, notifications, dashboards | Chat, gaming, collaborative tools |
Common Use Cases
Stock Price Updates
Financial applications use SSE to stream real-time price changes to thousands of connected clients simultaneously. The automatic reconnection feature ensures users stay updated even with network interruptions.
Social Media Feeds
Social platforms deliver new posts and notifications as they occur without requiring users to refresh pages. This creates an engaging, responsive experience while minimizing server load compared to constant polling.
Server Monitoring Dashboards
System administrators watch live server metrics and logs through SSE connections. The persistent connection provides instant alerts about issues while keeping implementation simple and resource-efficient.
Live Sports Scores
Sports websites broadcast score updates to viewers in real-time. SSE handles variable traffic loads well, scaling easily during peak events while automatically managing connections.
Try Our HTML Playground
Click the button below to open our interactive HTML editor. Write HTML code and see the results immediately!
Open HTML Playground ›
HTML Free Codes