If you are building real-time AI applications, Server-Sent Events (SSE) provides a lightweight alternative to WebSockets for streaming responses from server to client. In this hands-on guide, I will walk you through every aspect of EventSource compatibility across browsers, highlight the differences you need to understand, and provide working polyfill solutions that work seamlessly with the HolySheheep AI streaming API. By the end, you will have a production-ready streaming implementation that works on every browser your users might have.

Understanding Server-Sent Events and EventSource

Server-Sent Events allow a server to push data to your web application automatically. Unlike traditional HTTP requests where the client initiates communication, SSE enables the server to send new data whenever it becomes available. This makes SSE perfect for streaming AI responses, live notifications, progress updates, and real-time dashboards.

The EventSource API is the browser built-in interface for handling SSE. Here is the fundamental concept: your browser creates a one-way connection to a server endpoint, and the server sends events formatted as plain text. The browser parses these events and dispatches them to your JavaScript event handlers.

The Basic EventSource Pattern

// Basic EventSource connection to HolySheep AI streaming endpoint
const eventSource = new EventSource('https://api.holysheep.ai/v1/chat/stream', {
  headers: {
    'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY',
    'Content-Type': 'application/json'
  }
});

eventSource.onmessage = function(event) {
  const data = JSON.parse(event.data);
  console.log('Received:', data);
};

eventSource.onerror = function(error) {
  console.error('EventSource failed:', error);
  eventSource.close();
};

Browser Compatibility: What You Need to Know

EventSource has excellent support across modern browsers, but implementation differences can cause subtle bugs. From my experience testing across multiple browsers during production deployments, here are the critical differences you must handle.

Full EventSource Support (No Polyfill Needed)

Limited or No Native Support (Requires Polyfill)

The Cross-Origin Request Problem

One of the biggest compatibility issues involves Cross-Origin Resource Sharing (CORS). EventSource supports CORS, but the preflight request behavior varies between browsers. Chrome and Firefox send standard CORS preflight requests, while Safari handles them differently in certain configurations.

When connecting to HolySheep AI from your application, you need to ensure your server or proxy handles CORS headers correctly. The HolySheep AI API supports CORS for streaming endpoints, but you must include the appropriate headers in your requests.

Implementing SSE Streaming with HolySheep AI

The HolySheep AI API provides streaming endpoints that support SSE for real-time AI responses. With pricing at just $1 per dollar equivalent (compared to ¥7.3 elsewhere, saving over 85%), and latency under 50ms, it provides an excellent foundation for building responsive AI applications.

Let me walk you through a complete implementation step by step.

Step 1: Setting Up the Request

// Complete streaming implementation with EventSource
// Using HolySheep AI API - pricing: GPT-4.1 $8/MTok, Claude Sonnet 4.5 $15/MTok

function createStreamingConnection(messages, onChunk, onComplete, onError) {
  const url = 'https://api.holysheep.ai/v1/chat/completions';
  
  // Prepare the request body
  const body = JSON.stringify({
    model: 'gpt-4.1',
    messages: messages,
    stream: true
  });

  // Use fetch with ReadableStream for modern browsers
  fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY',
      'Content-Type': 'application/json'
    },
    body: body
  })
  .then(response => {
    if (!response.ok) {
      throw new Error(HTTP error! status: ${response.status});
    }
    
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';

    function read() {
      reader.read().then(({ done, value }) => {
        if (done) {
          if (buffer.length > 0) {
            processBuffer(buffer, onChunk);
          }
          onComplete();
          return;
        }

        buffer += decoder.decode(value, { stream: true });
        processBuffer(buffer, onChunk);
        read();
      });
    }

    read();
  })
  .catch(error => {
    onError(error);
  });
}

function processBuffer(buffer, callback) {
  // Split by newlines and process complete lines
  const lines = buffer.split('\n');
  buffer = lines.pop(); // Keep incomplete line in buffer
  
  for (const line of lines) {
    if (line.startsWith('data: ')) {
      const data = line.slice(6);
      if (data === '[DONE]') continue;
      
      try {
        const parsed = JSON.parse(data);
        if (parsed.choices && parsed.choices[0].delta.content) {
          callback(parsed.choices[0].delta.content);
        }
      } catch (e) {
        console.warn('Parse error:', e);
      }
    }
  }
}

// Usage example
createStreamingConnection(
  [{ role: 'user', content: 'Explain SSE in simple terms' }],
  (chunk) => {
    document.getElementById('output').textContent += chunk;
  },
  () => console.log('Stream complete'),
  (error) => console.error('Error:', error)
);

Step 2: Adding Reconnection Logic

Network connections drop unexpectedly. A robust SSE implementation must handle reconnection gracefully. Here is how to implement automatic reconnection with exponential backoff.

// Robust EventSource wrapper with automatic reconnection
class RobustEventSource {
  constructor(url, options = {}) {
    this.url = url;
    this.options = options;
    this.eventSource = null;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = options.maxReconnectAttempts || 5;
    this.baseReconnectDelay = options.baseReconnectDelay || 1000;
    this.isConnecting = false;
  }

  connect() {
    if (this.isConnecting) return;
    this.isConnecting = true;

    try {
      this.eventSource = new EventSource(this.url, this.options);
      
      this.eventSource.onopen = () => {
        console.log('Connected to SSE stream');
        this.reconnectAttempts = 0;
        this.isConnecting = false;
        if (this.options.onOpen) this.options.onOpen();
      };

      this.eventSource.onmessage = (event) => {
        if (this.options.onMessage) {
          this.options.onMessage(event);
        }
      };

      this.eventSource.onerror = (error) => {
        console.error('EventSource error:', error);
        this.isConnecting = false;
        
        if (this.reconnectAttempts < this.maxReconnectAttempts) {
          this.scheduleReconnect();
        } else {
          console.error('Max reconnection attempts reached');
          if (this.options.onError) this.options.onError(error);
        }
      };

      // Handle custom event types
      if (this.options.eventTypes) {
        for (const eventType of this.options.eventTypes) {
          this.eventSource.addEventListener(eventType, (event) => {
            if (this.options.onCustomEvent) {
              this.options.onCustomEvent(eventType, event);
            }
          });
        }
      }

    } catch (error) {
      console.error('Failed to create EventSource:', error);
      this.isConnecting = false;
      if (this.options.onError) this.options.onError(error);
    }
  }

  scheduleReconnect() {
    const delay = this.baseReconnectDelay * Math.pow(2, this.reconnectAttempts);
    console.log(Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts + 1}));
    
    setTimeout(() => {
      this.reconnectAttempts++;
      this.eventSource.close();
      this.connect();
    }, delay);
  }

  close() {
    if (this.eventSource) {
      this.eventSource.close();
      this.eventSource = null;
    }
    this.isConnecting = false;
  }
}

// Usage with HolySheep AI
const stream = new RobustEventSource(
  'https://api.holysheep.ai/v1/stream',
  {
    headers: {
      'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY'
    },
    eventTypes: ['chunk', 'done', 'error'],
    maxReconnectAttempts: 3,
    baseReconnectDelay: 1000,
    onMessage: (event) => {
      console.log('Received:', event.data);
    },
    onError: (error) => {
      console.error('Stream error:', error);
    }
  }
);

stream.connect();

Creating a Polyfill for Legacy Browsers

When you need to support Internet Explorer or older mobile browsers, you need a polyfill that simulates EventSource behavior using XMLHttpRequest or the Fetch API with streaming support. Here is a complete, production-ready polyfill.

// EventSource Polyfill for legacy browser support
(function(global) {
  'use strict';

  if (typeof global.EventSource !== 'undefined') {
    return;
  }

  function EventSourcePolyfill(url, options = {}) {
    this.url = url;
    this.readyState = 0;
    this.onopen = null;
    this.onmessage = null;
    this.onerror = null;
    this.listeners = {};
    this.xhr = null;
    this.buffer = '';
    this.isClosed = false;

    this.connect();
  }

  EventSourcePolyfill.CONNECTING = 0;
  EventSourcePolyfill.OPEN = 1;
  EventSourcePolyfill.CLOSED = 2;

  EventSourcePolyfill.prototype.connect = function() {
    var self = this;
    this.readyState = 0;

    // Use XDomainRequest for IE8/9, XMLHttpRequest otherwise
    if (typeof XDomainRequest !== 'undefined') {
      this.xhr = new XDomainRequest();
      this.xhr.open('GET', this.url, true);
    } else {
      this.xhr = new XMLHttpRequest();
      this.xhr.open('GET', this.url, true);
    }

    this.xhr.onprogress = function() {
      self.handleProgress();
    };

    this.xhr.onload = function() {
      self.readyState = 2;
      if (self.onload) self.onload();
    };

    this.xhr.onerror = function() {
      self.readyState = 2;
      if (self.onerror) self.onerror({ type: 'error' });
      self.dispatchEvent('error', { type: 'error' });
    };

    // Set headers if provided
    if (options.headers) {
      for (var header in options.headers) {
        try {
          this.xhr.setRequestHeader(header, options.headers[header]);
        } catch (e) {
          console.warn('Cannot set header:', header);
        }
      }
    }

    this.xhr.send();
  };

  EventSourcePolyfill.prototype.handleProgress = function() {
    if (this.isClosed) return;

    var data = this.xhr.responseText || '';
    var newData = data.slice(this.buffer.length);
    this.buffer = data;

    if (newData) {
      this.processData(newData);
    }
  };

  EventSourcePolyfill.prototype.processData = function(data) {
    var lines = data.split(/\r\n|\n/);
    var eventType = 'message';
    var eventData = '';

    for (var i = 0; i < lines.length; i++) {
      var line = lines[i];
      var colonIndex = line.indexOf(':');

      if (colonIndex === 0) continue;

      if (colonIndex > 0) {
        var field = line.substring(0, colonIndex);
        var value = line.substring(colonIndex + 1).trim();

        if (field === 'event') {
          eventType = value;
        } else if (field === 'data') {
          eventData += value + '\n';
        }
      } else if (line === '') {
        var event = new MessageEvent(eventType, {
          data: eventData.slice(0, -1),
          origin: this.url
        });

        if (eventType === 'message' && this.onmessage) {
          this.onmessage(event);
        }

        this.dispatchEvent(eventType, event);
        eventData = '';
        eventType = 'message';
      }
    }
  };

  EventSourcePolyfill.prototype.close = function() {
    this.isClosed = true;
    this.readyState = 2;
    if (this.xhr) {
      this.xhr.abort();
    }
  };

  EventSourcePolyfill.prototype.addEventListener = function(type, listener) {
    if (!this.listeners[type]) {
      this.listeners[type] = [];
    }
    this.listeners[type].push(listener);
  };

  EventSourcePolyfill.prototype.removeEventListener = function(type, listener) {
    if (!this.listeners[type]) return;
    var index = this.listeners[type].indexOf(listener);
    if (index > -1) {
      this.listeners[type].splice(index, 1);
    }
  };

  EventSourcePolyfill.prototype.dispatchEvent = function(type, event) {
    if (!this.listeners[type]) return;
    for (var i = 0; i < this.listeners[type].length; i++) {
      this.listeners[type][i].call(this, event);
    }
  };

  global.EventSource = EventSourcePolyfill;

})(typeof window !== 'undefined' ? window : this);

Testing Your Implementation

I always recommend testing your SSE implementation across multiple browsers before deploying to production. Here is a simple test harness you can use.

// Browser compatibility test suite
function testSSECompatibility() {
  const results = {
    nativeEventSource: false,
    polyfillLoaded: false,
    streamingSupported: false,
    corsSupported: false
  };

  // Test 1: Check for native EventSource
  results.nativeEventSource = typeof EventSource !== 'undefined';
  console.log('Native EventSource:', results.nativeEventSource ? 'PASS' : 'FAIL');

  // Test 2: Check if polyfill loaded
  results.polyfillLoaded = typeof EventSource !== 'undefined';
  console.log('EventSource available:', results.polyfillLoaded ? 'PASS' : 'FAIL');

  // Test 3: Test streaming with Fetch API
  fetch('https://api.holysheep.ai/v1/models', {
    headers: { 'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY' }
  })
  .then(response => {
    results.streamingSupported = response.body && response.body.getReader !== undefined;
    console.log('Fetch Streaming:', results.streamingSupported ? 'PASS' : 'FAIL');
  })
  .catch(() => {
    console.log('Fetch Streaming: FAIL');
  });

  // Test 4: Test CORS support
  const testCORS = new EventSource('https://api.holysheep.ai/v1/health');
  testCORS.onopen = () => {
    results.corsSupported = true;
    console.log('CORS Support: PASS');
    testCORS.close();
  };
  testCORS.onerror = () => {
    console.log('CORS Support: FAIL (or endpoint does not exist)');
  };

  return results;
}

// Run tests
document.addEventListener('DOMContentLoaded', () => {
  const testResults = testSSECompatibility();
  
  // Display results in UI
  const resultsDiv = document.createElement('div');
  resultsDiv.innerHTML = `
    

SSE Compatibility Test Results

  • Native EventSource: ${testResults.nativeEventSource ? '✓' : '✗'}
  • EventSource Available: ${testResults.polyfillLoaded ? '✓' : '✗'}
  • Streaming Supported: ${testResults.streamingSupported ? '✓' : '✗'}
  • CORS Supported: ${testResults.corsSupported ? '✓' : '✗'}
`; document.body.appendChild(resultsDiv); });

Common Errors and Fixes

Error 1: "EventSource is not defined" in Internet Explorer

Internet Explorer does not support EventSource natively. You must include the polyfill before any code that uses EventSource.

<!-- Solution: Include polyfill first in your HTML -->
<script src="eventsource-polyfill.js"></script>
<script src="your-app-code.js"></script>

Error 2: CORS Error When Connecting to API

If you see CORS errors in the console, ensure your server is setting the correct headers. For HolySheep AI, the API already handles CORS, but if you are proxying requests through your own server, add these headers:

// Server-side solution for CORS headers
// Example for Node.js Express
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
  res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  
  // Handle preflight requests
  if (req.method === 'OPTIONS') {
    return res.sendStatus(200);
  }
  next();
});

Error 3: "Failed to construct EventSource: URL scheme must be 'http' or 'https'"

This error occurs when using EventSource with data: URLs or file: URLs. EventSource only works with HTTP and HTTPS endpoints. If you are testing locally without HTTPS, use http://localhost instead of file://.

// Wrong - will fail
const source = new EventSource('file:///path/to/stream');

// Correct - use HTTP/HTTPS
const source = new EventSource('https://api.holysheep.ai/v1/stream');

// For local development
const source = new EventSource('http://localhost:3000/api/stream');

Error 4: Stream Stops After 30 Seconds

Some proxies and load balancers have default timeout settings that close long-running connections. Implement heartbeat messages from the server and client-side reconnection logic to handle this.

// Client-side heartbeat to keep connection alive
class HeartbeatEventSource {
  constructor(url, options = {}) {
    this.url = url;
    this.eventSource = new EventSource(url, options);
    this.heartbeatInterval = options.heartbeatInterval || 15000;
    this.lastActivity = Date.now();
    this.intervalId = null;
    
    // Listen for any message to track activity
    this.eventSource.addEventListener('message', () => {
      this.lastActivity = Date.now();
    });
    
    this.startHeartbeat();
  }
  
  startHeartbeat() {
    this.intervalId = setInterval(() => {
      const idle = Date.now() - this.lastActivity;
      if (idle > this.heartbeatInterval * 2) {
        console.log('Connection appears dead, reconnecting...');
        this.reconnect();
      }
    }, this.heartbeatInterval);
  }
  
  reconnect() {
    this.eventSource.close();
    this.eventSource = new EventSource(this.url);
  }
  
  close() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
    }
    this.eventSource.close();
  }
}

Best Practices for Production Deployments

After testing and implementing SSE streaming, follow these practices to ensure reliability in production environments.

Conclusion

Server-Sent Events provide a robust, standards-based way to stream data from servers to browsers. While browser support is generally good, understanding the implementation differences and having a solid polyfill strategy ensures your applications work for all users. The techniques covered in this guide, combined with the HolySheep AI streaming API, give you everything you need to build responsive, real-time AI applications.

With HolySheep AI pricing at $1 per dollar equivalent (compared to ¥7.3 elsewhere), support for WeChat and Alipay payments, latency under 50ms, and free credits on signup, you have a cost-effective and reliable backend for your streaming applications. The