HTML Server-Sent Events

Intermediate
14 min read
Updated: Nov 2026
5 examples
EventSource

Definition and Usage

Server-Sent Events (SSE) let a server push new data to an HTML page at any time. Traditionally the page must request updates; with SSE the server streams messages and your page script treats them as events—then updates the DOM (lists, clocks, alerts) without reloading.

What does the HTML page do?

A script creates an EventSource pointed at a stream URL. Incoming messages become message events (or named events). Handlers read event.data and change HTML elements—the connection stays open so updates keep arriving.

What does the server send?

A UTF-8 text stream with MIME type text/event-stream. Each event is one or more field lines (data:, optional event:, id:, retry:) ended by a blank line.

When should you use SSE on an HTML site?

Live scores, notification feeds, dashboards, and progress updates—anywhere the server talks and the browser mostly listens. For two-way chat or games, prefer WebSockets instead.

One-way only.

SSE cannot send events from the client to the server. Use normal HTTP forms/fetch for client→server actions.

Connection limits on HTTP/1.1.

Browsers often allow only a few SSE connections per domain across tabs (~6). HTTP/2 raises that limit. Prefer HTTP/2 in production.

Auto-reconnect.

If the stream drops, EventSource reconnects by default. Call close() when the HTML page no longer needs updates.

HTML / Client Syntax

Open a stream from a script in your HTML document:

JS
var evtSource = new EventSource("/sse");

evtSource.onmessage = function (event) {
  // event.data is a string — update the HTML page
  document.getElementById("out").textContent = event.data;
};

evtSource.onerror = function () {
  console.error("EventSource failed");
};

// Stop listening (optional)
// evtSource.close();
stream-format.txt
: keep-alive comment

data: some text

event: ping
data: {"time":"2026-11-05T07:40:00Z"}

Cross-origin streams can pass options: new EventSource(url, { withCredentials: true }).

Core HTML Concepts

Pieces that connect a live stream to your webpage:

ConceptRole
EventSourceBrowser API that opens and reads the SSE connection
text/event-streamRequired MIME type for the server response
data:Payload line(s); concatenated into event.data
event:Named event type (listen with addEventListener)
id:Last-Event-ID for resume after reconnect
retry:Reconnection delay in milliseconds
onmessageHandler for default (unnamed) messages
close()Stop the stream from the HTML page
DOM updateWrite event.data into elements, lists, or status text

Event stream fields

FieldEffect in the browser
dataBecomes event.data (multi-line data: joined with newlines)
eventDispatches a custom event name instead of message
idSets last event id; sent back on reconnect as Last-Event-ID
retryHow long to wait before reconnecting (ms)
: commentIgnored; useful as a keep-alive heartbeat

How to Use SSE in an HTML Page

Client first (what every HTML tutorial needs), then a minimal server shape.

  1. Add HTML placeholders for live content (<ul id="list">, <div id="clock">).
  2. In a script, new EventSource("/your-stream").
  3. Handle onmessage to update the DOM from event.data.
  4. For named server events, use addEventListener("ping", …).
  5. Handle onerror; call close() when leaving the page or stopping the feed.
  6. On the server: respond with text/event-stream and write data: …\n\n blocks.
GoalPattern
Connect from HTMLnew EventSource("/sse")
Show default messageses.onmessage = (e) => { … e.data … }
Named eventes.addEventListener("news", handler)
Stop updateses.close()
Server event bodydata: Hello\n\n with Content-Type: text/event-stream

Live Preview

Simulate an SSE feed updating an HTML list (same handler pattern as real EventSource.onmessage).

Simulated stream in the browser—no backend required. Real pages use new EventSource(url).

HTML preview

(clock idle)

    evtSource.onmessage = (e) => append(e.data)

    HTML Examples

    Five patterns: server stream shape, client EventSource, errors, custom events, and a full HTML clock page. Try It demos simulate the stream so you can practice handlers without Node.

    Example 1 — Minimal SSE Server (Node.js)

    Respond with text/event-stream and push a time string every second:

    JS
    const http = require("http");
    
    http.createServer(function (req, res) {
      res.writeHead(200, {
        "Content-Type": "text/event-stream",
        "Cache-Control": "no-cache",
        "Connection": "keep-alive"
      });
    
      setInterval(function () {
        res.write("data: " + new Date().toLocaleTimeString() + "\n\n");
      }, 1000);
    }).listen(8080);
    Try It Yourself

    How It Works

    1. MIME type — text/event-stream tells the browser this is SSE.
    2. data: line — payload the client reads as event.data.
    3. Blank line — \n\n ends one event so the browser can dispatch it.
    4. Keep-alive — long response; do not buffer/cache the stream.

    Example 2 — Receive Messages in the HTML Page

    Connect with EventSource and log each default message:

    JS
    var eventSource = new EventSource("http://localhost:8080");
    
    eventSource.onmessage = function (event) {
      console.log("New message:", event.data);
    };
    Try It Yourself

    How It Works

    1. EventSource(url) opens the HTTP stream to that path.
    2. onmessage runs for events without an event: field.
    3. event.data is always a string—use JSON.parse when the server sends JSON.
    4. DOM tip — replace console.log with updating an HTML element’s text.

    Example 3 — Handle Connection Errors

    Log failures while the browser tries to reconnect:

    JS
    eventSource.onerror = function () {
      console.error("Connection error. Retrying...");
    };
    Try It Yourself

    How It Works

    1. onerror fires on network issues or failed responses.
    2. Auto-reconnect continues unless you call close().
    3. Show status in the HTML UI so users know the feed is retrying.
    4. Server retry: field can tune the wait in milliseconds.

    Example 4 — Custom Event Types

    When the server sets event: news, listen by name instead of onmessage:

    JS
    // Server sends:
    // event: news
    // data: Breaking story
    // (blank line)
    
    eventSource.addEventListener("news", function (event) {
      console.log("News:", event.data);
    });
    Try It Yourself

    How It Works

    1. event: name on the wire maps to a DOM event name.
    2. addEventListener routes news vs alerts vs chat to different HTML UI.
    3. Default messages (no event:) still use onmessage.
    4. You can mix named and unnamed events in one stream.

    Example 5 — Full HTML Page (Live Clock)

    Wire SSE into a visible HTML element:

    HTML
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Server-Sent Events Example</title>
    </head>
    <body>
      <h1>Real-Time Clock</h1>
      <div id="clock"></div>
    
      <script>
        var eventSource = new EventSource("http://localhost:8080");
    
        eventSource.onmessage = function (event) {
          document.getElementById("clock").textContent = event.data;
        };
    
        eventSource.onerror = function () {
          console.error("Connection error. Retrying...");
        };
      </script>
    </body>
    </html>
    Try It Yourself

    How It Works

    1. HTML shell holds a target element for live text.
    2. EventSource connects to the stream from Example 1.
    3. onmessage writes each data: payload into #clock.
    4. No page reload — the document updates continuously.

    Edge Cases & Pitfalls

    SSE issues often come from headers, buffering, CORS, or connection limits—not from HTML markup itself.

    mime

    Wrong Content-Type

    Must be text/event-stream. HTML/JSON content types will not drive EventSource correctly.

    buffer

    Proxy / server buffering

    Disable response buffering so each event reaches the browser promptly (for example X-Accel-Buffering: no on some proxies).

    blank

    Missing blank line

    Each event must end with \n\n. Without it, the browser never dispatches the message to your HTML handler.

    cors

    Cross-origin streams

    Different origins need CORS headers. Use withCredentials: true only when cookies are required and allowed.

    limit

    Too many open tabs (HTTP/1.1)

    Browsers cap concurrent SSE connections per domain. Prefer HTTP/2 and call close() when leaving a page.

    xss

    Injecting event.data as HTML

    Treat stream data as untrusted. Prefer textContent over innerHTML when updating the page.

    Browser Support

    EventSource / Server-Sent Events are widely available in modern browsers (including use from workers where supported).

    ✓ Baseline · Widely available

    SSE in HTML pages

    Live server→page updates with EventSource work across current browsers for same-origin (and CORS-enabled) streams.

    95%+ EventSource support
    Google Chrome All versions · Desktop & Mobile
    Full support
    Mozilla Firefox All versions · Desktop & Mobile
    Full support
    Apple Safari All versions · macOS & iOS
    Full support
    Microsoft Edge All versions · Chromium & Legacy
    Full support
    Internet Explorer IE 6+ · Legacy environments
    Full support
    Opera All modern versions
    Full support
    Server-Sent Events Wide

    Bottom line: Build HTML pages with EventSource confidently—watch connection limits and always set text/event-stream on the server.

    Key Takeaways

    • SSE pushes server→HTML page over HTTP; one-way only.
    • EventSource in a page script listens and updates the DOM.
    • Format: data: lines + blank line; MIME text/event-stream.
    • Named events use event: + addEventListener.

    One line: Stream text/event-stream from the server → EventSource in the HTML page → update the DOM from event.data.

    Frequently Asked Questions

    SSE lets a server push text updates to your HTML page over one long-lived HTTP connection. A script creates an EventSource, listens for message (or named) events, and updates the DOM—without the page polling.
    SSE is one-way (server → browser) over ordinary HTTP with a simple text stream. WebSockets are two-way and use a different protocol. Prefer SSE for live feeds, notifications, and dashboards where only the server sends updates.
    EventSource is the browser API for SSE. Call new EventSource(url), handle onmessage or addEventListener for custom types, and optionally onerror. The browser reconnects automatically if the connection drops unless you call close().
    Content-Type: text/event-stream, usually with Cache-Control: no-cache. Each event is UTF-8 text lines ending with a blank line (two newlines), for example data: Hello followed by \n\n.
    In onmessage, read event.data (a string) and write it into the page—textContent on an element, append a list item, or JSON.parse then fill several fields.
    Messages with an event: field become custom events. Listen with addEventListener("ping", …). Messages without event: fire the default message event (onmessage).

    Practice client handlers

    Open a Try It demo that simulates the stream and updates HTML elements.

    Open Try It editor →

    About the author

    Mari Selvan M P
    Mari Selvan M P 🔗

    Developer, cloud engineer, and technical writer

    • Experience 12 years building web and cloud systems
    • Focus Full Stack Development, AWS, and Developer Education

    I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

    8 people found this page helpful