> ## 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.

# WebPurify Image Moderation


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

[WebPurify](https://www.webpurify.com/) offers an image moderation service based on human moderator experts. Cloudinary provides an add-on for using WebPurify's image moderation capabilities, fully integrated into Cloudinary's image management and transformation pipeline.     
        
With WebPurify's image moderation add-on, you can extend Cloudinary's powerful cloud-based image transformation and delivery capabilities with automatically moderation of your photos. When using the WebPurify add-on, **user uploaded images are automatically moderated, making sure that no adult or offensive photos are displayed to your web and mobile viewers**.  

> **NOTE**: The criteria for image moderation can be customized by [contacting us](https://support.cloudinary.com/hc/en-us/requests/new).
#### Getting started

Before you can use the WebPurify Image 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 image moderation flow

The following list describes the flow of uploading and displaying moderated images using Cloudinary and the WebPurify image moderation add-on: 

1. **Image upload**
  1. Your users upload an image to Cloudinary through your application.
  1. The uploaded images are set to a 'pending' status, with short term CDN caching.
1. **Image moderation**
  1. The uploaded image is sent to WebPurify for asynchronous moderation in the background.
  1. The image is either approved or rejected by WebPurify's moderation add-on.
  1. An optional notification callback is sent to your application with the image moderation result.
  1. If the image is approved, its cache settings are modified to be long-term.
  1. A rejected image does not appear in the Cloudinary Console, but is backed up, consuming storage, so that it can be restored if necessary.
1. **Manual override**
  1. Pending, approved and rejected images can be listed programmatically using Cloudinary's API or interactively using our online Media Library Web interface.
  1. You can [manually override](#manual_override) the automatic moderation using the API or 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).
## Request image moderation

To request moderation of uploaded images, set the `moderation` upload API parameter to `webpurify`:
      
```multi
|ruby
Cloudinary::Uploader.upload("local_file.jpg", 
  moderation: "webpurify")

|php_2
$cloudinary->uploadApi()->upload("local_file.jpg", 
  ["moderation" => "webpurify"]);

|python
cloudinary.uploader.upload("local_file.jpg",
  moderation = "webpurify")

|nodejs
cloudinary.v2.uploader
.upload("local_file.jpg", 
  { moderation: "webpurify" })
.then(result=>console.log(result)); 

|java
cloudinary.uploader().upload("local_file.jpg", 
  ObjectUtils.asMap("moderation", "webpurify"));

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"local_file.jpg"),
  Moderation = "webpurify"};
var uploadResult = cloudinary.Upload(uploadParams); 

|go
resp, err := cld.Upload.Upload(ctx, "local_file.jpg", uploader.UploadParams{
		Moderation: "webpurify"})

|android
MediaManager.get().upload("local_file.jpg")
  .option("moderation", "webpurify").dispatch(); 

|swift
let params = CLDUploadRequestParams().setModeration("webpurify")
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: "local_file.jpg", params: params)

|curl
curl https://api.cloudinary.com/v1_1/demo/image/upload -X POST -F 'file=@/path/to/local_file.jpg' -F 'moderation=webpurify' -F 'timestamp=173719931' -F 'api_key=436464676' -F 'signature=a781d61f86a6f818af'

|cli
cld uploader upload "local_file.jpg" moderation="webpurify"
```

> **TIP**:
>
> You can use **upload presets** to centrally define a set of upload options including add-on operations to apply, instead of specifying them in each upload call. You can define multiple upload presets, and apply different presets in different upload scenarios. You can create new upload presets in the **Upload Presets** page of the [Console Settings](https://console.cloudinary.com/app/settings/upload/presets) or using the [upload_presets](admin_api#upload_presets) Admin API method. From the **Upload** page of the Console Settings, you can also select default upload presets to use for image, video, and raw API uploads (respectively) as well as default presets for image, video, and raw uploads performed via the Media Library UI. 
> **Learn more**: [Upload presets](upload_presets)

The uploaded image is available for delivery based on the randomly assigned public ID with short-term caching of 10 minutes. Image moderation by the WebPurify add-on is performed asynchronously and should be completed within up to a few minutes. 

> **INFO**: WebPurify automatically rejects the following images: URLs with no image format extension, images with the image format written in CAPS and any images in the PDF format.

The following snippet shows the response of the upload API call that signifies that the WebPurify moderation is in the `pending` status.
    
```json
{
  "public_id": "gotjephlnz2jgiu20zni",
  "version": 1719307544,
  "url": "http://res.cloudinary.com/cld-docs/image/upload/v1719307544/gotjephlnz2jgiu20zni.jpg",
  "moderation": [{ "status": "pending", "kind": "webpurify" }],
  ...
}
```
          
## Status notification

Due to the fact that the WebPurify add-on moderates images asynchronously, you might want to get notified when the moderation process is completed.
    
When calling the upload API with WebPurify image moderation, you can request a [notification](notifications) by adding the `notification_url` parameter to a public HTTP or HTTPS URL of your online web application. Cloudinary sends a POST request to the specified endpoint when WebPurify moderation is completed.     

```multi
|ruby
Cloudinary::Uploader.upload("local_file.jpg", 
  moderation: "webpurify",
  notification_url: "https://mysite.example.com/hooks")

|php_2
$cloudinary->uploadApi()->upload("local_file.jpg", [
    "moderation" => "webpurify",
    "notification_url" => "https://mysite.example.com/hooks"]);

|python
cloudinary.uploader.upload("local_file.jpg",
  moderation = "webpurify",
  notification_url = "https://mysite.example.com/hooks")

|nodejs
cloudinary.v2.uploader
.upload("local_file.jpg", 
  { moderation: "webpurify",
    notification_url: "https://mysite.example.com/hooks" })
.then(result=>console.log(result)); 

|java
cloudinary.uploader().upload("local_file.jpg", 
  ObjectUtils.asMap(
    "moderation", "webpurify",
    "notification_url", "https://mysite.example.com/hooks"));

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"local_file.jpg"),
  Moderation = "webpurify",
  NotificationUrl = "https://mysite.example.com/hooks"};
var uploadResult = cloudinary.Upload(uploadParams); 

|go
resp, err := cld.Upload.Upload(ctx, "local_file.jpg", uploader.UploadParams{
		Moderation:      "webpurify",
		NotificationURL: "https://mysite.example.com/hooks"})

|android
MediaManager.get().upload("local_file.jpg")
  .option("moderation", "webpurify")
  .option("notification_url", "https://mysite.example.com/hooks").dispatch();
      
|swift
let params = CLDUploadRequestParams()
  .setModeration("webpurify")
  .setNotificationUrl("https://mysite.example.com/hooks")
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: "local_file.jpg", params: params)

|curl
curl https://api.cloudinary.com/v1_1/demo/image/upload -X POST -F 'file=@/path/to/local_file.jpg' -F 'moderation=webpurify' -F 'notification_url=https://mysite.example.com/hooks' -F 'timestamp=173719931' -F 'api_key=436464676' -F 'signature=a781d61f86a6f818af'

|cli
cld uploader upload "local_file.jpg" moderation="webpurify" notification_url="https://mysite.example.com/hooks"
```

The following JSON snippet is an example of a POST request sent to the notification URL when moderation is completed. The `moderation_status` value in this case can be either `approved` or `rejected`:

```json
{
  "moderation_response": "approved",
  "moderation_status": "approved",
  "moderation_kind": "webpurify",
  "moderation_updated_at": "2024-03-02T09:33:43Z",
  "asset_id": "429db1d66fdf74578ed1f2147c4d0080",
  "public_id": "gotjephlnz2jgiu20zni",
  "uploaded_at": "2024-03-02T09:33:42Z",
  "version": 1719307544,
  "url": "http://res.cloudinary.com/cld-docs/image/upload/v1719307544/gotjephlnz2jgiu20zni.jpg",
  "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/v1719307544/gotjephlnz2jgiu20zni.jpg",
  "etag": "83340520d28b704ca4f4b019effb33dc",
  "notification_type": "moderation" 
}
```

```json
{
  "moderation_response": "rejected",
  "moderation_status": "rejected",
  "moderation_kind": "webpurify",
  "moderation_updated_at": "2024-03-02T20:47:48Z",
  "asset_id": "429db1d66fdf74578ed1f2147c4d0080",
  "public_id": "upknxfupsmqzfomzmmpv",
  "uploaded_at": "2024-03-02T20:47:47Z",
  "version": 1571217178,
  "url": "http://res.cloudinary.com/cld-docs/image/upload/v1719334109/upknxfupsmqzfomzmmpv.jpg",
  "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/v1719334109/upknxfupsmqzfomzmmpv.jpg",
  "etag":"06778590d96907b60b5fa83795e7df3b",
  "notification_type":"moderation"
}          
```
 
The JSON content is signed using the API Secret of your Cloudinary product environment. For more details regarding Cloudinary's notifications and webhooks, see [this blog post](https://cloudinary.com/blog/webhooks_upload_notifications_and_background_image_processing).
                  

## Image moderation list

Cloudinary's Admin API can be used to list all moderated images. You can list images with a particular status, including approved, pending or rejected images, by specifying the value of the second parameter of the [`resources_by_moderation` API method](admin_api#get_resources_in_moderation). For example to list all *rejected* images:    
    
```multi
|ruby
Cloudinary::Api.resources_by_moderation("webpurify", "rejected")

|php_2
$api->assetsByModeration("webpurify", "rejected");

|python
cloudinary.api.resources_by_moderation("webpurify", "rejected")

|nodejs
cloudinary.api.resources_by_moderation(webpurify, 'rejected', 
  function(result)  { console.log(result); });
  
|java
cloudinary.api().resourcesByModeration("webpurify", "rejected", 
  ObjectUtils.emptyMap());

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

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

|cli
cld admin resources_by_moderation "webpurify" "rejected"
```

Example response:

```json
{
 "resources": 
  [{
    "asset_id": "3515c6000a548515f1134043f9785c2f",
    "public_id": "gotjephlnz2jgiu20zni",
    "format": "jpg",
    "version": 1719307544,
    "width": 1920,
    "height": 1441,
    "resource_type": "image",
    "created_at": "2024-06-25T09:25:44Z",
    "bytes": 896838,
    "type": "upload",
    "placeholder": false,
    "url": "http://res.cloudinary.com/cld-docs/image/upload/v1719307544/gotjephlnz2jgiu20zni.jpg",
    "secure_url": "https://res.cloudinary.com/cld-docs/image/upload/v1719307544/gotjephlnz2jgiu20zni.jpg",
    "asset_folder": "",
    "display_name": "gotjephlnz2jgiu20zni",
    "moderation_kind": "webpurify",
    "moderation_status": "rejected"
  },
  {
    "asset_id": "2a2c2de00a5b50171cdc855c40484bfd",
    "public_id": "zp4fgdbabhlwwa7bxu84",
    "format": "jpg",
    ...
  }
  ...
 ]
}
```   

## Manual override
  
While the automatic image moderation of the WebPurify add-on is very accurate, in some cases you may want to manually override the moderation decision. You can either approve a previously rejected image or reject an approved one.
    
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 **WebPurify** and then select the status (Pending, Rejected, or Approved) of the images you want to display.

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

Alternatively, you can use Cloudinary's Admin API to manually override the moderation result. The following sample code uses the `update` API method while specifying a public ID of a moderated image and setting the `moderation_status` parameter to the `approved` status.         

```multi
|ruby
Cloudinary::Api.update("hwepb67oxzh4lrigssld", 
  moderation_status: "approved")

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

|python
cloudinary.api.update("hwepb67oxzh4lrigssld",
  moderation_status = "approved")

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

|csharp
var updateParams = new UpdateParams("hwepb67oxzh4lrigssld"){
  ModerationStatus = "approved"};
var updateResult = cloudinary.Update(updateParams); 

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

|cli
cld admin update "hwepb67oxzh4lrigssld" moderation_status="approved"
```          

