Video Moderation

Stream's video moderation engine samples frames from an uploaded video and scores each frame with the same AI categories you use for images. The video takes the strictest frame verdict. Analysis runs asynchronously so the upload is not held back.

Results are returned as ai_video. Existing video rules, the review queue, webhooks, and billing keep working.

How it works

When a video is uploaded:

  1. The video is accepted immediately.
  2. Stream samples frames evenly across the whole video (default one frame per second). If the video is long, the sample rate is thinned so the full video is still covered.
  3. Each frame is scored against your video policy rules (the same label and confidence model as image moderation).
  4. The video action is the strictest frame action. Labels from every flagged frame are combined.
  5. The message or post is updated when analysis finishes.
  6. Flagged videos appear in the content review queue. Open Moderation > Review Queue in the dashboard.

You can change how densely frames are sampled in the dashboard video policy.

Supported categories

These are the categories shown in the dashboard video policy editor. Video uses the image moderation categories, without PII and QR Code, and has no subcategories:

  • Explicit
  • Non-Explicit Nudity of Intimate parts and Kissing
  • Swimwear or Underwear
  • Violence
  • Visually Disturbing
  • Drugs & Tobacco
  • Alcohol
  • Rude Gestures
  • Gambling
  • Hate Symbols

Set a confidence threshold per category (1 to 100). Higher values flag less. A threshold of 90 only matches highly confident frames, which means fewer flags and fewer false positives.

Supported formats

Video moderation accepts most common video containers and codecs, including:

  • MP4 (.mp4, .m4v)
  • QuickTime (.mov), including iPhone recordings in HEVC (H.265) and HDR
  • WebM (.webm)
  • Matroska (.mkv)
  • AVI (.avi)
  • MPEG (.mpg, .mpeg, .ts)
  • 3GP (.3gp)
  • FLV (.flv)
  • WMV (.wmv)

Supported video codecs include H.264, H.265 (HEVC), VP8, VP9, AV1, MPEG-2, MPEG-4 Part 2, and ProRes.

The format is detected from the file contents, not the extension. The file must include duration metadata. Videos without it are not moderated. To keep unsupported uploads out entirely in Stream Chat, configure the app's file upload allowlist or blocklist from the dashboard. This is a Stream Chat upload setting, not part of the Moderation API; for standalone moderation, filter file types in your own upload flow.

Configuration

Set an action for each category you care about on ai_video_config, with a required min_confidence on a 0-100 scale, the same shape as image rules. Video and image are set separately in the policy, so video settings don't affect image moderation. Live calls use video_call_rule_config, not this field.

await client.moderation.upsertConfig({
  key: "chat:messaging",
  ai_video_config: {
    rules: [
      { label: "Explicit", action: "remove", min_confidence: 70 },
      { label: "Violence", action: "flag", min_confidence: 50 },
    ],
  },
});

Actions are flag, shadow, remove, bounce, bounce_flag, and bounce_remove. Use flag for borderline frames and remove for content that should not stay up.

Send video URLs in moderation_payload.videos with the Check API. Stream Chat and Feeds send attached videos for you.

const response = await client.moderation.check({
  entity_type: "listing",
  entity_id: "listing-123",
  entity_creator_id: "user-42",
  config_key: "marketplace",
  moderation_payload: {
    videos: ["https://cdn.example.com/listings/123/tour.mp4"],
  },
});
// response.status is "pending" until the video is analyzed

Limitations

  • Analysis is always asynchronous. The verdict arrives a few seconds to a few minutes after the request, depending on length. The async field on ai_video_config is ignored for video, and force_sync on Check skips video entirely, so don't use either to wait for a verdict.
  • Very long videos are sampled more sparsely so the whole file is still covered.

Hold a video until it's checked

Stream Chat and Feeds publish the video right away and update the message or post if it is flagged or removed. To keep a video hidden until it's confirmed safe in your own app:

  1. Store the video as pending and don't show it to other users.
  2. Call Check with the video. The response has status: "pending".
  3. Handle the moderation_check.completed webhook. It carries entity_id, entity_type, and recommended_action.
  4. Publish the video when recommended_action is keep, and remove or hold it for review otherwise.