Events
This page provides an overview of the events emitted by meeting.participants and related participant maps, which you can use to keep your UI in sync with changes such as participants joining or leaving, pinning updates, active speaker changes, and grid view mode or page changes.
These events allow you to monitor changes to the grid.
Triggered when the view mode changes between ACTIVE_GRID and PAGINATED.
meeting.participants.on( "viewModeChanged", ({ viewMode, currentPage, pageCount }) => { console.log("view mode changed", viewMode); },);Triggered when the view mode changes between ACTIVE_GRID and PAGINATED.
const viewMode = useRealtimeKitSelector((m) => m.participants.viewMode);Or use event listener:
meeting.participants.on( "viewModeChanged", ({ viewMode, currentPage, pageCount }) => { console.log("view mode changed", viewMode); },);This event is not available on this platform.
Triggered when the view mode changes between ACTIVE_GRID and PAGINATED.
const viewMode = useRealtimeKitSelector((m) => m.participants.viewMode);Or use event listener:
meeting.participants.on( "viewModeChanged", ({ viewMode, currentPage, pageCount }) => { console.log("view mode changed", viewMode); },);Triggered when the page changes in paginated mode.
meeting.participants.on( "pageChanged", ({ viewMode, currentPage, pageCount }) => { console.log("page changed", currentPage); },);Triggered when the page changes in paginated mode.
const currentPage = useRealtimeKitSelector((m) => m.participants.currentPage);const pageCount = useRealtimeKitSelector((m) => m.participants.pageCount);This event is not available on this platform.
Triggered when the page changes in paginated mode.
const currentPage = useRealtimeKitSelector((m) => m.participants.currentPage);const pageCount = useRealtimeKitSelector((m) => m.participants.pageCount);Triggered when a participant starts speaking.
meeting.participants.on("activeSpeaker", (participant) => { console.log(`${participant.id} is currently speaking`);});const activeSpeaker = useRealtimeKitSelector( (m) => m.participants.lastActiveSpeaker,);Or use event listener:
meeting.participants.on("activeSpeaker", (participant) => { console.log(`${participant.id} is currently speaking`);});meeting.addParticipantsEventListener(object : RtkParticipantsEventListener { override fun onActiveSpeakerChanged(participant: RtkRemoteParticipant?) { participant?.let { println("${it.id} is currently speaking") } }})extension MeetingViewModel: RtkParticipantsEventListener { func onActiveSpeakerChanged(participant: RtkRemoteParticipant?) { if let participant = participant { print("\(participant.id) is currently speaking") } }}
meeting.addParticipantsEventListener(self)class ParticipantsNotifier extends RtkParticipantsEventListener { @override void onActiveSpeakerChanged(RtkRemoteParticipant? participant) { if (participant != null) { print('${participant.id} is currently speaking'); } }}
meeting.addParticipantsEventListener(ParticipantsNotifier());const activeSpeaker = useRealtimeKitSelector( (m) => m.participants.lastActiveSpeaker,);Or use event listener:
meeting.participants.on("activeSpeaker", (participant) => { console.log(`${participant.id} is currently speaking`);});These events allow you to monitor changes to remote participant maps. Use them to get notified when a participant joins or leaves the meeting, is pinned, or moves out of the grid.
Triggered when any participant joins the meeting.
meeting.participants.joined.on("participantJoined", (participant) => { console.log(`A participant with id "${participant.id}" has joined`);});const joinedParticipants = useRealtimeKitSelector((m) => m.participants.joined);Or use event listener:
meeting.participants.joined.on("participantJoined", (participant) => { console.log(`A participant with id "${participant.id}" has joined`);});meeting.addParticipantsEventListener(object : RtkParticipantsEventListener { override fun onParticipantJoin(participant: RtkRemoteParticipant) { println("A participant with id ${participant.id} has joined") }})extension MeetingViewModel: RtkParticipantsEventListener { func onParticipantJoin(participant: RtkRemoteParticipant) { print("A participant with id \(participant.id) has joined") }}
meeting.addParticipantsEventListener(self)class ParticipantsNotifier extends RtkParticipantsEventListener { @override void onParticipantJoin(RtkRemoteParticipant participant) { print('A participant with id ${participant.id} has joined'); }}
meeting.addParticipantsEventListener(ParticipantsNotifier());const joinedParticipants = useRealtimeKitSelector((m) => m.participants.joined);Or use event listener:
meeting.participants.joined.on("participantJoined", (participant) => { console.log(`A participant with id "${participant.id}" has joined`);});Triggered when any participant leaves the meeting.
meeting.participants.joined.on("participantLeft", (participant) => { console.log(`A participant with id "${participant.id}" has left the meeting`);});const joinedParticipants = useRealtimeKitSelector((m) => m.participants.joined);Or use event listener:
meeting.participants.joined.on("participantLeft", (participant) => { console.log(`A participant with id "${participant.id}" has left the meeting`);});meeting.addParticipantsEventListener(object : RtkParticipantsEventListener { override fun onParticipantLeave(participant: RtkRemoteParticipant) { println("A participant with id ${participant.id} has left the meeting") }})extension MeetingViewModel: RtkParticipantsEventListener { func onParticipantLeave(participant: RtkRemoteParticipant) { print("A participant with id \(participant.id) has left the meeting") }}
meeting.addParticipantsEventListener(self)class ParticipantsNotifier extends RtkParticipantsEventListener { @override void onParticipantLeave(RtkRemoteParticipant participant) { print('A participant with id ${participant.id} has left the meeting'); }}
meeting.addParticipantsEventListener(ParticipantsNotifier());const joinedParticipants = useRealtimeKitSelector((m) => m.participants.joined);Or use event listener:
meeting.participants.joined.on("participantLeft", (participant) => { console.log(`A participant with id "${participant.id}" has left the meeting`);});Each participant map emits participantJoined and participantLeft events:
// Listen for when a participant gets pinnedmeeting.participants.pinned.on("participantJoined", (participant) => { console.log(`Participant ${participant.name} got pinned`);});
// Listen for when a participant gets unpinnedmeeting.participants.pinned.on("participantLeft", (participant) => { console.log(`Participant ${participant.name} got unpinned`);});meeting.addParticipantsEventListener(object : RtkParticipantsEventListener { override fun onActiveParticipantsChanged(active: List<RtkRemoteParticipant>) { // Called when active participants change }})extension MeetingViewModel: RtkParticipantsEventListener { func onActiveParticipantsChanged(active: [RtkRemoteParticipant]) { // Called when active participants change }}
meeting.addParticipantsEventListener(self)class ParticipantsNotifier extends RtkParticipantsEventListener { @override void onActiveParticipantsChanged(List<RtkRemoteParticipant> active) { // Called when active participants change }}
meeting.addParticipantsEventListener(ParticipantsNotifier());Triggered when a participant is pinned.
meeting.participants.joined.on("pinned", (participant) => { console.log(`Participant with id "${participant.id}" was pinned`);});const pinnedParticipants = useRealtimeKitSelector((m) => m.participants.pinned);Or use event listener:
meeting.participants.joined.on("pinned", (participant) => { console.log(`Participant with id "${participant.id}" was pinned`);});meeting.addParticipantsEventListener(object : RtkParticipantsEventListener { override fun onParticipantPinned(participant: RtkRemoteParticipant) { println("Participant with id ${participant.id} was pinned") }})extension MeetingViewModel: RtkParticipantsEventListener { func onParticipantPinned(participant: RtkRemoteParticipant) { print("Participant with id \(participant.id) was pinned") }}
meeting.addParticipantsEventListener(self)class ParticipantsNotifier extends RtkParticipantsEventListener { @override void onParticipantPinned(RtkRemoteParticipant participant) { print('Participant with id ${participant.id} was pinned'); }}
meeting.addParticipantsEventListener(ParticipantsNotifier());const pinnedParticipants = useRealtimeKitSelector((m) => m.participants.pinned);Or use event listener:
meeting.participants.joined.on("pinned", (participant) => { console.log(`Participant with id "${participant.id}" was pinned`);});Triggered when a participant is unpinned.
meeting.participants.joined.on("unpinned", (participant) => { console.log(`Participant with id "${participant.id}" was unpinned`);});const pinnedParticipants = useRealtimeKitSelector((m) => m.participants.pinned);Or use event listener:
meeting.participants.joined.on("unpinned", (participant) => { console.log(`Participant with id "${participant.id}" was unpinned`);});meeting.addParticipantsEventListener(object : RtkParticipantsEventListener { override fun onParticipantUnpinned(participant: RtkRemoteParticipant) { println("Participant with id ${participant.id} was unpinned") }})extension MeetingViewModel: RtkParticipantsEventListener { func onParticipantUnpinned(participant: RtkRemoteParticipant) { print("Participant with id \(participant.id) was unpinned") }}
meeting.addParticipantsEventListener(self)class ParticipantsNotifier extends RtkParticipantsEventListener { @override void onParticipantUnpinned(RtkRemoteParticipant participant) { print('Participant with id ${participant.id} was unpinned'); }}
meeting.addParticipantsEventListener(ParticipantsNotifier());const pinnedParticipants = useRealtimeKitSelector((m) => m.participants.pinned);Or use event listener:
meeting.participants.joined.on("unpinned", (participant) => { console.log(`Participant with id "${participant.id}" was unpinned`);});You can monitor changes to a specific participant using the following events.
Triggered when any participant starts or stops video.
meeting.participants.joined.on("videoUpdate", (participant) => { console.log( `A participant with id "${participant.id}" updated their video track`, );
if (participant.videoEnabled) { // Use participant.videoTrack } else { // Handle stop video }});// Check for one participantconst videoEnabled = useRealtimeKitSelector( (m) => m.participants.joined.get(participantId)?.videoEnabled,);
// All video enabled participantsconst videoEnabledParticipants = useRealtimeKitSelector((m) => m.participants.joined.toArray().filter((p) => p.videoEnabled),);meeting.addParticipantEventListener(object : RtkParticipantEventListener { override fun onVideoUpdate(participant: RtkRemoteParticipant, isEnabled: Boolean) { println("Participant ${participant.id} video is now ${if (isEnabled) "enabled" else "disabled"}") }})extension MeetingViewModel: RtkParticipantEventListener { func onVideoUpdate(participant: RtkRemoteParticipant, isEnabled: Bool) { print("Participant \(participant.id) video is now \(isEnabled ? "enabled" : "disabled")") }}
meeting.addParticipantEventListener(self)class ParticipantUpdateHandler extends RtkParticipantUpdateListener { @override void onVideoUpdate(RtkRemoteParticipant participant, bool isEnabled) { print('Participant ${participant.id} video is now ${isEnabled ? "enabled" : "disabled"}'); }}
participant.addParticipantUpdateListener(ParticipantUpdateHandler());// Check for one participantconst videoEnabled = useRealtimeKitSelector( (m) => m.participants.joined.get(participantId)?.videoEnabled,);
// All video enabled participantsconst videoEnabledParticipants = useRealtimeKitSelector((m) => m.participants.joined.toArray().filter((p) => p.videoEnabled),);Triggered when any participant starts or stops audio.
meeting.participants.joined.on("audioUpdate", (participant) => { console.log( `A participant with id "${participant.id}" updated their audio track`, );
if (participant.audioEnabled) { // Use participant.audioTrack } else { // Handle stop audio }});// Check for one participantconst audioEnabled = useRealtimeKitSelector( (m) => m.participants.joined.get(participantId)?.audioEnabled,);
// All audio enabled participantsconst audioEnabledParticipants = useRealtimeKitSelector((m) => m.participants.joined.toArray().filter((p) => p.audioEnabled),);meeting.addParticipantEventListener(object : RtkParticipantEventListener { override fun onAudioUpdate(participant: RtkRemoteParticipant, isEnabled: Boolean) { println("Participant ${participant.id} audio is now ${if (isEnabled) "enabled" else "disabled"}") }})extension MeetingViewModel: RtkParticipantEventListener { func onAudioUpdate(participant: RtkRemoteParticipant, isEnabled: Bool) { print("Participant \(participant.id) audio is now \(isEnabled ? "enabled" : "disabled")") }}
meeting.addParticipantEventListener(self)class ParticipantUpdateHandler extends RtkParticipantUpdateListener { @override void onAudioUpdate(RtkRemoteParticipant participant, bool isEnabled) { print('Participant ${participant.id} audio is now ${isEnabled ? "enabled" : "disabled"}'); }}
participant.addParticipantUpdateListener(ParticipantUpdateHandler());// Check for one participantconst audioEnabled = useRealtimeKitSelector( (m) => m.participants.joined.get(participantId)?.audioEnabled,);
// All audio enabled participantsconst audioEnabledParticipants = useRealtimeKitSelector((m) => m.participants.joined.toArray().filter((p) => p.audioEnabled),);Triggered when any participant starts or stops screen share.
meeting.participants.joined.on("screenShareUpdate", (participant) => { console.log( `A participant with id "${participant.id}" updated their screen share`, );
if (participant.screenShareEnabled) { // Use participant.screenShareTracks } else { // Handle stop screen share }});// Check for one participantconst screensharingParticipant = useRealtimeKitSelector((m) => m.participants.joined.toArray().find((p) => p.screenShareEnabled),);
// All screen sharing participantsconst screenSharingParticipants = useRealtimeKitSelector((m) => m.participants.joined.toArray().filter((p) => p.screenShareEnabled),);meeting.addParticipantEventListener(object : RtkParticipantEventListener { override fun onScreenShareUpdate(participant: RtkRemoteParticipant, isEnabled: Boolean) { println("Participant ${participant.id} screen share is now ${if (isEnabled) "enabled" else "disabled"}") }})extension MeetingViewModel: RtkParticipantEventListener { func onScreenShareUpdate(participant: RtkRemoteParticipant, isEnabled: Bool) { print("Participant \(participant.id) screen share is now \(isEnabled ? "enabled" : "disabled")") }}
meeting.addParticipantEventListener(self)class ParticipantUpdateHandler extends RtkParticipantUpdateListener { @override void onScreenShareUpdate(RtkRemoteParticipant participant, bool isEnabled) { print('Participant ${participant.id} screen share is now ${isEnabled ? "enabled" : "disabled"}'); }}
participant.addParticipantUpdateListener(ParticipantUpdateHandler());// Check for one participantconst screensharingParticipant = useRealtimeKitSelector((m) => m.participants.joined.toArray().find((p) => p.screenShareEnabled),);
// All screen sharing participantsconst screenSharingParticipants = useRealtimeKitSelector((m) => m.participants.joined.toArray().filter((p) => p.screenShareEnabled),);Monitor participant network quality using the mediaScoreUpdate event.
meeting.participants.joined.on( "mediaScoreUpdate", ({ participantId, kind, isScreenshare, score, scoreStats }) => { if (kind === "video") { console.log( `Participant ${participantId}'s ${isScreenshare ? "screenshare" : "video"} quality score is`, score, ); }
if (kind === "audio") { console.log( `Participant ${participantId}'s audio quality score is`, score, ); }
if (score < 5) { console.log(`Participant ${participantId}'s media quality is poor`); } },);Monitor participant network quality using the mediaScoreUpdate event.
import { useEffect } from "react";
// Use event listener for media score updatesuseEffect(() => { if (!meeting) return;
const handleMediaScoreUpdate = ({ participantId, kind, isScreenshare, score, scoreStats, }) => { if (kind === "video") { console.log( `Participant ${participantId}'s ${isScreenshare ? "screenshare" : "video"} quality score is`, score, ); }
if (score < 5) { console.log(`Participant ${participantId}'s media quality is poor`); } };
meeting.participants.joined.on("mediaScoreUpdate", handleMediaScoreUpdate);
return () => { meeting.participants.joined.off("mediaScoreUpdate", handleMediaScoreUpdate); };}, [meeting]);This event is not available on this platform.
Monitor participant network quality using the mediaScoreUpdate event.
import { useEffect } from "react";
// Use event listener for media score updatesuseEffect(() => { if (!meeting) return;
const handleMediaScoreUpdate = ({ participantId, kind, isScreenshare, score, scoreStats, }) => { if (kind === "video") { console.log( `Participant ${participantId}'s ${isScreenshare ? "screenshare" : "video"} quality score is`, score, ); }
if (score < 5) { console.log(`Participant ${participantId}'s media quality is poor`); } };
meeting.participants.joined.on("mediaScoreUpdate", handleMediaScoreUpdate);
return () => { meeting.participants.joined.off("mediaScoreUpdate", handleMediaScoreUpdate); };}, [meeting]);Each participant object is an event emitter:
meeting.participants.joined .get(participantId) .on("audioUpdate", ({ audioEnabled, audioTrack }) => { console.log( "The participant with id", participantId, "has toggled their mic to", audioEnabled, ); });Alternatively, listen on the participant map for all participants:
meeting.participants.joined.on( "audioUpdate", (participant, { audioEnabled, audioTrack }) => { console.log( "The participant with id", participant.id, "has toggled their mic to", audioEnabled, ); },);import { useRealtimeKitClient } from "@cloudflare/realtimekit-react";import { useEffect } from "react";
function ParticipantAudioListener({ participantId }) { const [meeting] = useRealtimeKitClient();
useEffect(() => { if (!meeting) return;
const handleAudioUpdate = ({ audioEnabled, audioTrack }) => { console.log( "The participant with id", participantId, "has toggled their mic to", audioEnabled, ); };
const participant = meeting.participants.joined.get(participantId); participant.on("audioUpdate", handleAudioUpdate);
return () => { participant.off("audioUpdate", handleAudioUpdate); }; }, [meeting, participantId]);}Or use the selector for specific properties:
const audioEnabled = useRealtimeKitSelector( (m) => m.participants.joined.get(participantId)?.audioEnabled,);Implement the RtkParticipantEventListener interface to receive participant event updates:
meeting.addParticipantEventListener(object : RtkParticipantEventListener { override fun onVideoUpdate(participant: RtkRemoteParticipant, isEnabled: Boolean) { // Called when participant's video state changes }
override fun onAudioUpdate(participant: RtkRemoteParticipant, isEnabled: Boolean) { // Called when participant's audio state changes }
override fun onScreenShareUpdate(participant: RtkRemoteParticipant, isEnabled: Boolean) { // Called when participant's screen share state changes }})Implement the RtkParticipantEventListener protocol to receive participant event updates:
extension MeetingViewModel: RtkParticipantEventListener { func onVideoUpdate(participant: RtkRemoteParticipant, isEnabled: Bool) { // Called when participant's video state changes }
func onAudioUpdate(participant: RtkRemoteParticipant, isEnabled: Bool) { // Called when participant's audio state changes }
func onScreenShareUpdate(participant: RtkRemoteParticipant, isEnabled: Bool) { // Called when participant's screen share state changes }}
meeting.addParticipantEventListener(self)Implement the RtkParticipantUpdateListener interface and add the listener on a participant:
class ParticipantUpdateHandler extends RtkParticipantUpdateListener { @override void onVideoUpdate(RtkRemoteParticipant participant, bool isEnabled) { print("${participant.name}'s video is now ${isEnabled ? 'on' : 'off'}"); }
@override void onAudioUpdate(RtkRemoteParticipant participant, bool isEnabled) { print("${participant.name}'s audio is now ${isEnabled ? 'on' : 'off'}"); }
@override void onPinned(RtkRemoteParticipant participant) { print("${participant.name} was pinned"); }
@override void onUnpinned(RtkRemoteParticipant participant) { print("${participant.name} was unpinned"); }
@override void onScreenShareUpdate(RtkRemoteParticipant participant, bool isEnabled) { print("${participant.name}'s screen-share is now ${isEnabled ? 'on' : 'off'}"); }
@override void onUpdate(RtkRemoteParticipant participant) { print("${participant.name} was updated"); }}
// Register the listener with a specific participantfinal listener = ParticipantUpdateHandler();participant.addParticipantUpdateListener(listener);
// When done listening, remove the listenerparticipant.removeParticipantUpdateListener(listener);import { useRealtimeKitClient } from "@cloudflare/realtimekit-react-native";import { useEffect } from "react";
function ParticipantAudioListener({ participantId }) { const [meeting] = useRealtimeKitClient();
useEffect(() => { if (!meeting) return;
const handleAudioUpdate = ({ audioEnabled, audioTrack }) => { console.log( "The participant with id", participantId, "has toggled their mic to", audioEnabled, ); };
const participant = meeting.participants.joined.get(participantId); participant.on("audioUpdate", handleAudioUpdate);
return () => { participant.off("audioUpdate", handleAudioUpdate); }; }, [meeting, participantId]);}Or use the selector for specific properties:
const audioEnabled = useRealtimeKitSelector( (m) => m.participants.joined.get(participantId)?.audioEnabled,);Was this helpful?
- Resources
- API
- New to Cloudflare?
- Directory
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2026 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark
-