Realtime

Open a WebSocket to a collection or one of its fields and receive an event the instant a write commits.

Docs menu

Connect and subscribe

Connect to GET /v1/realtime and upgrade to a WebSocket, with the same auth as the REST API (Authorization: Bearer <key>). The server sends {"type":"connected","conn_id":...} on open, then takes JSON text messages:

const ws = new WebSocket("wss://my-app.substrio.com/v1/realtime", [], {
  headers: { Authorization: `Bearer ${process.env.SUBSTRIO_KEY}` },
});

ws.onmessage = (event) => console.log(JSON.parse(event.data));

ws.onopen = () => {
  ws.send(JSON.stringify({ type: "subscribe", collection: "orders", field: "status", value: "pending" }));
};

A field subscription (type: "subscribe") takes collection, field and value: an exact-match filter, not a range. It is answered with {"type":"subscribed","sub_id":...,"collection":...,"field":...,"topic":...}, or {"type":"error","code":...,"error":...} when the caller cannot read the collection, or the connection already holds as many subscriptions as one connection may (realtime_subscriptions_limit).

A whole-collection stream (type: "subscribe_collection", {"collection":"orders"}) carries every insert, update and delete of that collection, each with the record's oid (an insert's event carries the document too). It answers {"type":"subscribed_collection","collection":...,"topic":...}.

type: "subscribe_batch" takes a subscriptions array of field entries and answers one result per entry, in order, each its own topic or error, with count of how many were taken. type: "unsubscribe" (with topic) and type: "unsubscribe_collection" (with collection) drop a subscription; type: "ping" answers {"type":"pong"}.

Resuming a collection stream

subscribe_collection takes an optional resumeAfter (a _seq an earlier subscribed_collection or change event sent). With it, every change since that position is replayed before the stream goes live; without it, the stream starts from now. A resumeAfter the app's history no longer reaches back to (never kept, or pruned since) answers {"type":"error","collection":...,"code":"HISTORY_NOT_KEPT",...} instead of replaying nothing or part of it.

Limits

Setting Meaning
realtime_connections_limit this app's open realtime connections; the next upgrade past it is refused 429
realtime_subscriptions_limit subscriptions one connection may hold; the next subscribe past it answers a LIMIT or TENANT_LIMIT error

Stats

curl -s $SUBSTRIO_URL/v1/realtime/stats -H "Authorization: Bearer $SUBSTRIO_KEY"
{"connections": {"total": 4021, "active": 37},
 "subscriptions": {"total": 9102, "active": 112},
 "notifications": {"total": 583012},
 "dropped": {"slow_client": 3},
 "history": {"entry_builds": 44210}}

dropped.slow_client counts a connection closed for falling behind its own backlog; everything else is a running total since the server last started.