Video Moderation / Continuous Moderation

Continuous Video Moderation


Continuous Video Moderation is done through a few steps:

  1. Your back-end submits a video and gets a stream ID from Sightengine
  2. Sightengine analyzes the video, and creates alerts each time offending content is found
  3. Your back-end receives callbacks (through webhooks) to inform you of any offending content. Or you can poll Sightengine to ask for status updates and moderation progress and results
  4. Once finished, the full results are sent to your server through a webhook

Submitting a Video to Sightengine

There are two ways to submit a video for Continuous Moderation:

  • Via raw bytes upload (you send the video file to our API). This is usually the best solution if you have a static video file at hand.
  • Via a streaming URL (you send a URL pointing to your video). This is usually the best solution for streaming and live feeds

Raw Bytes Upload

curl -X POST '' \
  -F 'media=@/path/to/video' \
  -F 'models=nudity' \
  -F 'callback_url=https://yourcallback/path' \
  -F 'api_user={api_user}' \
  -F 'api_secret={api_secret}'

URL upload

curl -X GET -G '' \
    -d 'stream_url=https://yourvideo/path' \
    -d 'models=nudity' \
    -d 'callback_url=https://yourcallback/path' \
    -d 'api_user={api_user}' \
    -d 'api_secret={api_secret}'

# if you haven't already, install the SDK with 'pip install sightengine'
from sightengine.client import SightengineClient
client = SightengineClient('{api_user}','{api_secret}')
client.check('nudity').video('https://yourvideo/path', 'https://yourcallback/path')

// if you haven't already, install the SDK with 'composer require sightengine/client-php'
use \Sightengine\SightengineClient;
$client = new SightengineClient('{api_user}','{api_secret}');
$client->check(['nudity'])->video('https://yourvideo/path', 'https://yourcallback/path');

// if you haven't already, install the SDK with 'npm install sightengine --save'
var sightengine = require('sightengine')('{api_user}','{api_secret}');
sightengine.check(['nudity']).video('https://yourvideo/path', 'https://yourcallback/path').then(function(result) {
    // The API response (result)
}).catch(function(err) {
    // Handle error

Please note that you will have to choose the models you wish to apply to your video, and make sure you have an API user and API secret. You can get those from your dashboard.

Receiving webhook call-backs

Once you have submitted a video stream and received a 200 HTTP status code, our Moderation Engine will start consuming the stream and will assign a moderation score to relevant frames and send moderation results to your callback URL.

To avoid sending too many callback events, the engine will send callbacks only when one of the following happens:

  • the video has been completely read and moderation is done
  • an "interesting event" has been detected. One such event would be the presence of nudity. This is defined by setting threshold values on the nudity probabilities.
  • an error was encountered after the initial request was closed

Callback recommendations

Acknowledging receipt

To acknowledge receipt of a callback, your endpoint should return a 2xx HTTP status code. Any other information returned in the request headers or request body is ignored. All response codes outside this range, including 3xx codes, will indicate to Sightengine that you did not receive the callback. This does mean that a URL redirection or a "Not Modified" response will be treated as a failure.

If your callback script performs complex logic, or makes network calls, it's possible the script would timeout before Sightengine sees its complete execution. For that reason, you may want to have your callback endpoint immediately acknowledge receipt by returning a 2xx HTTP status code, and then perform the rest of its duties.

Verifying callbacks

As an extra security measure, you should check that the media id value returned in the callback matches the media id returned in the initial API response. This is can be helpful if you have several streams moderated at the same time and need to verify what media each callback refers to.


If you use an HTTPS URL for your callback endopint, please make sure that your server is correctly configured to support HTTPS with a valid server certificate. Sightengine will valide that the connection to your server is secure before sending the data.


Keep in mind that your callback may occasionally receive the same event more than once. We advise you to guard against duplicated event receipts by making your event processing idempotent.

Interacting with video moderations

Getting the list of on-going video moderations

At any time you can request a list of on-going video moderations, meaning video moderations that have been launched but have not reached the stopped or finished status.

This can be useful if you hit your maximum concurrency limit, to see what moderations are on-going, or if you wish to monitor the progress of videos but don't have access to the stream ids.

curl -X GET -G '' \
  -d 'api_user={api_user}' \
  -d 'api_secret={api_secret}'

Getting the status and results of an on-going video moderation

curl -X GET -G '' \
  -d 'id={media_id}' \
  -d 'api_user={api_user}' \
  -d 'api_secret={api_secret}'

Early stopping of a video moderation

In general you should not worry about having to stop Video Moderation. Moderation actions automatically finish once the video ends or once the video timeout has been reached. Early Stopping is useful either if you have a long running video and realize you don't want/need to run it through moderation until the end, or if you made a mistake and need to stop Moderation immediately.

To stop a video, simply perform the following command, providing the video's media id.

curl -X DELETE '' \
  -d 'id={media_id}' \
  -d 'api_user={api_user}' \
  -d 'api_secret={api_secret}'

Did you find this page helpful?

We're always looking for advice to help improve our documentation!

Let us know what you think