# Permissions & Moderation

Control participant permissions and capabilities - for example, in webinars where hosts control who can speak or share their screen.

## Best Practices

- Use `useOwnCapabilities` hook to check permissions before showing UI controls.
- Listen to `call.permission_request` events to handle permission requests from users.
- Use `call.grantPermissions` and `call.revokePermissions` for granular permission control.
- Consider using `call.muteUser` instead 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](/video/docs/react/guides/configuring-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:

```tsx
import { useCallStateHooks } from "@stream-io/video-react-sdk";

const { useOwnCapabilities } = useCallStateHooks();
const ownCapabilities = useOwnCapabilities();
```

## Permissions

### Check permissions

```ts
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:

```tsx
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:

```ts
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:

```ts
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:

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

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

```ts
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):

```ts
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:

```ts
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");
```


---

This page was last updated at 2026-07-10T16:05:24.377Z.

For the most recent version of this documentation, visit [https://getstream.io/video/docs/react/guides/permissions-and-moderation/](https://getstream.io/video/docs/react/guides/permissions-and-moderation/).