Skip to content

Introduction to Server-Sent Events

DodaTech Updated 2026-06-28 5 min read

In this tutorial, you will learn about Introduction to Server. We cover key concepts, practical examples, and best practices to help you master this topic.

Learn Server-Sent Events basics: how SSE enables server-to-client real-time push over HTTP, the EventSource API, event stream format, and when to use SSE in backend applications.

What You Learn

You will learn what Server-Sent Events are, how they differ from polling and WebSockets, the text/event-stream format, how to connect with the EventSource API, and when SSE is the right choice.

Why It Matters

Real-time updates improve user experience: live notifications, stock tickers, progress bars, feed updates. SSE provides a simpler alternative to WebSockets for one-way server-to-client streaming, using standard HTTP without special server support.

Real-World Use

DodaTech uses SSE for live deployment logs, scan progress updates, notification feeds, and system monitoring dashboards. SSE is preferred over WebSockets for these use cases because the data flows only from server to client.

Basic SSE Example

from http.server import HTTPServer, BaseHTTPRequestHandler
import time
import json

class SSEHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-Type', 'text/event-stream')
        self.send_header('Cache-Control', 'no-cache')
        self.send_header('Connection', 'keep-alive')
        self.end_headers()

        for i in range(5):
            data = json.dumps({'count': i, 'message': f'Event {i}'})
            self.wfile.write(f"data: {data}\n\n".encode())
            time.sleep(1)

server = HTTPServer(('localhost', 8080), SSEHandler)
print("SSE server on http://localhost:8080")
server.serve_forever()
<!DOCTYPE html>
<html>
<body>
<div id="output"></div>
<script>
const source = new EventSource('http://localhost:8080');
source.onmessage = (event) => {
    const data = JSON.parse(event.data);
    document.getElementById('output').innerHTML +=
        `<p>Count: ${data.count} - ${data.message}</p>`;
};
</script>
</body>
</html>

Expected output (in browser):

Count: 0 - Event 0
Count: 1 - Event 1
Count: 2 - Event 2
Count: 3 - Event 3
Count: 4 - Event 4

The text/event-stream Format

# SSE format: "field: value" pairs separated by newlines
# Events are separated by double newlines

# Simple data event
data: Hello World

# Event with ID
id: 42
data: {"message": "Hello"}

# Named event type
event: update
data: {"status": "completed"}

# Multi-line data
data: line 1
data: line 2

# Retry interval (milliseconds)
retry: 5000

# Comment (ignored by client)
: this is a comment

data: last message

Connecting with EventSource

// Basic connection
const source = new EventSource('/events');

// Listen for all messages
source.onmessage = function(event) {
    console.log('Received:', event.data);
};

// Listen for specific event types
source.addEventListener('user-update', function(event) {
    console.log('User update:', JSON.parse(event.data));
});

source.addEventListener('notification', function(event) {
    showNotification(event.data);
});

// Error handling
source.onerror = function(event) {
    if (event.eventPhase === EventSource.CLOSED) {
        console.log('Connection closed');
    } else {
        console.log('Connection error, will auto-reconnect');
    }
};

// Close connection
// source.close();

When to Use SSE

use_cases = {
    'sse': {
        'good_for': [
            'Live notifications',
            'Status updates',
            'Progress bars',
            'Feed updates',
            'Log streaming',
            'Metrics dashboards',
        ],
        'one_way': 'Server -> Client only',
        'simple': 'Uses standard HTTP',
        'auto_reconnect': 'Built into EventSource',
    },
    'websocket': {
        'good_for': [
            'Chat applications',
            'Collaborative editing',
            'Gaming',
            'Real-time forms',
        ],
        'two_way': 'Bidirectional',
        'complex': 'Requires WebSocket handshake',
        'reconnect': 'Must implement manually',
    },
    'polling': {
        'good_for': [
            'Infrequent updates',
            'Simple implementations',
            'Legacy browser support',
        ],
        'overhead': 'HTTP request per update',
        'latency': 'Up to polling interval delay',
        'bandwidth': 'Headers waste on each poll',
    },
}

Common Mistakes

1. Missing Content-Type Header

Without Content-Type: text/event-stream, the browser treats the response as regular HTTP and buffers it. The EventSource API will not work.

2. No Cache-Control Header

Browsers and proxies may cache SSE responses. Set Cache-Control: no-cache to prevent Caching.

3. Sending Events Without Newlines

SSE requires double newlines (\n\n) between events. Single newlines are ignored as line continuations.

4. Forgetting the Connection: keep-alive Header

Without Connection: keep-alive, the HTTP connection may close after each event, defeating the purpose of SSE.

5. Using SSE for Bidirectional Communication

SSE is one-way server-to-client. For bidirectional, use WebSockets. Trying to send data to the server via SSE requires separate HTTP requests.

Practice Questions

1. What MIME type does SSE use?

text/event-stream. The server must set this Content-Type header for the EventSource API to work.

2. How are SSE events delimited?

By double newlines (\n\n). Each event is separated by a blank line between the event fields.

3. What is the main advantage of SSE over WebSockets?

SSE uses standard HTTP, auto-reconnects natively, and is simpler to implement for one-way server-to-client streaming.

4. How does the browser handle SSE connection loss?

The EventSource API automatically reconnects after a connection loss. The server can use Last-Event-ID to resume from the last event.

Challenge

Build a simple SSE server that sends stock price updates every 2 seconds. Each event includes a stock symbol, price, and timestamp. Connect a client that displays prices in real time and highlights price changes.

FAQ

What browsers support SSE?

All modern browsers support EventSource. Internet Explorer does not. For IE support, use a polyfill or fall back to long-polling.

Can SSE go through HTTP/2?

Yes. HTTP/2 multiplexes SSE connections efficiently. Multiple SSE streams can share a single TCP connection without the browser's 6-connection-per-host limit.

How many SSE connections can a browser handle?

By default, browsers limit 6 concurrent connections per host (HTTP/1.1). HTTP/2 removes this limit. For many clients, use a stream server or HTTP/2.

Does SSE work behind a proxy?

Yes, but proxies may buffer the response. Ensure the proxy does not buffer text/event-stream responses. Set X-Accel-Buffering: no for nginx.

Is SSE encrypted with HTTPS?

Yes. SSE works over HTTPS with the same security as any HTTP connection. Use HTTPS in production to prevent tampering.

Mini Project: SSE Progress Updates

import time
import json
from http.server import HTTPServer, BaseHTTPRequestHandler

class ProgressSSE(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-Type', 'text/event-stream')
        self.send_header('Cache-Control', 'no-cache')
        self.send_header('Connection', 'keep-alive')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.end_headers()

        total = 100
        for i in range(total + 1):
            event = {
                'progress': i,
                'total': total,
                'percent': i,
                'status': 'in_progress' if i < total else 'completed',
                'message': f'Processing item {i}/{total}',
            }
            self.wfile.write(f"event: progress\ndata: {json.dumps(event)}\n\n".encode())
            time.sleep(0.1)

server = HTTPServer(('localhost', 8081), ProgressSSE)
print("Progress SSE on http://localhost:8081")
server.serve_forever()

What's Next

Now that you understand SSE basics, compare SSE vs WebSocket to choose the right technology, then learn the event stream format in detail.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro