eventsource



WhatWG/W3C-compatible server-sent events/eventsource client. The module attempts to implement an absolute minimal amount of features/changes beyond the specification.
If you're looking for a modern alternative with a less constrained API, check out the eventsource-client package.
Installation
npm install --save eventsource
Supported engines
Basically, any environment that supports:
If you need to support runtimes without private class fields, methods and accessors, try the 4.x branch/version range.
If you need to support even older runtimes, try the 2.x branch/version range (note: 2.x branch is primarily targeted at Node.js, not browsers).
Usage
import {EventSource} from 'eventsource'
const es = new EventSource('https://my-server.com/sse')
es.addEventListener('notice', (event) => {
console.log(event.data)
})
es.addEventListener('update', (event) => {
console.log(event.data)
})
es.addEventListener('message', (event) => {
console.log(event.data)
})
setTimeout(() => {
es.close()
}, 10_000)
TypeScript
Make sure you have configured your TSConfig so it matches the environment you are targetting. If you are targetting browsers, this would be dom:
{
"compilerOptions": {
"lib": ["dom"],
},
}
If you're using Node.js, ensure you have @types/node installed (and it is version 22 or higher). Cloudflare workers have @cloudflare/workers-types etc.
The following errors are caused by targetting an environment that does not have the necessary types available:
error TS2304: Cannot find name 'Event'.
error TS2304: Cannot find name 'EventTarget'.
error TS2304: Cannot find name 'MessageEvent'.
Safari and WebKit
Safari/WebKit encodes non-ASCII Last-Event-ID header values as UTF-8 a second time, so the server receives a different ID on reconnect. This affects accented characters, currency symbols and emoji. Event data and MessageEvent.lastEventId retain their original Unicode values.
For the widest client compatibility, we recommend that servers use ASCII-only values in the event stream's id field. See WebKit's header encoding for the underlying behavior.
Cloudflare Workers
Cloudflare Workers require compatibilityDate: '2024-11-11' or later, and addEventListener() instead of the onmessage, onopen and onerror properties.
workerd's EventTarget dispatches on<type> handler properties itself, on top of the listener this module registers, so a handler assigned that way is called twice per event - and assigning null only removes one of the two registrations, so it does not unsubscribe (workerd#6022).
eventSource.onmessage = (event) => console.log(event.data)
eventSource.addEventListener('message', (event) => console.log(event.data))
workerd also drops origin and lastEventId from the MessageEvent constructor. This module assigns them itself, so both are correct on Workers today; the workaround goes away once workerd#6995 lands.
Workers' native fetch encodes header values as UTF-8 itself. This module passes it the original event ID to avoid encoding twice. Custom fetch implementations receive a UTF-8 byte string; wrappers that forward to Workers' native fetch must decode Last-Event-ID back to Unicode first.
Migrating from v1 / v2
See MIGRATION.md for a detailed migration guide.
Extensions to the WhatWG/W3C API
Message and code properties on errors
The error event has a message and code property that can be used to get more information about the error. In the specification, the Event
es.addEventListener('error', (err) => {
if (err.code === 401 || err.code === 403) {
console.log('not authorized')
}
})
Limit parser buffer size
The parser buffers up to 100 MB while waiting for a complete EventSource line. To change that limit, pass maxBufferSize in the constructor options:
const es = new EventSource('https://my-server.com/sse', {
maxBufferSize: 10 * 1024 * 1024,
})
If the limit is exceeded, the connection fails and emits an error event, and will not reconnect. Prefer servers that emit smaller chunks or newlines more frequently over increasing this limit.
Specify fetch implementation
The EventSource constructor accepts an optional fetch property in the second argument that can be used to specify the fetch implementation to use.
This can be useful in environments where the global fetch function is not available - but it can also be used to alter the request/response behaviour.
const es = new EventSource('https://my-server.com/sse', {
fetch: (input, init) =>
fetch(input, {
...init,
headers: {
...init.headers,
Authorization: 'Bearer myToken',
},
}),
})
HTTP/HTTPS proxy
Use a package like undici to add proxy support, either through environment variables or explicit configuration.
import {fetch, EnvHttpProxyAgent} from 'undici'
const proxyAgent = new EnvHttpProxyAgent()
const es = new EventSource('https://my-server.com/sse', {
fetch: (input, init) => fetch(input, {...init, dispatcher: proxyAgent}),
})
Using HTTP2
Use a package like undici that supports HTTP2.
import {Agent, fetch} from 'undici'
const http2Dispatcher = new Agent({allowH2: true})
const es = new EventSource('https://my-server.com/sse', {
fetch: (url, init) => fetch(url, {...init, dispatcher: http2Dispatcher}),
})
Allow unauthorized HTTPS requests
Use a package like undici for more control of fetch options through the use of an Agent.
import {fetch, Agent} from 'undici'
const unsafeAgent = new Agent({
connect: {
rejectUnauthorized: false,
},
})
await fetch('https://my-server.com/sse', {
dispatcher: unsafeAgent,
})
Feature checking
For library authors, you may want to feature-check if an EventSource implementation supports passing a custom fetch implementation (such as this library does). We declare (from v4.1.0 and onwards) a non-enumerable symbol on the EventSource class to indicate this, named eventsource.supports-fetch-override. It can be used downstream such as:
function yourLibrary(options) {
const OurEventSource = options.polyfills.EventSource || globalThis.EventSource
if (OurEventSource && Symbol.for('eventsource.supports-fetch-override') in OurEventSource) {
const es = new OurEventSource('https://some.url', {
fetch: (input, init) =>
fetch(input, {
...init,
headers: {
...(init.headers || {}),
'x-some-header': 'foo',
},
}),
})
}
}
License
MIT-licensed. See LICENSE.