Events (2)·续

Audio update

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

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

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

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 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

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)
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?

YesNo

On this page

Events (2)·续 - 图1Docs

{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/realtime/realtimekit/humans/core/remote-participants/events/#page","headline":"Events","description":"Events emitted by RealtimeKit participants for join, leave, pin, and grid changes.","url":"https://developers.cloudflare.com/realtime/realtimekit/humans/core/remote-participants/events/","inLanguage":"en","image":"https://developers.cloudflare.com/realtime/realtimekit/humans/core/remote-participants/events/og.png?v=dcd0b2d5addfa5ab","dateModified":"2026-10-19","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}


description: Render RealtimeKit participant video as a floating Picture-in-Picture tile in the browser. title: Picture in Picture image: https://developers.cloudflare.com/realtime/realtimekit/humans/core/remote-participants/pip/og.png?v=d37018f536cfe11e


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/realtime/llms.txt
Use this file to discover all available pages before exploring further.