Real-Time Streaming
WebSocket push, channel subscriptions, and polling fallback for live updates.
Hookstream pushes updates to connected clients in real-time over WebSockets. Under the hood, a per-org EventStream Durable Object manages every connection using Cloudflare's Hibernatable WebSocket API — so idle connections cost you nothing.
Connect to the stream
Get an API key
Generate one from Settings → API Keys or via the CLI:
bashhookstream api-keys create --name "streaming"
Open a WebSocket
The endpoint is wss://hookstream.io/v1/ws?token=<api_key>. In the browser, session cookies also work automatically.
import WebSocket from "ws";
const ws = new WebSocket(`wss://hookstream.io/v1/ws?token=${process.env.HOOKSTREAM_API_KEY}`);
ws.on("open", () => {
ws.send(JSON.stringify({ type: "subscribe", channel: "events" }));
});
ws.on("message", (raw) => {
const msg = JSON.parse(raw.toString());
console.log(msg.type, msg.data);
});websocat "wss://hookstream.io/v1/ws?token=$HOOKSTREAM_API_KEY"Subscribe to channels
On connect, hookstream sends a welcome message with your org_id. Send { "type": "subscribe", "channel": "<name>" } for every channel you want to receive.
Available channels
events— every new event, across all sources in the org.events:<source_id>— events from a single source.deliveries— completed delivery attempts across all destinations.deliveries:<destination_id>— delivery attempts for a single destination.issues— issue created, updated, or resolved.collections:<collection_id>— Instant Database sync events.
Subscribe to as many as you like — the DO uses Cloudflare's native tag-based filtering so you only receive messages for channels you asked for.
Message format
Every message is JSON with a type and a channel:
json{ "type": "event", "channel": "events", "data": { "...full event object..." } } { "type": "delivery", "channel": "deliveries", "data": { "...full delivery attempt..." } } { "type": "issue", "channel": "issues", "data": { "...full issue object..." } }
The data field is the complete resource — the same shape you'd get from the REST API.
Reconnect automatically
The dashboard's useEventStream hook handles reconnection with exponential backoff (1s → 2s → 4s → capped at 30s) and re-sends channel subscriptions after reconnecting. If you're writing your own client, mirror that behavior.
Polling fallback
Every dashboard page also polls the REST API on an interval, just in case the WebSocket drops. When connected, polling slows down to 30 seconds. When disconnected, it speeds up to 5 seconds so the UI stays fresh. The usePolling hook in the frontend manages this automatically.
If you're building your own client, the same pattern works — treat the WebSocket as the fast path and the REST API as the safety net.