Local Participant
Last updated Oct 19, 2026 Manage local user media devices, control audio, video, and screenshare, and handle events in RealtimeKit meetings.
Prerequisites
Initialize the SDK and understand the meeting object structure. Refer to Initialize SDK and Meeting Object Explained.
Introduction
The local user is accessible via meeting.self and contains all information and methods related to the current participant. This includes media controls, device management, participant metadata, and state information.
Properties
WebMobile
ReactWeb ComponentsAngular
Metadata Properties
Access participant identifiers and display information:
// Participant identifiers
meeting.self.id; // Peer ID (unique per session)
meeting.self.userId; // User ID (persistent across sessions)
meeting.self.customParticipantId; // Custom identifier set by developer
meeting.self.name; // Display name
meeting.self.picture; // Display picture URL
import { useRealtimeKitSelector } from "@cloudflare/realtimekit-react";
// Participant identifiers
const id = useRealtimeKitSelector((m) => m.self.id);
const userId = useRealtimeKitSelector((m) => m.self.userId);
const customParticipantId = useRealtimeKitSelector(
(m) => m.self.customParticipantId,
);
const name = useRealtimeKitSelector((m) => m.self.name);
const picture = useRealtimeKitSelector((m) => m.self.picture);
// Participant identifiers
meeting.localUser.id // Peer ID (unique per session)
meeting.localUser.userId // User ID (persistent across sessions)
meeting.localUser.customParticipantId // Custom identifier set by developer
meeting.localUser.name // Display name
meeting.localUser.picture // Display picture URL
// Participant identifiers
meeting.localUser.id // Peer ID (unique per session)
meeting.localUser.userId // User ID (persistent across sessions)
meeting.localUser.customParticipantId // Custom identifier set by developer
meeting.localUser.name // Display name
meeting.localUser.picture // Display picture URL
import { useRealtimeKitSelector } from "@cloudflare/realtimekit-react-native";
// Participant identifiers
const id = useRealtimeKitSelector((m) => m.self.id);
const userId = useRealtimeKitSelector((m) => m.self.userId);
const customParticipantId = useRealtimeKitSelector(
(m) => m.self.customParticipantId,
);
const name = useRealtimeKitSelector((m) => m.self.name);
const picture = useRealtimeKitSelector((m) => m.self.picture);
Media Properties
Access the local user's media tracks and states:
// Media state flags
meeting.self.audioEnabled; // Boolean: Is audio enabled?
meeting.self.videoEnabled; // Boolean: Is video enabled?
meeting.self.screenShareEnabled; // Boolean: Is screen share active?
// Media tracks (MediaStreamTrack objects)
meeting.self.audioTrack; // Audio MediaStreamTrack (available when audioEnabled is true)
meeting.self.videoTrack; // Video MediaStreamTrack (available when videoEnabled is true)
meeting.self.screenShareTracks; // Object: { video: MediaStreamTrack, audio?: MediaStreamTrack }
// Permissions granted by user
meeting.self.mediaPermissions; // Current audio/video permissions
// Media state flags
const audioEnabled = useRealtimeKitSelector((m) => m.self.audioEnabled);
const videoEnabled = useRealtimeKitSelector((m) => m.self.videoEnabled);
const screenShareEnabled = useRealtimeKitSelector(
(m) => m.self.screenShareEnabled,
);
// Media tracks (MediaStreamTrack objects)
const audioTrack = useRealtimeKitSelector((m) => m.self.audioTrack);
const videoTrack = useRealtimeKitSelector((m) => m.self.videoTrack);
const screenShareTracks = useRealtimeKitSelector(
(m) => m.self.screenShareTracks,
);
// Permissions granted by user
const mediaPermissions = useRealtimeKitSelector((m) => m.self.mediaPermissions);
// Media state flags
meeting.localUser.audioEnabled // Boolean: Is audio enabled?
meeting.localUser.videoEnabled // Boolean: Is video enabled?
meeting.localUser.screenShareEnabled // Boolean: Is screen share active?
// Permissions granted by user
meeting.localUser.isCameraPermissionGranted // Camera permission status
meeting.localUser.isMicrophonePermissionGranted // Microphone permission status
// Media state flags
meeting.localUser.audioEnabled // Boolean: Is audio enabled?
meeting.localUser.videoEnabled // Boolean: Is video enabled?
meeting.localUser.screenShareEnabled // Boolean: Is screen share active?
// Permissions granted by user
meeting.localUser.isCameraPermissionGranted // Camera permission status
meeting.localUser.isMicrophonePermissionGranted // Microphone permission status
// Media state flags
const audioEnabled = useRealtimeKitSelector((m) => m.self.audioEnabled);
const videoEnabled = useRealtimeKitSelector((m) => m.self.videoEnabled);
const screenShareEnabled = useRealtimeKitSelector(
(m) => m.self.screenShareEnabled,
);
// Media tracks (MediaStreamTrack objects)
const audioTrack = useRealtimeKitSelector((m) => m.self.audioTrack);
const videoTrack = useRealtimeKitSelector((m) => m.self.videoTrack);
const screenShareTracks = useRealtimeKitSelector(
(m) => m.self.screenShareTracks,
);
// Permissions granted by user
const mediaPermissions = useRealtimeKitSelector((m) => m.self.mediaPermissions);
State Properties
Access room state and participant status:
// Room state
meeting.self.roomJoined; // Boolean: Has joined the meeting?
meeting.self.roomState; // Current room state (see possible values below)
meeting.self.isPinned; // Boolean: Is the local user pinned?
// Permissions and config
meeting.self.permissions; // Capabilities defined by preset
meeting.self.config; // Configuration for meeting appearance
Room state values:
'init'- Initialized but not joined'joined'- Successfully joined the meeting'waitlisted'- Waiting in the waiting room'rejected'- Entry rejected'kicked'- Removed from meeting'left'- Left the meeting'ended'- Meeting has ended'disconnected'- Disconnected from meeting
// Room state
const roomJoined = useRealtimeKitSelector((m) => m.self.roomJoined);
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
const isPinned = useRealtimeKitSelector((m) => m.self.isPinned);
// Permissions and config
const permissions = useRealtimeKitSelector((m) => m.self.permissions);
const config = useRealtimeKitSelector((m) => m.self.config);
Example: Conditional rendering based on room state
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
return (
<>
{roomState === "disconnected" && <div>You are disconnected</div>}
{roomState === "waitlisted" && <div>Waiting for host to admit you</div>}
{roomState === "joined" && <div>You are in the meeting</div>}
</>
);
Room state values:
'init'- Initialized but not joined'joined'- Successfully joined the meeting'waitlisted'- Waiting in the waiting room'rejected'- Entry rejected'kicked'- Removed from meeting'left'- Left the meeting'ended'- Meeting has ended'disconnected'- Disconnected from meeting
// Room state
meeting.localUser.roomJoined // Boolean: Has joined the meeting?
meeting.localUser.waitListStatus // Waitlist status (None, Waiting, Accepted, Rejected)
meeting.localUser.isPinned // Boolean: Is the local user pinned?
// Permissions and config
meeting.localUser.permissions // Capabilities defined by preset
meeting.localUser.presetName // Name of preset for local user
meeting.localUser.presetInfo // Typed object representing preset information
// Room state
meeting.localUser.roomJoined // Boolean: Has joined the meeting?
meeting.localUser.waitListStatus // Waitlist status (None, Waiting, Accepted, Rejected)
meeting.localUser.isPinned // Boolean: Is the local user pinned?
// Permissions and config
meeting.localUser.permissions // Capabilities defined by preset
meeting.localUser.presetName // Name of preset for local user
meeting.localUser.presetInfo // Typed object representing preset information
// Room state
const roomJoined = useRealtimeKitSelector((m) => m.self.roomJoined);
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
const isPinned = useRealtimeKitSelector((m) => m.self.isPinned);
// Permissions and config
const permissions = useRealtimeKitSelector((m) => m.self.permissions);
const config = useRealtimeKitSelector((m) => m.self.config);
Example: Conditional rendering based on room state
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
return (
<>
{roomState === "disconnected" && <Text>You are disconnected</Text>}
{roomState === "waitlisted" && <Text>Waiting for host to admit you</Text>}
{roomState === "joined" && <Text>You are in the meeting</Text>}
</>
);
Room state values:
'init'- Initialized but not joined'joined'- Successfully joined the meeting'waitlisted'- Waiting in the waiting room'rejected'- Entry rejected'kicked'- Removed from meeting'left'- Left the meeting'ended'- Meeting has ended'disconnected'- Disconnected from meeting
Media Controls
Audio control
Mute and unmute the microphone:
// Enable audio (unmute)
await meeting.self.enableAudio();
// Disable audio (mute)
await meeting.self.disableAudio();
// Check current status
const isAudioEnabled = meeting.self.audioEnabled;
import { useRealtimeKitClient } from "@cloudflare/realtimekit-react";
function AudioControls() {
const [meeting] = useRealtimeKitClient();
const audioEnabled = useRealtimeKitSelector((m) => m.self.audioEnabled);
const toggleAudio = async () => {
if (audioEnabled) {
await meeting.self.disableAudio();
} else {
await meeting.self.enableAudio();
}
};
return (
<button onClick={toggleAudio}>{audioEnabled ? "Mute" : "Unmute"}</button>
);
}
// Enable audio (unmute)
meeting.localUser.enableAudio { error: AudioError? -> }
// Disable audio (mute)
meeting.localUser.disableAudio { error: AudioError? -> }
// Check current status
val isAudioEnabled = meeting.localUser.audioEnabled
// Enable audio (unmute)
meeting.localUser.enableAudio { err in }
// Disable audio (mute)
meeting.localUser.disableAudio { err in }
// Check current status
let isAudioEnabled = meeting.localUser.audioEnabled
import {
useRealtimeKitClient,
useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react-native";
import { TouchableHighlight, Text } from "react-native";
function AudioControls() {
const [meeting] = useRealtimeKitClient();
const audioEnabled = useRealtimeKitSelector((m) => m.self.audioEnabled);
const toggleAudio = async () => {
if (audioEnabled) {
await meeting.self.disableAudio();
} else {
await meeting.self.enableAudio();
}
};
return (
<TouchableHighlight onPress={toggleAudio}>
<Text>{audioEnabled ? "Mute" : "Unmute"}</Text>
</TouchableHighlight>
);
}
Video control
Enable and disable the camera:
// Enable video
await meeting.self.enableVideo();
// Disable video
await meeting.self.disableVideo();
// Check current status
const isVideoEnabled = meeting.self.videoEnabled;
function VideoControls() {
const [meeting] = useRealtimeKitClient();
const videoEnabled = useRealtimeKitSelector((m) => m.self.videoEnabled);
const toggleVideo = async () => {
if (videoEnabled) {
await meeting.self.disableVideo();
} else {
await meeting.self.enableVideo();
}
};
return (
<button onClick={toggleVideo}>
{videoEnabled ? "Stop Video" : "Start Video"}
</button>
);
}
// Enable video
meeting.localUser.enableVideo { error: VideoError? -> }
// Disable video
meeting.localUser.disableVideo { error: VideoError? -> }
// Check current status
val isVideoEnabled = meeting.localUser.videoEnabled
// Enable video
meeting.localUser.enableVideo { err in }
// Disable video
meeting.localUser.disableVideo { err in }
// Check current status
let isVideoEnabled = meeting.localUser.videoEnabled
function VideoControls() {
const [meeting] = useRealtimeKitClient();
const videoEnabled = useRealtimeKitSelector((m) => m.self.videoEnabled);
const toggleVideo = async () => {
if (videoEnabled) {
await meeting.self.disableVideo();
} else {
await meeting.self.enableVideo();
}
};
return (
<TouchableHighlight onPress={toggleVideo}>
<Text>{videoEnabled ? "Stop Video" : "Start Video"}</Text>
</TouchableHighlight>
);
}
Screen share control
Start and stop screen sharing:
// Enable screen share
await meeting.self.enableScreenShare();
// Disable screen share
await meeting.self.disableScreenShare();
// Check current status
const isScreenShareEnabled = meeting.self.screenShareEnabled;
function ScreenShareControls() {
const [meeting] = useRealtimeKitClient();
const screenShareEnabled = useRealtimeKitSelector(
(m) => m.self.screenShareEnabled,
);
const toggleScreenShare = async () => {
if (screenShareEnabled) {
await meeting.self.disableScreenShare();
} else {
await meeting.self.enableScreenShare();
}
};
return (
<button onClick={toggleScreenShare}>
{screenShareEnabled ? "Stop Sharing" : "Share Screen"}
</button>
);
}
// Enable screen share
meeting.localUser.enableScreenShare()
// Disable screen share
meeting.localUser.disableScreenShare()
// Check current status
val isScreenShareEnabled = meeting.localUser.screenShareEnabled
Android API 14 and above
Declare the following permission in your app's AndroidManifest.xml to use screenshare on Android devices running Android API 14 and above:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
Adding this permission requires extra steps on Google Play Console. Refer to Google's documentation ↗︎ for more information.
// Enable screen share
let err: ScreenShareError? = meeting.localUser.enableScreenShare()
// Disable screen share
meeting.localUser.disableScreenShare()
Refer to iOS screen sharing for platform-specific configuration.
function ScreenShareControls() {
const [meeting] = useRealtimeKitClient();
const screenShareEnabled = useRealtimeKitSelector(
(m) => m.self.screenShareEnabled,
);
const toggleScreenShare = async () => {
if (screenShareEnabled) {
await meeting.self.disableScreenShare();
} else {
await meeting.self.enableScreenShare();
}
};
return (
<TouchableHighlight onPress={toggleScreenShare}>
<Text>{screenShareEnabled ? "Stop Sharing" : "Share Screen"}</Text>
</TouchableHighlight>
);
}
Change display name
Update the display name before joining the meeting:
await meeting.self.setName("New Name");
Note
Name changes only reflect across all participants if done before joining the meeting.
await meeting.self.setName("New Name");
Note
Name changes only reflect across all participants if done before joining the meeting.
meeting.localUser.setDisplayName("New Name")
Note
Name changes only reflect across all participants if done before joining the meeting.
meeting.localUser.setDisplayName(name: "New Name")
Note
Name changes only reflect across all participants if done before joining the meeting.
await meeting.self.setName("New Name");
Note
Name changes only reflect across all participants if done before joining the meeting.
Manage media devices
Get available devices
// Get all media devices
const devices = await meeting.self.getAllDevices();
// Get all audio input devices (microphones)
const audioDevices = await meeting.self.getAudioDevices();
// Get all video input devices (cameras)
const videoDevices = await meeting.self.getVideoDevices();
// Get all audio output devices (speakers)
const speakerDevices = await meeting.self.getSpeakerDevices();
// Get device by ID
const device = await meeting.self.getDeviceById("device-id", "audio");
// Get current devices being used
const currentDevices = meeting.self.getCurrentDevices();
// Returns: { audio: MediaDeviceInfo, video: MediaDeviceInfo, speaker: MediaDeviceInfo }
```jsx import { useRealtimeKitClient } from "@cloudflare/realtimekit-react"; import { useState, useEffect } from "react";
function DeviceSelector() { const [meeting] = useRealtimeKitClient(); const [audioDevices, setAudioDevices] = useState([]); const [videoDevices, setVideoDevices] = useState([]);
useEffect(() => { if (!meeting) return;
