DailyTrackState interface. Understanding track states is essential for building a reliable call object UI.
DailyTrackState
See theDailyTrackState reference for the full interface definition and field descriptions.
Track States
Thestate field describes the current condition of a track — not a step in a sequential progression:
Why the off sub-fields matter
Track Types
EachDailyParticipant carries a tracks object of type DailyParticipantTracks:
Custom tracks
Custom tracks let you send arbitraryMediaStreamTrack objects alongside the standard camera and mic. Start them with startCustomTrack() and stop them with stopCustomTrack():
DailyParticipantTracks.
Local vs. remote track behavior
How a track’s initial state is reached differs between local and remote:- Local tracks start directly as
playable,off, orblocked— they never pass throughloading. If a local track startsoffand the user enables it withsetLocalVideo(true)orsetLocalAudio(true), it transitions straight toplayable(orblockedif the user denied device permissions). - Remote tracks can start in any state except
playableorinterrupted— most commonlyloading(subscribed but stream not yet established),off(sender muted before you joined),blocked(sender has a device issue), orsendable(sender is ready but you haven’t subscribed). interruptedis never an initial state — it only occurs after a track wasplayableand then transiently stalled, most commonly during network fluctuations or iOS tab backgrounding. It can return toplayableonce the condition resolves.
Track Subscription
By default Daily subscribes to tracks from all participants automatically (subscribeToTracksAutomatically: true). In large calls, subscribing to every track is wasteful. Disable automatic subscription to control this explicitly.
DailyTrackSubscriptionState
DailyTrackSubscriptionOptions
Subscribing per participant
Global subscription toggle
Attaching Tracks to Video Elements
The recommended approach for rendering tracks is to usetrack-started and track-stopped events:
track vs. persistentTrack
The key difference: track is undefined whenever state !== 'playable'. persistentTrack is present whenever a track exists, regardless of playable state.
We recommend using persistentTrack over track when attaching to media elements. It acts as a proactive defense against black frames during call disruptions and helps avoid browser bugs related to auto-playing media tracks.
track only when you need a guarantee that the media is currently flowing.
Track Events
The
type field in DailyEventObjectTrack is one of 'video', 'audio', 'screenVideo', 'screenAudio', or a custom track name string.
Track replacement
track-started and track-stopped fire not only on state transitions but also when the underlying MediaStreamTrack is replaced — for example when a participant switches cameras or a device change causes a new track to be issued. In this case the track state stays playable throughout, but you will receive a track-stopped for the old track immediately followed by a track-started for the new one.
This means you should key your media elements on the track object itself (or its id), not on participant or track type alone: