# Call Moderation

Handle moderation events in video call applications. Stream's moderation system automatically emits events when content violates configured policies. Configure policies via the [Stream Dashboard](https://getstream.io/signin/?product=video) or moderation API.

## Best Practices

- **Display warnings clearly** - Show moderation warnings prominently to users
- **Handle blur gracefully** - Apply blur filters without disrupting call flow
- **Inform about termination** - Explain why a call ended due to violations
- **Log moderation events** - Track violations for review and policy adjustment

Stream API moderation events:

- **call.moderation_warning** - Warning issued to user
- **call.moderation_blur** - Blur effect should be applied to camera
- **call.ended** - Call terminated (with `reason: PolicyViolationModeration` for violations)

## Video Moderation Configuration

The Flutter SDK handles `call.moderation_blur` events through `VideoModerationConfig`, set via `CallPreferences` when creating a call:

| Flag / Callback | Description                                                                                                                    |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `muteAudio`     | Mutes the local user's microphone and prevents re-enabling it for the configured duration.                                     |
| `muteVideo`     | Mutes the local user's camera and prevents re-enabling it for the configured duration.                                         |
| `applyBlur`     | Applies a full-frame native blur on the camera track visible to all participants. Requires the `stream_video_filters` package. |
| `duration`      | How long the moderation action lasts. `null` means it persists until `call.clearModerationBlur()` is called.                   |
| `onWarning`     | Callback invoked when a `call.moderation_warning` event is received.                                                           |
| `onApply`       | Callback invoked when the moderation blur action fires (after built-in actions).                                               |
| `onClear`       | Callback invoked when the moderation blur action is cleared (after built-in clear actions).                                    |

Convenience constructors cover the most common presets:

| Constructor                        | Equivalent to                                                             |
| ---------------------------------- | ------------------------------------------------------------------------- |
| `VideoModerationConfig.disabled()` | Default. No automatic action. The event is still emitted on `callEvents`. |
| `VideoModerationConfig.mute()`     | `muteAudio: true, muteVideo: true`                                        |
| `VideoModerationConfig.blur()`     | `applyBlur: true`                                                         |

### Setting the Configuration

Pass `videoModerationConfig` in `DefaultCallPreferences` when creating a call:

```dart
final call = streamVideo.makeCall(
  callType: StreamCallType.defaultType(),
  id: 'my-call-id',
  preferences: DefaultCallPreferences(
    videoModerationConfig: VideoModerationConfig.mute(
      duration: Duration(seconds: 5),
    ),
  ),
);
```

### Combining Behaviors

Flags are composable. For example, mute audio and video while also running a custom callback:

```dart
final call = streamVideo.makeCall(
  callType: StreamCallType.defaultType(),
  id: 'my-call-id',
  preferences: DefaultCallPreferences(
    videoModerationConfig: VideoModerationConfig(
      muteAudio: true,
      muteVideo: true,
      duration: Duration(seconds: 10),
      onWarning: (message) {
        // Show a warning snackbar
      },
      onApply: () {
        // Show a moderation banner in the UI
      },
      onClear: () {
        // Hide the moderation banner
      },
    ),
  ),
);
```

Or combine mute with native blur:

```dart
VideoModerationConfig(
  muteAudio: true,
  muteVideo: true,
  applyBlur: true,
  duration: Duration(seconds: 10),
)
```

## Moderation Blur

To use `applyBlur: true` (or `VideoModerationConfig.blur()`), you need the `stream_video_filters` package. This applies a full-frame native blur on the outgoing camera track before encoding, so the blur is visible to all participants.

### Behavior

- **With `stream_video_filters` package** - Full-screen blur applied to outgoing video, auto-removed after the configured duration
- **Without the package** - The blur handlers will not be registered and the blur effect will not be applied

### Usage

```dart
final call = streamVideo.makeCall(
  callType: StreamCallType.defaultType(),
  id: 'my-call-id',
  preferences: DefaultCallPreferences(
    videoModerationConfig: VideoModerationConfig.blur(
      duration: Duration(seconds: 5),
    ),
  ),
);
```

## Custom Moderation Handling

For full control over what happens when a moderation blur event is received, pass `onApply` and `onClear` callbacks directly in the config:

```dart
final call = streamVideo.makeCall(
  callType: StreamCallType.defaultType(),
  id: 'my-call-id',
  preferences: DefaultCallPreferences(
    videoModerationConfig: VideoModerationConfig(
      duration: Duration(seconds: 5),
      onWarning: (reason) {
        // Called when a moderation warning is received
      },
      onApply: () {
        // Called when moderation blur fires
      },
      onClear: () {
        // Called when moderation blur is cleared
      },
    ),
  ),
);
```

The callbacks run after any built-in actions, so you can add them alongside `muteAudio`, `muteVideo`, or `applyBlur` for additional side effects.

## Listening to Call Events

All moderation events are also emitted on `call.callEvents`, regardless of the `VideoModerationConfig` setting. For moderation warnings you can use either the `onWarning` callback in the config or listen to `StreamCallModerationWarningEvent` on `callEvents` directly.

### Moderation Warning

Display a notification when the user receives a moderation warning:

```dart
call.callEvents.on<StreamCallModerationWarningEvent>((event) {
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: Text('Moderation Warning'),
      content: Text(event.message),
      actions: [
        TextButton(
          onPressed: () => Navigator.of(context).pop(),
          child: Text('OK'),
        ),
      ],
    ),
  );
});
```

### Moderation Blur

Listen to blur events directly when using `VideoModerationConfig.disabled()` or when you need additional side effects alongside the config:

```dart
call.callEvents.on<StreamCallModerationBlurEvent>((event) {
  // Handle the blur event manually
});
```

## Handling Moderation Policy Violation

Multiple policy violations may terminate the call. The `StreamCallEndedEvent` carries a `reason` field with the value `PolicyViolationModeration` when the call was ended due to moderation:

```dart
call.callEvents.on<StreamCallEndedEvent>((event) {
  if (event.reason == 'PolicyViolationModeration') {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Call Terminated'),
        content: Text(
          'The video call was terminated due to multiple policy violations.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: Text('OK'),
          ),
        ],
      ),
    );
  }
});
```

## Checking Moderation State

You can check whether the local user is currently under moderation via the call state:

```dart
final isModerated = call.state.value.isVideoModerated;
```

To programmatically clear the moderation action (for example, from an admin UI):

```dart
call.clearModerationBlur();
```

---

For the most recent version of this documentation, visit [https://getstream.io/video/docs/flutter/ui-cookbook/call-moderation/](https://getstream.io/video/docs/flutter/ui-cookbook/call-moderation/).