> ## Documentation Index
> This page is part of the Image and Video APIs product. Fetch the complete documentation index for Image and Video APIs at: https://cloudinary.com/documentation/llms-image-and-video-apis.txt?referrer=docpage and then use it to discover all relevant pages before exploring further.
> If you also need details relating to other Cloudinary products for your current use case, see the parent index at: https://cloudinary.com/documentation/llms.txt?referrer=docpage

# Post-upload processing


In addition to the [upload control parameters](upload_parameters) that control what happens during the upload itself, you can also include options in your upload call or upload preset that trigger additional processing after Cloudinary uploads and stores the asset. Even though you specify these options up front, they run asynchronously in the background after Cloudinary stores the asset, and you can use [webhook notifications](#webhook_notifications) to monitor when processing completes.

This page covers the post-upload processing parameters: moderation, analysis, on-success event handling, and running otherwise synchronous operations asynchronously.

> **TIP**: For a full listing of all the available optional parameters for the upload method, see the [Upload API reference](image_upload_api_reference#upload_optional_parameters).

## Moderation 

[Moderating assets](moderate_assets) before they go live lets you keep out inappropriate or offensive content, reject assets that don't meet your quality standards, and ensure that only the right content reaches your audience. This is especially important for platforms that accept user-generated content (UGC), where you can't control what users upload. 

You can manually mark an uploading asset for moderation or use one of the AI-based [add-ons](cloudinary_add_ons#moderation_and_malware_detection) to automatically moderate assets at upload time. Assets added to the moderation queue can then be [reviewed in the Media Library](moderate_assets#moderating_assets_via_the_media_library).

For example, you can moderate assets while uploading them by specifying the `moderation` parameter in the upload method. The following code marks an image for moderation by the [WebPurify's Image Moderation add-on](webpurify_image_moderation_addon) and the [Cloudinary Duplicate Image Detection add-on](cloudinary_duplicate_image_detection_addon):

``` multi
|ruby 
Cloudinary::Uploader.upload("user_photo.jpg", 
  moderation: 'webpurify|duplicate:0')

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

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

|python
cloudinary.uploader.upload("user_photo.jpg",
  moderation = "webpurify|duplicate:0")

|java
cloudinary.uploader().upload("user_photo.jpg", 
  Cloudinary.asMap("moderation", "webpurify|duplicate:0"));

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

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

|android
MediaManager.get().upload("user_photo.jpg")
  .option("moderation", "webpurify|duplicate:0").dispatch();

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

|cli
cld uploader upload user_photo.jpg moderation=webpurify|duplicate:0

|curl
curl https://api.cloudinary.com/v1_1/cld-docs/image/upload -X POST --data 'file=user_photo.jpg&moderation=webpurify|duplicate:0&timestamp=173719931&api_key=436464676&signature=a788d68f86a6f868af'
```

> **NOTE**:
>
> :title=Tips

> * See the [user-generated content guide](user_generated_content) for best practices on managing UGC at scale.

> * For brand and enterprise use cases, [Cloudinary Moderation](cloudinary_moderation) uses AI tailored to your visual guidelines to validate assets for brand consistency, quality, and compliance. It functions like a dedicated brand reviewer to ensure every asset meets your standards before it goes live.

## Analysis

When uploading assets to your Cloudinary product environment, you can request different types of [analysis](analyze_assets) to be performed on the assets.  In addition to [Image quality analysis](image_quality_analysis), [Accessibility analysis](accessibility_analysis), and [Semantic data extraction](semantic_data_extraction), Cloudinary has a number of [add-ons](cloudinary_add_ons) that enable various types of AI-based analyses.

For example, you can request quality and accessibility analysis on assets while uploading them by specifying the `quality_analysis` and `accessibility_analysis` parameters in the upload method. The following code uploads the `user_photo.jpg` image and requests analysis:

``` multi
|ruby 
Cloudinary::Uploader.upload("user_photo.jpg", 
  quality_analysis: true, 
  accessibility_analysis: true)

|php_2
$cloudinary->uploadApi()->upload("user_photo.jpg",[
  "quality_analysis" => true,
  "accessibility_analysis" => true ]);
s
|nodejs
cloudinary.v2.uploader
.upload("user_photo.jpg",
  { quality_analysis: true,
    accessibility_analysis: true })
.then(result=>console.log(result)); 

|python
cloudinary.uploader.upload("user_photo.jpg",
  quality_analysis = 1,
  accessibility_analysis = 1)

|java
cloudinary.uploader().upload("user_photo.jpg", 
  Cloudinary.asMap(
    "quality_analysis", true,
    "accessibility_analysis", true));

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"user_photo.jpg"),
  QualityAnalysis = true
  AccessibilityAnalysis" = true};
var uploadResult = cloudinary.Upload(uploadParams); 

|go
resp, err := cld.Upload.Upload(ctx, "user_photo.jpg", uploader.UploadParams{
	QualityAnalysis:        api.Bool(true),
  AccessibilityAnalysis:  api.Bool(true)})

|cli
cld uploader upload user_photo.jpg quality_analysis=true accessibility_analysis=true

|curl
curl https://api.cloudinary.com/v1_1/cld-docs/image/upload -X POST --data 'file=user_photo.jpg&quality_analysis=true&accessibility_analysis=true&timestamp=173719931&api_key=436464676&signature=a788d68f86a6f868af'
```

The following is an example of the response returned:

```json
{
    "asset_id": "3515c6000a548515f1134043f9785c2f",
    "public_id": "gotjephlnz2jgiu20zni",
    "version": 1719307544,
    "version_id": "7d2cc533bee9ff39f7da7414b61fce7e",
    "signature": "d0b1009e3271a942836c25756ce3e04d205bf754",
    "width": 1920,
    "height": 1441,
    "format": "jpg",
    "resource_type": "image",
    "created_at": "2024-06-25T09:25:44Z",
    "tags": [],
    "pages": 1,
    "bytes": 896838,
    "type": "upload",
    "etag": "2a2df1d2d2c3b675521e866599273083",
    "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",
    "quality_analysis": {
        "focus": 1.0
    },
    "accessibility_analysis": {
        "colorblind_accessibility_analysis": {
            "distinct_edges": 0.54,
            "distinct_colors": 0.95,
            "most_indistinct_pair": [
                "#DAD9D9",
                "#AFCA9D"
            ]
        },
        "colorblind_accessibility_score": 0.75
    },
    "original_filename": "user_photo",
    "api_key": "614335564976464"
}
```


## On success: Update metadata after upload

The `on_success` parameter lets you customize asset behavior after a successful upload by running JavaScript code. Use it when you need information that's only available after the upload completes, such as AI captioning results, quality analysis scores, or face detection data. 

> **TIP**:
>
> To inject scripts that run *before* the upload to conditionally modify upload options instead, see [Eval: Modify upload options before upload](upload_parameters#eval_modify_upload_options_before_upload).

#### How it works

You write JavaScript to:

* Inspect `e.upload_info` (`event.upload_info`), which contains the full upload response, e.g.:
  * `e.upload_info.width` – to check final dimensions
  * `e.upload_info.info.detection.captioning` – to access AI analysis results
  > **NOTE**: You can also check e.status, which is either "success" or "failure". This is rarely needed for `on_success` (since it only runs on success), but may be useful in shared scripts used across multiple event types (e.g., `on_error`, `on_failure`).

* Call `current_asset.update()` to assign new values to: 
  * `tags` – list of tags
  * `context` – contextual key-value metadata
  * `metadata` – structured metadata fields from your product environment
  > **NOTE**: The values you assign with `current_asset.update()` replace any existing values. They aren't merged or appended.

#### Quick example: Add a caption after upload

Set a "caption" in the asset's contextual metadata based on the uploaded file's name.

* Here's the JavaScript code to include in your upload call as a string;

    ```js
    const base = e.upload_info?.original_filename?.split('.')[0];
    current_asset.update({ context: { caption: `Uploaded file: ${base}` } });
    ```

* Here's how to include that code in your upload request across various SDKs:

    ```multi
    |ruby
    Cloudinary::Uploader.upload("photo.jpg", 
      on_success: "const base = e.upload_info?.original_filename?.split('.')[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })")

    |php_2
    $cloudinary->uploadApi()->upload("photo.jpg", [ 
      "on_success" => "const base = e.upload_info?.original_filename?.split('.')[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })" ]);

    |nodejs
    cloudinary.v2.uploader.upload("photo.jpg", {
      on_success: "const base = e.upload_info?.original_filename?.split('.')[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })"
    });

    |python
    cloudinary.uploader.upload("photo.jpg",
      on_success = "const base = e.upload_info?.original_filename?.split('.')[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })")

    |java
    cloudinary.uploader().upload("photo.jpg", 
      Cloudinary.asMap(
        "on_success", "const base = e.upload_info?.original_filename?.split('.')[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })"));

    |csharp
    var uploadParams = new ImageUploadParams(){
      File = new FileDescription(@"photo.jpg"),
      OnSuccess = "const base = e.upload_info?.original_filename?.split('.')[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })" };
    var uploadResult = cloudinary.Upload(uploadParams); 

    |go
    resp, err := cld.Upload.Upload(ctx, "photo.jpg", uploader.UploadParams{
      OnSuccess: "const base = e.upload_info?.original_filename?.split('.')[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })" })

    |android
    MediaManager.get().upload("photo.jpg")
      .option("on_success", "const base = e.upload_info?.original_filename?.split('.')[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })").dispatch();

    |swift
    let params = CLDUploadRequestParams()
      .setOnSuccess("const base = e.upload_info?.original_filename?.split('.')[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })")
    var mySig = MyFunction(params)
    params.setSignature(CLDSignature(signature: mySig.signature, timestamp: mySig.timestamp))
    let request = cloudinary.createUploader().signedUpload(
      url: "photo.jpg", params: params)

    |cli
    cld uploader upload photo.jpg -O on_success 'const base = e.upload_info?.original_filename?.split(".")[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })'

    |curl
    curl https://api.cloudinary.com/v1_1/<cloud_name>/image/upload \
      -X POST --data 'file=photo.jpg&on_success=const base = e.upload_info?.original_filename?.split(".")[0]; current_asset.update({ context: { caption: `Uploaded file: ${base}` } })&timestamp=173719931&api_key=<your_key>&signature=<signature>'

    ```

#### Examples

**Save an AI-generated caption as contextual metadata**

Upload an asset and update its contextual metadata (context) with the caption returned from the [Cloudinary AI Content Analysis](cloudinary_ai_content_analysis_image_analysis#ai_based_image_captioning) add-on, and add the tag 'autocaption' (`current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})`):

``` multi
|ruby 
Cloudinary::Uploader.upload("user_photo.jpg", 
  detection: "captioning",
  on_success: "current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})")

|php_2
$cloudinary->uploadApi()->upload("user_photo.jpg",[ 
    "detection" => "captioning",
    "on_success" => "current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})" ]);

|nodejs
cloudinary.v2.uploader
.upload("user_photo.jpg",
  { detection: "captioning",
    on_success: "current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})" })
.then(result=>console.log(result)); 

|python
cloudinary.uploader.upload("user_photo.jpg",
  detection = "captioning",
  on_success = "current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})")

|java
cloudinary.uploader().upload("user_photo.jpg", 
  Cloudinary.asMap(
    "detection", "captioning",
    "on_success", "current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})"));

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"user_photo.jpg"),
  Detection = "captioning",
  OnSuccess = "current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})"};
var uploadResult = cloudinary.Upload(uploadParams); 

|go
resp, err := cld.Upload.Upload(ctx, "user_photo.jpg", uploader.UploadParams{
	Detection: "captioning",
	OnSuccess: "current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})"})


|android
MediaManager.get().upload("user_photo.jpg")
  .option("detection", "captioning")
  .option("on_success", "current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})").dispatch();

|swift
let params = CLDUploadRequestParams()
  .setOnSuccess("current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})")
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: "user_photo.jpg", params: params) 

|cli
cld uploader upload user_photo.jpg detection='captioning' -O on_success 'current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})'

|curl
curl https://api.cloudinary.com/v1_1/cld-docs/image/upload -X POST --data 'file=user_photo.jpg&detection=captioning&on_success=\"current_asset.update({tags: ['autocaption'], context: {caption: e.upload_info?.info?.detection?.captioning?.data?.caption}})\"&timestamp=173719931&api_key=436464676&signature=a788d68f86a6f868af'
```

**Set structured Metadata for large images**

Assign values to different types of structured metadata, but only if the image width exceeds 1000 pixels.

* Assign `high` to the single-select structured metadata field, `rating`.

* Assign `['print', 'web', 'social']` to the multiselect structured metadata field `usage_types`.

```multi
|ruby
Cloudinary::Uploader.upload("photo.jpg", 
  on_success: "current_asset.update({ metadata: { rating: 'high', usage_types: ['web', 'print', 'social'] } })")

|php_2
$cloudinary->uploadApi()->upload("photo.jpg", [ 
  "on_success" => "current_asset.update({ metadata: { rating: 'high', usage_types: ['web', 'print', 'social'] } })" ]);

|nodejs
cloudinary.v2.uploader.upload("photo.jpg", {
  on_success: "current_asset.update({ metadata: { rating: 'high', usage_types: ['web', 'print', 'social'] } })"
});

|python
cloudinary.uploader.upload("photo.jpg",
  on_success = "current_asset.update({ metadata: { rating: 'high', usage_types: ['web', 'print', 'social'] } })")

|java
cloudinary.uploader().upload("photo.jpg", 
  Cloudinary.asMap(
    "on_success", "current_asset.update({ metadata: { rating: 'high', usage_types: ['web', 'print', 'social'] } })"));

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"photo.jpg"),
  OnSuccess = "current_asset.update({ metadata: { rating: 'high', usage_types: ['web', 'print', 'social'] } })" };
var uploadResult = cloudinary.Upload(uploadParams); 

|go
resp, err := cld.Upload.Upload(ctx, "photo.jpg", uploader.UploadParams{
  OnSuccess: "current_asset.update({ metadata: { rating: 'high', usage_types: ['web', 'print', 'social'] } })" })

|android
MediaManager.get().upload("photo.jpg")
  .option("on_success", "current_asset.update({ metadata: { rating: 'high', usage_types: ['web', 'print', 'social'] } })").dispatch();

|swift
let params = CLDUploadRequestParams()
  .setOnSuccess("current_asset.update({ metadata: { rating: 'high', usage_types: ['web', 'print', 'social'] } })")
var mySig = MyFunction(params)
params.setSignature(CLDSignature(signature: mySig.signature, timestamp: mySig.timestamp))
let request = cloudinary.createUploader().signedUpload(
  url: "photo.jpg", params: params)

|cli
cld uploader upload photo.jpg -O on_success 'current_asset.update({ metadata: { rating: "high", usage_types: ["web", "print", "social"] } })'

|curl
curl https://api.cloudinary.com/v1_1/<cloud_name>/image/upload \
  -X POST --data 'file=photo.jpg&on_success=current_asset.update({ metadata: { rating: "high", usage_types: ["web", "print", "social"] } })&timestamp=173719931&api_key=<your_key>&signature=<signature>'
```

> **NOTE**:
>
> For structured metadata, the syntax depends on the field type defined in your product environment's metadata schema:

> * **Text or single-select fields**: Pass a single string value.

> * **Multi-select fields**: Use an array of strings (e.g., `["item1", "item2"]`).

**Append to existing tags**

To add tags without losing any existing tags, explicitly include the current tags from the upload response:

```multi
|ruby
Cloudinary::Uploader.upload("photo.jpg", 
  on_success: 'current_asset.update({
  tags: [...(e.upload_info?.tags || []), "autocaption"],
  context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption }
})')

|php_2
$cloudinary->uploadApi()->upload("photo.jpg", [ 
  "on_success" => 'current_asset.update({
  tags: [...(e.upload_info?.tags || []), "autocaption"],
  context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption }
})' ]);

|nodejs
cloudinary.v2.uploader.upload("photo.jpg", {
  on_success: `current_asset.update({
  tags: [...(e.upload_info?.tags || []), "autocaption"],
  context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption }
})`
});

|python
cloudinary.uploader.upload("photo.jpg",
  on_success = 'current_asset.update({
  tags: [...(e.upload_info?.tags || []), "autocaption"],
  context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption }
})')

|java
cloudinary.uploader().upload("photo.jpg", 
  ObjectUtils.asMap(
    "on_success", "current_asset.update({ tags: [...(e.upload_info?.tags || []), \"autocaption\"], context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption } })"));

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"photo.jpg"),
  OnSuccess = "current_asset.update({ tags: [...(e.upload_info?.tags || []), \"autocaption\"], context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption } })"
};
var uploadResult = cloudinary.Upload(uploadParams); 

|go
resp, err := cld.Upload.Upload(ctx, "photo.jpg", uploader.UploadParams{
  OnSuccess: `current_asset.update({
  tags: [...(e.upload_info?.tags || []), "autocaption"],
  context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption }
})` })

|android
MediaManager.get().upload("photo.jpg")
  .option("on_success", "current_asset.update({ tags: [...(e.upload_info?.tags || []), \"autocaption\"], context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption } })")
  .dispatch();

|swift
let params = CLDUploadRequestParams()
  .setParam("on_success", value: "current_asset.update({ tags: [...(e.upload_info?.tags || []), \"autocaption\"], context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption } })")

|cli
cld uploader upload photo.jpg -O on_success 'current_asset.update({
  tags: [...(e.upload_info?.tags || []), "autocaption"],
  context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption }
})'

|curl
curl https://api.cloudinary.com/v1_1/<cloud_name>/image/upload \
  -X POST --data 'file=photo.jpg&on_success=current_asset.update({ tags: [...(e.upload_info?.tags || []), "autocaption"], context: { caption: e.upload_info?.info?.detection?.captioning?.data?.caption } })&timestamp=173719931&api_key=<your_key>&signature=<signature>'

```

## Requesting asynchronous uploads

By default, when you call the upload method, Cloudinary processes the upload and returns a response synchronously. However, note that many of the post-upload processing options on this page (such as moderation, analysis, and transcription) always run asynchronously regardless of this setting, and return a `pending` status in the upload response.

For uploads that would otherwise be handled synchronously, you can request asynchronous processing by setting the `async` parameter to `true`. This is recommended for large assets or uploads that include parameters that take a long time to process, where waiting for the synchronous response would result in a poor experience for your users. When `async` is `true`, Cloudinary returns a short response immediately with a `pending` status and a batch ID, and sends the full upload response to your notification URL once processing is complete.

> **INFO**:
>
> * Whenever setting `async` to `true`, make sure to always pass a `notification_url` parameter for the [webhook notification](#webhook notifications).

> * Some optional parameters always process asynchronously regardless of the `async` setting (for example, moderation, transcription, and `raw_convert`). Even without `async: true`, always include a `notification_url` when using these parameters so you know when the additional processing is finished.

For example, to asynchronously upload an image, request the [Content Analysis add-on](cloudinary_ai_content_analysis_image_analysis#ai_based_image_captioning) to analyze the image and suggest a caption, and then send a notification to "https://mysite.example.com/upload_endpoint" when the processing is complete with the full upload response:

```multi
|ruby
Cloudinary::Uploader.upload("toy_room.jpg", 
  detection: "captioning",
  async: true, 
  notification_url: "https://mysite.example.com/upload_endpoint")

|php_2
$cloudinary->uploadApi()->upload("toy_room.jpg", 
  ["detection" => "captioning",
  "async" => true, 
  "notification_url" => "https://mysite.example.com/upload_endpoint"]);

|python
cloudinary.uploader.upload("toy_room.jpg",
  detection = "captioning", 
  async = True, 
  notification_url = "https://mysite.example.com/upload_endpoint")

|nodejs
cloudinary.v2.uploader
.upload("toy_room.jpg", 
  { detection: "captioning", 
    async: true,
    notification_url: "https://mysite.example.com/upload_endpoint" })
.then(result=>console.log(result)); 

|java
cloudinary.uploader().upload("toy_room.jpg", ObjectUtils.asMap(
  "detection", "captioning", 
  "async", true,
  "notification_url", "https://mysite.example.com/upload_endpoint"));

|csharp
var uploadParams = new ImageUploadParams() 
{
  File = new FileDescription(@"toy_room.jpg"),
  Detection = "captioning",
  Async = true,
  NotificationUrl = "https://mysite.example.com/upload_endpoint"
};
var uploadResult = cloudinary.Upload(uploadParams);  

|go
resp, err := cld.Upload.Upload(ctx, "toy_room.jpeg", uploader.UploadParams{
		Detection:   "captioning",
    Async: true,
    NotificationURL: "https://mysite.example.com/upload_endpoint"})

|android
MediaManager.get().upload("toy_room.jpg")
  .option("detection", "captioning")
  .option("async", true)
  .option("notification_url", "https://mysite.example.com/upload_endpoint").dispatch();

|swift
let params = CLDUploadRequestParams()
  .setDetection("captioning")
  .setAsync(true)
  .setNotificationUrl("https://mysite.example.com/upload_endpoint")
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: "toy_room.jpg", params: params) 

|cli
cld uploader upload "toy_room.jpg" detection="captioning" async=true notification_url="https://mysite.example.com/upload_endpoint"

|curl
curl https://api.cloudinary.com/v1_1/cld-docs/image/upload -X POST -F 'file=@/path/to/toy_room.jpg' -F 'detection=captioning' -F 'async=true' -F 'notification_url=https://mysite.example.com/upload_endpoint' -F 'timestamp=173719931' -F 'api_key=436464676' -F 'signature=a781d61f86a6f818af'
```

The immediate response to an asynchronous upload call is short and looks similar to this:

```json
{
  "status": "pending",
  "type": "upload",
  "batch_id": "a7877927ae1af0d1115485018ce92a6792c97938bb3edb9b0777d4663d6abbee"
}
```

When the processing is finished, the complete upload response is sent to the notification URL that you specified.

> **TIP**: You can also tell Cloudinary to [generate eager transformations in the background](eager_and_incoming_transformations#eager_asynchronous_transformations) by setting the `eager_async` parameter to true and providing an `eager_notification_url`.

## Webhook notifications

Cloudinary provides [webhook notifications](notifications) to inform your backend about upload events. When the upload is completed, an HTTP POST request can be sent to a public notification URL you provide. The payload contains all the results pertinent to the upload.

You can use webhook notifications with any upload, but we recommend using them whenever your upload includes asynchronous post-upload operations. This ensures your application is notified when processing completes.

For example, you can ask Cloudinary to send a notification when an asset finishes uploading, by specifying the `notification_url` parameter in the upload method. The following code uploads the `sample.jpg` image and then sends a notification to `https://mysite.example.com/my_notification_endpoint`.

> **NOTE**: A notification is sent to the destination you specified via the `notification_url` parameter in addition to any of the [global notification URLs](notifications#global_notification_urls) set to handle the upload.

For example, to add a `notification_url` to a specific upload call:

```multi
|ruby 
Cloudinary::Uploader.upload("sample.jpg", 
  notification_url: "https://mysite.example.com/my_notification_endpoint")
  
|php_2
$cloudinary->uploadApi()->upload("sample.jpg", 
  ["notification_url" => "https://mysite.example.com/my_notification_endpoint"]);

|python
cloudinary.uploader.upload("sample.jpg", 
  notification_url = "https://mysite.example.com/my_notification_endpoint")

|nodejs
cloudinary.v2.uploader
.upload("sample.jpg", 
  { notification_url: "https://mysite.example.com/my_notification_endpoint" })
.then(result=>console.log(result)); 
  
|java
cloudinary.uploader().upload("sample.jpg", 
  ObjectUtils.asMap("notification_url", "https://mysite.example.com/my_notification_endpoint"));

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

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

|cli
cld uploader upload "sample.jpg" notification_url="https://mysite.example.com/my_notification_endpoint"
```  
