LiveKit Logo



Guides / Working with Rooms / Event handling

Event handling


Client SDKs use events to communicate with the application changes that are taking place in the room.

There are two kinds of events, room events and participant events. Room events are emitted from the main Room object, reflecting any change in the room. Participant events are emitted from each Participant, when that specific participant has changed.

Room events is generally a superset of participant events. As you can see, some events are fired on both Room and Participant; this is intentional. This duplication is designed to make it easier to componentize your application. For example, if you have a UI component that renders a participant, it should only listen to events scoped to that participant.

Declarative UI

Event handling can be quite complicated in a real-time, multi-user system. Participants could be joining and leaving, each publishing tracks or muting them. To simplify this, LiveKit has built-in support for declarative UI in majority of our SDKs.

With declarative UI, you would specify the how the UI should look given a particular state, without having to worry about the sequence of transformations to apply. Modern frameworks are highly efficient at detecting changes and rendering only what's changed.

We offer a few hooks & components that makes working with React much simpler.

  • useRoom - manages state of the room
  • useParticipant - maps participant events to state
  • VideoRenderer - React component that renders a video track
  • AudioRenderer - React component that plays back audio
const Stage = () => {
const { room, isConnecting, participants, audioTracks } = useRoom({
adaptiveStream: true,
dynacast: true,
return (
// render all subscribed audio tracks together
{ => {
<AudioRenderer track={t} isLocal={false} />
{ => (
<ParticipantView participant={p} />
interface ParticipantViewProps {
participant: Participant
const ParticipantView = ({ participant }: ParticipantViewProps): ReactElement | null => {
// isSpeaking, connectionQuality will update when changed
const { isSpeaking, connectionQuality, isLocal, cameraPublication } = useParticipant(participant)
// user has disabled video
if (cameraPublication?.isMuted ?? true) {
// render placeholder view
return (
// user is not subscribed to track, for if using selective subscriptions
if (!cameraPublication.isSubscribed) {
return null;
return (
<VideoRenderer track={cameraPublication.track} isLocal={isLocal} />


This table captures a consistent set of events that are available across platform SDKs. In addition to what's listed here, there may be platform-specific events on certain platforms.

EventDescriptionRoom EventParticipant Event
ParticipantConnectedA RemoteParticipant joins after the local participant.x
ParticipantDisconnectedA RemoteParticipant leavesx
ReconnectingThe connection to the server has been interrupted and it's attempting to reconnect.x
ReconnectedReconnection has been successfulx
DisconnectedDisconnected from room due to the room closing or unrecoverable failurex
TrackPublishedA new track is published to room after the local participant has joinedxx
TrackUnpublishedA RemoteParticipant has unpublished a trackxx
TrackSubscribedThe LocalParticipant has subscribed to a trackxx
TrackUnsubscribedA previously subscribed track has been unsubscribedxx
TrackMutedA track was muted, fires for both local tracks and remote tracksxx
TrackUnmutedA track was unmuted, fires for both local tracks and remote tracksxx
LocalTrackPublishedA local track was published successfullyxx
LocalTrackUnpublishedA local track was unpublishedxx
ActiveSpeakersChangedCurrent active speakers has changedx
IsSpeakingChangedThe current participant has changed speaking statusx
ConnectionQualityChangedConnection quality was changed for a Participantxx
ParticipantMetadataChangedA participant's metadata was updated via server APIxx
RoomMetadataChangedMetadata associated with the room has changedx
DataReceivedData received from another participant or serverxx
TrackStreamStateChangedIndicates if a subscribed track has been paused due to bandwidthxx
TrackSubscriptionPermissionChangedOne of subscribed tracks have changed track-level permissions for the current participantxx
ParticipantPermissionsChangedWhen the current participant's permissions have changedxx