Skip to content

Real-time event streaming to browsers and services

Subscribe a dashboard, a worker or another service to your events over WebSocket. Filter what each consumer sees, resume after a disconnect, and send signed webhooks to as many endpoints as you need.

The problem

Getting events to a live UI sounds easy until it has to survive real networks. A tab sleeps, a phone changes towers, a deploy restarts your socket server. Pub/sub libraries tell you a message was published; they rarely tell you which messages one particular client missed.

Server-to-server delivery has the opposite problem. A consumer can be down for an hour, and you need retries, backoff, signatures so the receiver can trust the call, and a log that explains what happened to each delivery.

Teams usually end up with two systems: one for browsers and one for services, both fed by the same events.

How Eventeer handles it

  • WebSocket streams

    A stream has its own URL and token. Browsers pass the token as a query parameter; servers can use a bearer header.

  • Scoped and filtered

    Limit a stream to chosen listeners and match a single condition on the payload, such as type equals alarm, so each consumer gets only its slice.

  • Resume with since

    Reconnect with the last event id and Eventeer replays stored events first, then switches to live. Slow consumers are closed with 4408 and can resume the same way.

  • Destinations for servers

    Fan one event out to several HTTPS endpoints. Each request is signed with HMAC-SHA256 and retried with backoff, and failures show in a delivery log.

Delivery guarantees, stated plainly

Live stream frames are at-most-once. Eventeer does not buffer for a client that is not connected. The way to close a gap is replay: reconnect with since and read stored events from there. Replay is at-least-once and may repeat a few events around the cursor, so clients dedupe by id. Destinations are also at-least-once. Neither mode is exactly-once, and your consumers should be idempotent.

Replay has bounds

A replay sends at most 1,000 events per connect. If more are pending you get a replay_truncated frame with the next id, and you reconnect from there. Events older than your plan's retention are gone, so replay cannot reach past 7, 30 or 90 days. A stream can also turn replay off.

Billing

Each frame sent counts one delivered event, and each open stream socket meters connection minutes. Retries of a destination delivery are not billed again. Details are on the pricing page.

What it looks like

A consumer connects, remembers the last event id, and passes it as since when it reconnects. The frame shape matches the body Eventeer posts to destinations.

Subscribe from a browser and resume with since
// Browser or Node: subscribe to a stream and resume after a drop
let lastId = localStorage.getItem("lastId") ?? "";
const seen = new Set();

function connect() {
  const url = `wss://app.eventeer.io/out/s/${STREAM_KEY}?token=${TOKEN}&since=${lastId}`;
  const ws = new WebSocket(url);
  ws.onmessage = (m) => {
    const f = JSON.parse(m.data);
    if (f.type !== "event" || seen.has(f.id)) return; // dedupe replay overlap
    seen.add(f.id);
    lastId = f.id;
    render(f.data);
  };
  ws.onclose = () => setTimeout(connect, 1000);
}
connect();

Questions

Are live stream frames guaranteed to arrive?
No. Live frames are at-most-once: if your socket is down or too slow, you miss them. Reconnect with since set to the last id you saw and Eventeer replays stored events, up to 1,000 per connect, then sends a live marker.
Can replay produce duplicates?
Yes, by design. Replay is at-least-once and re-sends a small overlap window before since, so a late-committing event is not skipped. Dedupe on the event id, as in the sample above.
When should I use a destination instead of a stream?
Use a stream when a client can hold a connection and you want low latency. Use a destination when your server should receive a signed HTTPS POST: it retries 8 times over about 24 hours and keeps a delivery log.

Put your events on a live stream

Create a stream, copy the WebSocket URL and watch events appear the moment they are ingested.