Skip to content

Sse Event Stream Format

DodaTech 4 min read

title: "SSE Event Stream Format" description: "Learn the Server-Sent Events event stream format including data fields, event types, IDs, retry intervals, and protocol rules." weight: 13 date: 2026-06-28 lastmod: 2026-06-28 tags: ["apis", "sse"]


The SSE event stream format defines how data is structured and transmitted from server to client. Understanding the format is essential for building correct SSE implementations.

## What You'll Learn

- SSE event stream structure
- Field types: data, event, id, retry
- Comment lines
- Event boundaries
- UTF-8 encoding requirements

## Why It Matters

Correctly formatted SSE streams ensure reliable parsing on the client side. Format errors cause parsing failures, lost events, or broken connections.

## Real-World Use

A real-time monitoring system sends structured SSE events with fields for event type, metric name, value, and a unique ID for tracking. The client parses each field to update specific dashboard widgets.

## Flow Chart

```mermaid
flowchart LR
    A[SSE Stream] --> B[Field: event]
    A --> C[Field: data]
    A --> D[Field: id]
    A --> E[Field: retry]
    B --> F[Named Event Type]
    C --> G[Payload String]
    D --> H[Last Event ID]
    E --> I[Reconnection Time]

Code Examples

Example 1: All SSE Field Types

// Server sending different SSE fields
const http = require('http');

http.createServer((req, res) => {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
  });

  // Comments start with ':'
  res.write(': This is a comment line\n\n');

  // Send event with all fields
  res.write(
    'id: event-001\n' +
    'event: user-update\n' +
    'data: {"name": "Alice", "status": "online"}\n' +
    '\n'
  );

  // Send another event
  res.write(
    'id: event-002\n' +
    'data: {"message": "Hello World"}\n' +
    '\n'
  );

  // Multi-line data field
  res.write(
    'id: event-003\n' +
    'data: {\n' +
    'data: "line1",\n' +
    'data: "line2"\n' +
    'data: }\n' +
    '\n'
  );

  // Set reconnection time
  res.write('retry: 5000\n\n');

  // Send without event type
  res.write(
    'id: event-004\n' +
    'data: unnamed event\n' +
    '\n'
  );

}).listen(3000);

Expected output: Client receives events with different field combinations, including named events, IDs, multi-line data, and retry interval.

Example 2: Client Parsing Different Fields

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

// Handle named events
source.addEventListener('user-update', (event) => {
  console.log('Event type:', event.type);
  console.log('Event ID:', event.lastEventId);
  console.log('Data:', event.data);
});

// Handle unnamed events (onmessage)
source.onmessage = (event) => {
  console.log('Unnamed event');
  console.log('ID:', event.lastEventId);
  console.log('Data:', event.data);
};

// Track last event ID for reconnection
let lastEventId = null;
source.onmessage = (event) => {
  lastEventId = event.lastEventId || lastEventId;
  processEvent(event.data);
};

// The client sends Last-Event-ID header on reconnection
// Server can read it from the request headers

Expected output: Client correctly parses event types, IDs, and data fields, tracking the last event ID for reconnection.

Example 3: Proper Event Stream Generation

function sendSSEEvent(res, options = {}) {
  const {
    data,
    event,
    id,
    retry,
  } = options;

  let message = '';

  // Event type (optional)
  if (event) {
    message += `event: ${event}\n`;
  }

  // Data (required)
  if (data) {
    // Handle multi-line data
    const lines = String(data).split('\n');
    lines.forEach(line => {
      message += `data: ${line}\n`;
    });
  }

  // Event ID (optional)
  if (id) {
    message += `id: ${id}\n`;
  }

  // Retry interval (optional)
  if (retry) {
    message += `retry: ${retry}\n`;
  }

  // Empty line terminates the event
  message += '\n';

  res.write(message);
}

// Usage
sendSSEEvent(res, {
  event: 'stock-price',
  data: JSON.stringify({
    symbol: 'AAPL',
    price: 175.50,
    change: 2.30,
  }),
  id: `stock-${Date.now()}`,
});

sendSSEEvent(res, {
  data: 'Simple message without type or ID',
});

Expected output: A reusable function that generates properly formatted SSE events with all optional fields.

Common Mistakes

Mistake Explanation
Missing trailing newlines Each event must end with \n\n (two newlines)
Using wrong field names Valid fields are event, data, id, and retry only
Including colons in field names Field names must not contain colons; the colon separates field name from value
Sending binary data SSE only supports UTF-8 text; binary must be Base64-encoded
Not escaping newlines in data Data containing newlines must be split across multiple data: lines

Practice Questions

  1. What are the four field types in SSE?
  2. How do you send multi-line data in SSE?
  3. What is the purpose of the id field?
  4. How does the retry field affect the client?
  5. What is the purpose of comment lines starting with :?

Challenge

Build an SSE event generator that creates a properly formatted stream with named events, IDs, and retry intervals. Include multi-line data and comments. Create a test client that validates each event format.

FAQ

What is the maximum field length in SSE?

There is no specified maximum, but practical limits depend on the HTTP implementation. Most servers handle up to 64KB per field.

Can I include HTML in SSE data?

Yes, but you must escape it properly. The client should treat SSE data as plain text until explicitly rendered.

What happens if a field name is invalid?

Invalid fields are ignored by the browser's EventSource parser. Only event, data, id, and retry are recognized.

Can I have multiple lines with the same field?

Yes, multiple data: lines are concatenated with newlines. Multiple id: lines result in the last ID being used.

How do I send an empty event?

Send just the terminating newlines \n\n. The client will fire an onmessage event with empty data.

Is the event stream format case-sensitive?

Field names are case-sensitive. Use lowercase event, data, id, retry.

Mini Project

Build an SSE stream inspector tool that connects to any SSE endpoint, displays each event with its fields, shows raw stream content, and validates the event format. Include the ability to send test events for debugging.

What's Next

Learn about the EventSource API in browsers

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro