Skip to content
Cloudflare Docs

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.

Grid events

These events allow you to monitor changes to the grid.

View mode change

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);
},
);

Page change

Triggered when the page changes in paginated mode.

const currentPage = useRealtimeKitSelector((m) => m.participants.currentPage);
const pageCount = useRealtimeKitSelector((m) => m.participants.pageCount);

Active speaker

Triggered when a participant starts speaking.

const activeSpeaker = useRealtimeKitSelector(
(m) => m.participants.lastActiveSpeaker,
);

Or use event listener:

meeting.participants.on("activeSpeaker", (participant) => {
console.log(`${participant.id} is currently speaking`);
});

Participant map events

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.

Participant joined

Triggered when any participant joins the meeting.

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`);
});

Participant left

Triggered when any participant leaves 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`);
});

Active participants changed

Each participant map emits participantJoined and participantLeft events:

JavaScript
// Listen for when a participant gets pinned
meeting.participants.pinned.on("participantJoined", (participant) => {
console.log(`Participant ${participant.name} got pinned`);
});
// Listen for when a participant gets unpinned
meeting.participants.pinned.on("participantLeft", (participant) => {
console.log(`Participant ${participant.name} got unpinned`);
});

Participant pinned

Triggered when a participant is 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`);
});

Participant unpinned

Triggered when a participant is 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`);
});

Participant events

You can monitor changes to a specific participant using the following events.

Video update

Triggered when any participant starts or stops video.

// Check for one participant
const videoEnabled = useRealtimeKitSelector(
(m) => m.participants.joined.get(participantId)?.videoEnabled,
);
// All video enabled participants
const videoEnabledParticipants = useRealtimeKitSelector((m) =>
m.participants.joined.toArray().filter((p) => p.videoEnabled),
);

Audio update

Triggered when any participant starts or stops audio.

// Check for one participant
const audioEnabled = useRealtimeKitSelector(
(m) => m.participants.joined.get(participantId)?.audioEnabled,
);
// All audio enabled participants
const audioEnabledParticipants = useRealtimeKitSelector((m) =>
m.participants.joined.toArray().filter((p) => p.audioEnabled),
);

Screen share update

Triggered when any participant starts or stops screen share.

// Check for one participant
const screensharingParticipant = useRealtimeKitSelector((m) =>
m.participants.joined.toArray().find((p) => p.screenShareEnabled),
);
// All screen sharing participants
const screenSharingParticipants = useRealtimeKitSelector((m) =>
m.participants.joined.toArray().filter((p) => p.screenShareEnabled),
);

Network quality score

Monitor participant network quality using the mediaScoreUpdate event.

import { useEffect } from "react";
// Use event listener for media score updates
useEffect(() => {
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]);

Listen to participant events

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,
);