val callServiceConfigRegistry = CallServiceConfigRegistry().apply {
// Set configuration for all call types.
register(CallType.AnyMarker.name) {
setModerationConfig(
ModerationConfig(
moderationWarningConfig = ModerationWarningConfig(
enable = true,
displayTime = 5_000L,
),
videoModerationConfig = VideoModerationConfig(
enable = true,
blurDuration = 25_000L,
),
),
)
}
}
// Inject the registry into the SDK builder once during initialization.
StreamVideoBuilder(callServiceConfigRegistry = callServiceConfigRegistry, ... )Video moderation
The backend periodically captures video keyframes from each participant and analyzes them using the moderation service. When a violation is detected, the backend sends a moderation event to the SDK. The specific actions taken depend on the configured policy in the dashboard.
Events
- Moderation Warning – first violation, show a warning banner. Event:
CallModerationWarningEvent. - Moderation Blur – violation continues, blur/obscure the user’s outgoing video. Event:
CallModerationBlurEvent. - Call Ended – repeated violations, end the call with a policy explanation. Event:
CallEndedEvent(reason"PolicyViolationModeration").
Blur enforcement (event 2) and the final call termination (event 3) are handled automatically at the SDK level, even if you do not ship any UI.
Warning banners are only rendered by the CallContent composable inside the stream-video-android-ui-compose module.
Enabling & Configuring Video Moderation
Video moderation is enabled by default for all calls. You can disable it by setting the enable property of ModerationWarningConfig and VideoModerationConfig to false.
Register your ModerationConfig via CallServiceConfigRegistry when creating StreamVideoBuilder.
Configure Video moderation
To configure video moderation you can use the provided configuration classes.
Configure the moderation behavior via the CallServiceConfigRegistry by supplying an instance of ModerationConfig.
These configurations are stored per call type and automatically applied whenever a matching call starts. The snippet below shows how to configure a warning display time of 5 seconds and a blur duration of 25 seconds that applies to all call types (these are also the default values):
The blur effect for moderation
The blur effect is implemented as a BitmapVideoFilter that modifies the outgoing video frame.
By default, DefaultModerationVideoFilter (a software implementation) is used. It runs entirely on the CPU, which is fine for short warnings but can be expensive if you expect blur periods to last longer or need to support low-end devices. In those cases prefer a hardware accelerated filter from the Stream video filters for Android.
// Add the dependency
implementation("io.getstream:stream-video-android-filters-video:$stream_version")You can then supply a different bitmapVideoFilter in the VideoModerationConfig class.
// Use the filter
val moderationConfig = ModerationConfig(
moderationWarningConfig = ModerationWarningConfig(
enable = true,
displayTime = 5_000L
),
videoModerationConfig = VideoModerationConfig(
enable = true,
blurDuration = 20_000L,
bitmapVideoFilter = SimpleBlurVideoFilter(), // This uses the filter from the `stream-video-android-filters-video` package
),
)As a final option you can also supply your own custom BitmapVideoFilter implementation.
class CustomVideoFilter : BitmapVideoFilter() {
override fun applyFilter(videoFrameBitmap: Bitmap) {
// Your custom filter logic here, e.g. blank out the bitmap
}
}Customizing Moderation UI
The StreamVideo Android Compose UI (CallContent) ships with moderation-ready warning.
You can render custom Video Moderation Warning UI to align with the rest of your experience.
By default the warning UI is a snackbar-like element shown at the bottom of the screen. To implement custom moderation warnings, supply your own UI in CallContent.
If you want to inform the user that moderation blur is active (for example with an overlay or helper text), supply an implementation in the videoModerationBlurUi here:
@Composable
public fun CallContent(
videoModerationWarningUi: @Composable (Call, String?) -> Unit = { _, message ->
// Your custom UI here
},
videoModerationBlurUi: @Composable (Call) -> Unit = {
// Your custom UI here
}
)CallContent automatically dismisses both UIs after the durations specified in ModerationConfig.
Low level implementation
If you are not using the Compose components, but instead you have your own custom UI, listen to the events directly and render your own warning/blur/call-ended state. The SDK still applies the blur effect according to the config and still leaves the call when the policy is violated; only the UI portion needs to be implemented by the integration.
For example, in your ViewModel you can observe the events and react accordingly:
viewModelScope.launch {
call.events.collect { event ->
when (event) {
is CallModerationWarningEvent -> {
// Instruct the UI to show moderation warning UI
}
is CallModerationBlurEvent -> {
// Instruct the UI to show additional UI for blur (e.g. informing the user that their video is being blurred)
}
is CallEndedEvent -> {
if (event.reason == CallEndedReason.PolicyViolationModeration) {
// Instruct the UI to show policy violation UI
}
}
}
}
}Additional moderation support
You can also trigger moderation manually on the publisher side if you have extra rules within your integration (for example, a live moderator toggles blur for a specific participant, or your backend detects issues outside the built-in flow). Once your integration decides that the local publisher should be blurred, instruct the SDK to apply the moderation effect to their video feed:
// On the publisher side
call.state.applyVideoModeration(
bitmapVideoFilter = DefaultModerationVideoFilter(),
)The bitmapVideoFilter parameter is optional and defaults to the filter configured in ModerationConfig, so you only need to pass it when overriding the behavior (for example, to match a backend-provided severity level).
Clear the effect manually when the external condition is resolved, or allow the timeout configured by videoModerationConfig.blurDuration to elapse:
call.state.clearVideoModeration()