Most state in the Browser SDK — devices, participants, capabilities, call status — is exposed as RxJS observables. This page covers the subset of RxJS used by the SDK. For everything else, see the RxJS docs.
An observable is a stream of values over time. It does nothing until .subscribe() is called; .subscribe() returns a subscription, and .unsubscribe() ends it. Subscriptions left open are the main source of memory leaks.
SDK observables behave like BehaviorSubjects: subscribing emits the current value synchronously, then every subsequent change.
Transform a stream with .pipe() and operators (filter, map, take, combineLatest, switchMap, debounceTime, etc.).
$ suffixA property ending in $ is the observable. The same name without $ is the current snapshot.
Snapshots are not always populated. For state the SDK already holds in memory (call.status, call.participants, device lists), the snapshot is the current value and reading it is fine. For lazily-loaded collections — directory.addresses, address.textMessages, address.history — the snapshot starts empty until something subscribes to the corresponding $ observable (and, for paginated collections, until loadMore() is called). Reading the snapshot synchronously right after connecting will give you []. Subscribe to the $ form, then call loadMore() to trigger the first page.
The first emission fires synchronously with the current device list; subsequent emissions fire on device changes.
Wait for a value, then proceed once. take(1) ends the subscription after the first match.
React on every match.
Combine the latest of multiple streams.
Skip the initial value when only changes matter.
Throttle high-frequency streams.
Two patterns:
takeUntil scales better with many subscriptions; an array is fine for a few.
BehaviorSubject)