> ## Documentation Index
> Fetch the complete documentation index at: https://cloudinary.com/documentation/llms.txt
> Use this file to discover all available pages before exploring further.

# Google AI Video Moderation


[Cloudinary](https://cloudinary.com) is a cloud-based service that provides an end-to-end image and video management solution including uploads, storage, transformations, optimizations and delivery. Cloudinary offers a rich set of transformation and analysis capabilities and allows you to upload images and videos to the cloud, transform them on the fly and deliver them to your users optimized and cached via a fast CDN.

[Google Cloud Video Intelligence](https://cloud.google.com/video-intelligence/) is a service that makes it easy to add video analysis to your applications. Cloudinary provides an add-on for Google's automatic video moderation service, fully integrated into Cloudinary's video management and transformation pipeline.     
        
With the Google AI Moderation add-on, you can extend Cloudinary's powerful cloud-based transformation and delivery capabilities with automatic AI-based moderation of your videos. Protect your users from explicit and suggestive adult content in your user-uploaded videos, making sure that no offensive videos are displayed to your viewers. Adult content is generally inappropriate for those under 18 years of age and includes, but is not limited to, nudity, sexual activities, and pornography. Such content detected in cartoons or anime is also identified.
#### Getting started

Before you can use the Google AI Video Moderation add-on:

* You must have a Cloudinary account. If you don't already have one, you can [sign up](https://cloudinary.com/users/register_free) for a free account. 

* Register for the add-on: make sure you're logged in to your account and then go to the [Add-ons](https://console.cloudinary.com/app/settings/addons) page. For more information about add-on registrations, see [Registering for add-ons](cloudinary_add_ons#registering_for_add_ons).

* Keep in mind that many of the examples on this page use our SDKs. For SDK installation and configuration details, see the relevant [SDK](cloudinary_sdks) guide.
  
* If you're new to Cloudinary, you may want to take a look at the [Developer Kickstart](dev_kickstart) for a hands-on, step-by-step introduction to a variety of features.

## Automatic video moderation flow

The following describes the flow of uploading and displaying moderated videos using Cloudinary and the Google AI Video Moderation add-on: 
    
1. Your users upload a video to Cloudinary through your application.
2. The uploaded video is sent to Google for moderation and set to a 'pending' status.
3. The video is marked as either approved or rejected based on the results returned by Google.
4. An optional notification callback is sent to your application with the video moderation result.
5. A rejected video does not appear in the Cloudinary Console, but is backed up, consuming storage, so that it can be restored if necessary.
6. Moderated videos can be listed programmatically using Cloudinary's Admin API or interactively using the Media Library in your Console.
7. You can [manually override](#manual_override) the automatic moderation results using the [Admin API](admin_api#update_details_of_an_existing_resource) or the [Media Library](https://console.cloudinary.com/console/media_library).  
> **NOTE**: By default, assets that are marked for moderation are deliverable and available via the Media Library. If you'd like the assets marked for moderation to be blocked (until approved) either from the Media Library, or from being delivered, or from both, [contact support](https://support.cloudinary.com/hc/en-us/requests/new).
## Moderation categorization

Google assigns a moderation confidence level indicating the chances that a video contains unacceptable content. The likelihood is given as a value on the following scale: `very_unlikely`, `unlikely`, `possible`, `likely`, and `very_likely`.

The default moderation confidence level for rejecting an image is `likely`, unless specifically overridden (see explanation and examples below). All videos classified by Google with a value that is more severe than the rejection confidence level are classified as "rejected". Otherwise their status is set to "approved".

## Request video moderation

To request moderation while uploading a video with the default rejection confidence level, set the `moderation` upload API parameter to `google_video_moderation` and set the `resource_type` parameter to `video`:
      
```multi
|ruby
Cloudinary::Uploader.upload("my_file.mp4",
  resource_type: "video", 
  moderation: "google_video_moderation")
  
|php_2
$cloudinary->uploadApi()->upload("my_file.mp4", [
    "resource_type" => "video", 
    "moderation" => "google_video_moderation"]);
 
|python
cloudinary.uploader.upload("my_file.mp4",
  resource_type = "video", 
  moderation = "google_video_moderation")
      
|nodejs
cloudinary.v2.uploader
.upload("my_file.mp4", 
  { resource_type: "video", 
    moderation: "google_video_moderation"})
.then(result=>console.log(result)); 

|java
cloudinary.uploader().upload("my_file.mp4", 
  ObjectUtils.asMap(
    "resource_type", "video", 
    "moderation", "google_video_moderation"));

|csharp
var uploadParams = new VideoUploadParams(){
  File = new FileDescription(@"my_file.mp4"),
  Moderation = "google_video_moderation"};
var uploadResult = cloudinary.Upload(uploadParams); 

|go
resp, err := cld.Upload.Upload(ctx, "my_file.mp4", uploader.UploadParams{
		ResourceType: "video",
		Moderation:   "google_video_moderation"})

|android
MediaManager.get().upload("my_file.mp4")
  .option("resource_type", "video")
  .option("moderation", "google_video_moderation").dispatch();

|swift
let params = CLDUploadRequestParams()
  .setResourceType(.video)
  .setModeration("google_video_moderation")
var mySig = MyFunction(params)  // your own function that returns a signature generated on your backend
params.setSignature(CLDSignature(signature: mySig.signature, timestamp: mySig.timestamp))
let request = cloudinary.createUploader().signedUpload(
  url: "my_file.mp4", params: params)

|curl
curl https://api.cloudinary.com/v1_1/demo/video/upload -X POST -F 'file=@/path/to/my_file.mp4' -F 'moderation=google_video_moderation' -F 'timestamp=173719931' -F 'api_key=436464676' -F 'signature=a781d61f86a6f818af'

|cli
cld uploader upload "my_file.mp4" resource_type="video" moderation="google_video_moderation"
```

By default, if any frame in the video returns a result of *at least* `likely`, then the video will be rejected. You can override the default rejection confidence level of `likely` by including the new value as part of the 'moderation' parameter value, separated by a colon. Possible rejection values are: `unlikely`, `possible`, `likely`, and `very_likely`.

For example, to request moderation with the rejection confidence level set to `possible`: 

```multi
|ruby
Cloudinary::Uploader.upload("my_file.mp4", 
  resource_type: "video", 
  moderation: "google_video_moderation:possible")
  
|php_2
$cloudinary->uploadApi()->upload("my_file.mp4", [
    "resource_type" => "video", 
    "moderation" => "google_video_moderation:possible"]);

|python
cloudinary.uploader.upload("my_file.mp4",
  resource_type = "video", 
  moderation = "google_video_moderation:possible")
      
|nodejs
cloudinary.v2.uploader
.upload("my_file.mp4", 
  { resource_type: "video", 
    moderation: "google_video_moderation:possible"})
.then(result=>console.log(result)); 

|java
cloudinary.uploader().upload("my_file.mp4", 
  ObjectUtils.asMap(
    "resource_type", "video", 
    "moderation", "google_video_moderation:possible"));

|csharp
var uploadParams = new VideoUploadParams(){
  File = new FileDescription(@"my_file.mp4"),
  Moderation = "google_video_moderation:possible"};
var uploadResult = cloudinary.Upload(uploadParams);

|go
resp, err := cld.Upload.Upload(ctx, "my_file.mp4", uploader.UploadParams{
		ResourceType: "video",
		Moderation:   "google_video_moderation:possible"})

|android
MediaManager.get().upload("my_file.mp4")
  .option("resource_type", "video")
  .option("moderation", "google_video_moderation:possible").dispatch();

|swift
let params = CLDUploadRequestParams()
  .setResourceType(.video)
  .setModeration("google_video_moderation:possible")
var mySig = MyFunction(params)  // your own function that returns a signature generated on your backend
params.setSignature(CLDSignature(signature: mySig.signature, timestamp: mySig.timestamp))
let request = cloudinary.createUploader().signedUpload(
  url: "my_file.mp4", params: params)  

|curl
curl https://api.cloudinary.com/v1_1/demo/video/upload -X POST -F 'file=@/path/to/my_file.mp4' -F 'moderation=google_video_moderation:possible' -F 'timestamp=173719931' -F 'api_key=436464676' -F 'signature=a781d61f86a6f818af'

|cli
cld uploader upload "my_file.mp4" resource_type="video" moderation="google_video_moderation:possible"
```

## Moderation response

As moderation is processed asynchronously, the initial upload response will include a `moderation` parameter indicating the status and kind of moderation:

```json
"moderation":[{ "status":"pending", "kind": "google_video_moderation" }]
```

Once the moderation is complete, you will receive a [notification](notifications) indicating the results of the request for moderation. The snippet below shows the individual frames that failed the moderation evaluation, and that the video has been placed in 'rejected' moderation status.

```json
{
...
"moderation_response":
  {"moderation_confidence": "POSSIBLE",
   "frames":
     [{"pornography_likelihood": "POSSIBLE",
       "time_offset": 0.510936},
      {"pornography_likelihood": "LIKELY",
      "time_offset": 2.832345},
      ...
      {"pornography_likelihood": "VERY_LIKELY",
      "time_offset": 14.014693}],
   "moderation_status": "rejected",
   "moderation_kind": "google_video_moderation",
   "moderation_updated_at": "2018-11-13T12:37:30Z",
   "asset_id": "466ee700176d83ccf05cad3c33f590c7",}
 ...
}
```

                  
## Video moderation listing

Cloudinary's Admin API can be used to list all moderated videos. You can list either the approved or the rejected videos by specifying the second parameter of the [`resources_by_moderation` API method](admin_api#get_resources_in_moderation). For example, to list all videos rejected by the Google AI Video Moderation add-on: 

```multi
|ruby
Cloudinary::Api.resources_by_moderation("google_video_moderation", "rejected", resource_type: "video")

|php_2
$api->assetsByModeration("google_video_moderation", "rejected", ["resource_type" => "video"]);

|python
cloudinary.api.resources_by_moderation("google_video_moderation", "rejected", resource_type = "video")

|nodejs
cloudinary.api
.resources_by_moderation("google_video_moderation", "rejected", { resource_type: "video" })
.then(result=>console.log(result)); 
  
|java
cloudinary.api().resourcesByModeration("google_video_moderation", "rejected", 
  ObjectUtils.emptyMap("resource_type", "video"));

|csharp
var listResourcesResult = cloudinary.ListResourcesByModerationStatus("google_video_moderation", "rejected");

|go
resp, err := cld.Admin.AssetsByModeration(ctx, admin.AssetsByModerationParams{
		AssetType: "video",
		Kind:      "google_video_moderation",
		Status:    "rejected"})

|cli
cld admin resources_by_moderation "google_video_moderation" "rejected" resource_type="video"
```

```json
{
 "resources": 
  [{
    "asset_id": "3515c6000a548515f1134043f9785c2f",
    "public_id": "tquyfignx5bxcbsupr6a",
    "format": "mp4",
    "version": 1720618130,
    "width": 1920,
    "height": 1441,
    "resource_type": "video",
    "created_at": "2024-06-25T09:25:44Z",
    "bytes": 896838,
    "type": "upload",
    "placeholder": false,
    "url": "https://res.cloudinary.com/cld-docs/video/upload/v1720618130/tquyfignx5bxcbsupr6a.mp4",
    "secure_url": "https://res.cloudinary.com/cld-docs/video/upload/v1720618130/tquyfignx5bxcbsupr6a.mp4",
    "asset_folder": "",
    "display_name": "tquyfignx5bxcbsupr6a",
  },
  {
    "asset_id": "3515c6000a548515f1134043f9785c2f",,
    "public_id": "zp4fgdbabhlwwa7bxu84",
    "format": "mp4",
    ...
  }
  ...
 ]
}
```                

## Manual override
  
As the automatic video moderation of the Google AI Moderation add-on is based on a decision made by an advanced artificial intelligence algorithm, in some cases you may want to manually override the automatic moderation decision and either approve a previously rejected video or reject an approved one.

### Overriding moderation via the Media Library

One way to manually override the moderation result is using Cloudinary's Media Library Web interface. From the left navigation menu, select **Moderation**. Then, from moderation tools list in the top menu, select **Google Video** and then select the status of the videos you want to display (Rejected, or Approved).

* When displaying the videos *rejected* by Google, you can click on the green **Approve** button to revert the decision and recover the original rejected video.
* When displaying the videos *approved* by Google, you can click on the red **Reject** button to revert the decision and prevent a certain video from being publicly available to your users.   

### Overriding moderation via the Admin API
  
Alternatively to using the Media Library interface, you can use Cloudinary's Admin API to manually override the moderation result. The following example uses the [`update` API method](admin_api#update_details_of_an_existing_resource) while specifying a public ID of a moderated video and setting the `moderation_status` parameter to the `rejected` status.         
          
```multi
|ruby
Cloudinary::Api.update("hwepb67oxzh4lrigssld", 
  resource_type: "video", 
  moderation_status: "rejected")

|php_2
$api->update("hwepb67oxzh4lrigssld", [
    "resource_type" => "video", 
    "moderation_status" => "rejected"]);

|python
cloudinary.api.update("hwepb67oxzh4lrigssld",
  resource_type = "video", 
  moderation_status = "rejected")

|nodejs
cloudinary.v2.api
.update("hwepb67oxzh4lrigssld",
  { resource_type: "video", 
    moderation_status: "rejected" })
.then(result=>console.log(result));
  
|java
cloudinary.api().update("hwepb67oxzh4lrigssld", 
  ObjectUtils.asMap(
    "resource_type", "video", 
    "moderation_status", "rejected"));

|csharp
var updateParams = new UpdateParams("hwepb67oxzh4lrigssld"){
  ResourceType = "video",
  ModerationStatus = "rejected"};
var updateResult = cloudinary.Update(updateParams); 

|go
resp, err := cld.Admin.UpdateAsset(ctx, "hwepb67oxzh4lrigssld", admin.UpdateAssetParams{
		AssetType:        "video",
		ModerationStatus: "rejected"})

|cli
cld admin update "hwepb67oxzh4lrigssld" resource_type="video" moderation_status="rejected"
```

