Using Server-Sent Events for Real-Time Data Push

Modern web applications often require real-time updates from server to client. A common approach is WebSockets, but another mechanism—Server-Sent Events (SSE)—can serve this purpose efficiently using standard HTTP. SSE relies on the Content-Type: text/event-stream header defined in HTML5.

Server-Sent Events Overveiw

SSE provides a lightweight unidirectional channel where the server streams data to the browser. It is simpler than WebSockets because it uses plain HTTP and handles reconnection automatically. Typical use cases include live news feeds, stock tickers, and notification systems.

Comparison with WebSockets

Advantages of SSE:

  • Straightforward implementation over HTTP; no special handshake required.
  • Built-in reconnection handling ensures resilience to transient network failures.
  • Minimal overhead compared to full-duplex protocols; suitable for constrained bandwidth.
  • Supports cross-origin requests when proper CORS headers are configured.

Limitations of SSE:

  • Communication is server-to-client only; no native way for client-to-server messages.
  • Browser support may be incomplete in legacy environments.

Advantages of WebSockets:

  • Full-duplex communication enables interactive, bidirectional data exchange.
  • Lower latency and higher throughput for demanding real-time apps.
  • Scales well for complex scenarios like multiplayer games or collaborative editors.

Limitations of WebSockets:

  • More intricate setup due to protocol negotiation and framing.
  • May face connectivity issues behind restrictive proxies or firewalls.

For applications needing only downstream data flow, SSE offers an elegant solution. Where upstream messaging or high-frequency interaction is essential, WebSockets are preferable despite added complexity.

Example Implementation

Backend in Go

The server creates an event stream and pushes timestamped messaegs every two seconds.

package main

import (
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/antage/eventsource"
)

func main() {
	stream := eventsource.New(nil, nil)
	defer stream.Close()

	http.Handle("/", http.FileServer(http.Dir("./")))
	http.HandleFunc("/feed", func(w http.ResponseWriter, r *http.Request) {
		stream.Handler(r, w)
	})

	go func() {
		for {
			msg := fmt.Sprintf("update @ %s", time.Now().Format(time.RFC3339))
			stream.SendEventMessage(msg, "", "")
			log.Printf("Dispatched update (listeners: %d)", stream.ConsumersCount())
			time.Sleep(2 * time.Second)
		}
	}()

	log.Println("Access http://localhost:8080/ in your browser")
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal(err)
	}
}

Frontend in HTML/JavaScript

A simple page connects to the SSE endpoint and appends each incoming message to a list.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>SSE Demo</title>
</head>
<body>
  <h1>Live Event Stream</h1>
  <ul id="output"></ul>

  <script>
    document.addEventListener("DOMContentLoaded", () => {
      const src = new EventSource("http://localhost:8080/feed");
      const list = document.getElementById("output");

      src.onmessage = (e) => {
        const item = document.createElement("li");
        item.textContent = e.data;
        list.appendChild(item);
      };

      src.onerror = (e) => {
        console.log("Connection state:", e.target.readyState);
      };
    });
  </script>
</body>
</html>

The backend broadcasts messages at fixed intervals, and the frontend renders them in real time, demonstrating a basic SSE workflow.

Tags: Server-Sent Events Real-Time Web HTTP streaming Go javascript

Posted on Tue, 08 Sep 2026 16:46:05 +0000 by Perryl7