Snapshot vs events
The SDK gives you two complementary ways to read the world: a synchronous snapshot of the current state, and streaming events as it changes. Use both — they’re cheap and they’re always consistent with each other.
Snapshot — the state right now
Section titled “Snapshot — the state right now”const { sportEvents, stale } = client.snapshot()// sportEvents: ReadonlyMap<SportEventId, SportEvent>// stale: true when the connection is currently downThe snapshot is a live view of the SDK’s internal store. It’s not a copy — it reflects everything received so far, every time you read it.
Use it when:
- You’re rendering a dashboard and need to draw the current state of all events.
- You just started up and want to see what’s already known before subscribing.
- A user navigated to a screen mid-session and you need to populate it.
function renderEventList() { const { sportEvents } = client.snapshot() return [...sportEvents.values()] .filter(ev => ev.sport === 'basketball') .map(ev => `${ev.name} — ${ev.markets.size} markets`)}Lookup by id is O(1) via client.getSportEvent(id) or snapshot().sportEvents.get(id).
Events — what changed since you last looked
Section titled “Events — what changed since you last looked”Subscribe to events to react to changes:
| Event | When |
|---|---|
sportEvent:added | A sport event is observed for the first time (per bookmaker). |
sportEvent:updated | The event’s metadata, market list, or any odds value changed. |
sportEvent:removed | A sport event is no longer reported by its source. |
odds:changed | A specific selection’s quote (or order book) changed. Fires alongside sportEvent:updated. |
client.on('odds:changed', ({ bookmaker, selectionId, quote }) => { console.log(`${bookmaker} ${selectionId} → ${quote.price}`)})See the Events reference for full payload shapes.
How they relate
Section titled “How they relate”sportEvent:updated fires on every change to a sport event, including odds updates — the gateway’s store creates a new immutable instance each time, so consumers tracking by reference need the new one. This means:
- If you only want to know when an event is added or removed, subscribe to
sportEvent:added/sportEvent:removed. - If you want to know when anything about an event changes (so you can re-render it as a whole), subscribe to
sportEvent:updated. - If you want per-selection price updates only, subscribe to
odds:changed— it carries just the newquoteplus its identifiers, so you don’t have to diff the whole event.
You’ll often subscribe to both sportEvent:updated (for re-rendering) and odds:changed (for line-move detection or alerting).
Initial sync
Section titled “Initial sync”When you call connect(), the gateway sends the SDK its current state in one or more frames. The SDK populates the store before resolving connect(). This means:
- Right after
await client.connect(),client.snapshot()is already populated. - The
sportEvent:addedevents that fire during the initial sync also fire — you’ll see one per existing event. If you only want to handle new events, attach the listener afterawait connect()if that fits, or filter using a “ready” flag.
// Pattern: ignore initial-sync eventslet ready = falseclient.on('sportEvent:added', ({ sportEvent }) => { if (!ready) return // skip during initial sync notifyNewMatch(sportEvent)})await client.connect()ready = trueWhat to render
Section titled “What to render”For UI: read the snapshot on first paint, subscribe to sportEvent:updated to invalidate cached views by id. The snapshot is fresh enough to drive any list view, and event-driven updates keep your UI in sync without polling.