import { useCallStateHooks } from "@stream-io/video-react-sdk";
const { useOwnCapabilities } = useCallStateHooks();
const ownCapabilities = useOwnCapabilities();Permissions & Moderation
Control participant permissions and capabilities - for example, in webinars where hosts control who can speak or share their screen.
Best Practices
- Use
useOwnCapabilitieshook to check permissions before showing UI controls. - Listen to
call.permission_requestevents to handle permission requests from users. - Use
call.grantPermissionsandcall.revokePermissionsfor granular permission control. - Consider using
call.muteUserinstead of revoking permissions for temporary muting.
Conceptual overview
Roles
Users have global roles and call-level roles. Use predefined roles or create custom ones.
Call types
Call types provide granular control - enable/disable features and configure role behavior per call type.
Capabilities
A user's allowed actions are determined by their roles and call type settings. Access via useOwnCapabilities hook:
Permissions
Check permissions
import { OwnCapability } from "@stream-io/video-react-sdk";
const call = client.call(type, id);
const canSendAudio = call.permissionsContext.hasPermission(
OwnCapability.SEND_AUDIO,
);Or use the useHasPermissions hook:
import { useCallStateHooks } from "@stream-io/video-react-sdk";
const { useHasPermissions } = useCallStateHooks();
const canSendAudio = useHasPermissions(OwnCapability.SEND_AUDIO);Request permissions
Users can request permissions based on call type settings. For example, in audio rooms, non-hosts must request send-audio permission:
import { OwnCapability } from "@stream-io/video-react-sdk";
const call = client.call(type, id);
if (!call.permissionsContext.canRequest(OwnCapability.SEND_AUDIO)) {
console.log("The host has disabled the ability to request this permission");
return;
}
await call.requestPermissions({
permissions: [OwnCapability.SEND_AUDIO],
});Approving permission requests
Hosts and moderators can approve permission requests. Listen to call.permission_request events:
import {
PermissionRequestEvent,
StreamCallEvent,
} from "@stream-io/video-react-sdk";
const call = client.call(type, id);
call.on("call.permission_request", async (event: StreamCallEvent) => {
const request = event as PermissionRequestEvent;
if (shouldApproveRequest(request)) {
await call.grantPermissions(request.user.id, request.permissions);
}
});Moderation
Grant or revoke permissions for any participant:
import { OwnCapability } from "@stream-io/video-react-sdk";
const call = client.call(type, id);
await call.updateUserPermissions({
user_id: "demo-user",
grant_permission: [OwnCapability.SEND_AUDIO, OwnCapability.SEND_VIDEO],
revoke_permissions: [OwnCapability.SCREENSHARE],
});
// alternate API for granting user permissions:
await call.grantPermissions("demo-user", [
OwnCapability.SEND_AUDIO,
OwnCapability.SEND_VIDEO,
]);
// alternate API for revoking user permissions:
await call.revokePermissions("demo-user", [OwnCapability.SCREENSHARE]);Users receive call.permissions_updated events. When permissions are revoked, the SDK automatically stops publishing affected tracks.
Ending call for everyone
const call = client.call(type, id);
await call.endCall();Emits call.ended to all participants. The SDK stops publishing and leaves automatically. Ended calls cannot be re-joined.
Users
Blocking and Unblocking
const call = client.call(type, id);
await call.blockUser("user-id");
// to unblock
await call.unblockUser("user-id");Kicking
Kicking disconnects the participant but allows them to re-join (softer than blocking):
const call = client.call(type, id);
await call.kickUser({ user_id: "user-id" });
// you can use this shortcut to block the user from re-joining the call:
await call.kickUser({ user_id: "user-id", block: true });Muting
Mute participants to handle unwanted noise. Unlike revoking permissions, users can unmute themselves:
const call = client.call(type, id);
await call.muteUser("demo-user-id", "audio");
await call.muteUser("demo-user-id", "video");
await call.muteUser("demo-user-id", "screenshare");
// or, mute in bulk
await call.muteUser(["demo-user-id", "demo-user-id-2"], "audio");
// or, muting self
await call.muteSelf("audio");
// or, muting others
await call.muteOthers("audio");
// or, mute all, including self.
await call.muteAllUsers("audio");