Realtime — Subscribe
Live tail every insert, update, and delete on a lens. One shared WebSocket, events arrive as they happen, optional in-process filter.
Signature
for await through the iterator. break to stop; the client cleans up
the op. The shared WebSocket stays open for other subscriptions.
Filter — what it matches
- Scalars: strict equality (
===). - Arrays: same length, same elements in the same order.
- Missing fields on the record: treated as
undefined, won't match anything.
Not supported in v1: $gte / $in / $or operators, nested object
equality, predicate functions. If you need richer matching, filter on
the client inside your loop. The server-side filter saves bandwidth
when most events don't match; the client-side filter handles anything
the server can't.
React hook
useSubscribe wraps the iterator, retry loop, and event accumulation:
events: StreamEvent<M>[]— ring-buffered tomaxEvents(default 500).latest— the most recent event (ornullbefore anything arrives).error— set when the iterator throws and retry hasn't kicked in yet.reset()— clear the event list and force a fresh subscribe.
The hook holds the subscription open for the lifetime of the component.
On unmount, it calls the iterator's return() to cleanly close the op.
Combining with a fetched snapshot
A common pattern: load the current list with query, then subscribe for
changes on top of it.
useSubscribe leaves the merge strategy to you — different apps want
different behaviors (insert to top vs. insert to match orderBy,
overwrite vs. animate, etc.).
Limits
- One WebSocket per environment. All
subscribe/observe/stream.query/stream.search/feed.subscribecalls from the same client share it. maxLiveSubscriptionsper lens (fromgrants.stream.maxLiveSubscriptions). Exceed it →4290 rate_limitedclose code.- Org tier cap on concurrent subs across all lenses. Exceed it →
4291 quotaExceeded. - Heartbeats: server pings every 25s. Client SDK auto-responds with
pong. Two missed pongs → server closes with1011.
Error handling
| Close code | Meaning | Fix |
|---|---|---|
4403 | grants.stream.enabled is false, or modes excludes 'live', or access rule denied | Check grants.stream + the caller's identity |
4290 | Per-lens maxLiveSubscriptions hit | Close an old sub or raise the lens's cap |
4291 | Org-wide tier cap hit | Upgrade tier, or close unused subs |
1011 | Server-initiated close (heartbeat timeout, restart) | Retry with backoff |
All of these surface as BeamStreamClosedError in your iterator. The
error's .code field carries the close code so the retry loop can
branch on it.