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

# User-generated content


User-generated content (UGC) has become a cornerstone of modern web experiences, driving engagement and fostering community among users. Whether it's images, videos, or text, UGC allows websites to dynamically grow and reflect the contributions of their audience. However, managing and optimizing this influx of diverse content can be challenging. 

This guide shows how Cloudinary can streamline your UGC workflows, deliver content at scale, and ensure high performance with a consistent user experience across all devices and platforms.

Functionality is grouped into [Upload](#upload) and [Manage & Analyze](#manage_and_analyze) on the upload side (moderation and analysis are invoked during upload), and [Transform & Customize](#transform_and_customize) and [Optimize & Deliver](#optimize_and_deliver) on the delivery side, with recommendations for their use across four [example use cases](#popular_applications_of_ugc).

   
    
  
    
  
    
  
    
  

## Popular applications of UGC

Many websites and apps use UGC, ranging from social media sites to marketplaces, to travel sites and e-commerce apps. 

Images and videos can be uploaded for profiles, photo/video feeds, customer reviews, product information, recommendations, personalization, and more. 

Watch a clip about popular applications of UGC from the [Cloudinary Academy UGC workshop](https://training.cloudinary.com/courses/using-cloudinarys-incoming-transformations-for-perfectly-crafted-user-generated-content-45-minute-workshop):

  This video is brought to you by Cloudinary's video player - embed your own!Use the controls to set the playback speed, navigate to chapters of interest and select subtitles in your preferred language.

> **TIP**: Head to the [Cloudinary Academy](https://training.cloudinary.com) to take the full workshop or browse others - free for all Cloudinary users!
This guide focuses on four example uses cases: 

* [Profile pictures](#profile_pictures): A user uploads their profile picture for their account on your site.
* [Video reviews](#video_reviews): A customer uploads a video of themselves using one of your products.
* [Marketplace products](#marketplace_products): A vendor uploads product images and videos to the marketplace platform.
* [Try before you buy](#try_before_you_buy): A potential customer uploads an image to visualize how your product will look in their environment, or applied to their personal items.

Some of the features presented in this guide are essential for all the use cases, but others are specific to certain use cases. Throughout the guide, you'll see which features are recommended for each of the use cases.

### Profile pictures

If your site lets users log in to personal accounts, it's common to let users personalize their accounts with a profile picture. The picture is likely to be visible to others and may need to be presented in different ways depending on the context. For example, a mini version of the picture against a user's comments, or a larger version on a user's profile page. 

Comments icon

Profile page 

> **TIP**: Take a look at the [profile picture sample project](profile_picture_sample_project) to explore the code and see it in action.

### Video reviews

Consumers trust customer reviews, and videos allow users to see how products look in real life. Therefore, allowing users to upload video reviews of products can lead to more sales and lower return rates. 

You can use Cloudinary to moderate uploaded videos to ensure they are appropriate, resize them to fit specific dimensions and play them with the Cloudinary Video Player.

> **TIP**: Take a look at the [video review sample project](video_review_sample_project) to explore the code and see it in action.

### Marketplace products

Vendors on a marketplace upload images and videos of products that they're selling. The marketplace may have guidelines on dimensions, content and style which Cloudinary can help to enforce, standardizing images and videos automatically, and at scale. For example, products may need to have consistent backgrounds, dimensions and rounded corners. 

Product 1

Product 2 

> **TIP**: Take a look at the [marketplace products sample project](marketplace_products_sample_project) to explore how MediaFlows can help to moderate incoming content.

### Try before you buy

Visualizing how a product looks in a customer's environment, or applied to something personal to the customer helps them to decide if the product is right for them. The customer uploads an image, but does not expect it to be stored indefinitely - it can be deleted after it has served its purpose. It's also not displayed to anyone else, so it's less critical to analyze the content to ensure it's appropriate.

Paint color 1 

Paint color 2

> **TIP**: Take a look at the [try before you buy sample project](try_before_you_buy_sample_project) to explore the code and see it in action.

## Upload

Upload is an essential feature of UGC - you have to provide your users a way to add their media to your site or app. In addition to simply storing the media in your product environment, there are many features that you can invoke while uploading, for example, [limiting the size](#transform_on_upload) of the uploads, [moderating the content](#moderate_automatically) that's uploaded, and [analyzing the media](#analyze_quality_and_accessibility) for management purposes.

> **NOTE**: Moderation and analysis are discussed under [Manage and analyze](#manage_and_analyze), although they can (and should) be invoked as part of the upload flow.

The following table shows recommended features (marked ✅) for the four different [example UGC cases](#popular_applications_of_ugc):

{table:class=no-borders overview textcenter}  | Profile pictures | Video reviews | Marketplace products | Try before you buy
---|---|---|---|---
[Upload](#ways_to_upload) | ✅  | ✅  | ✅  | ✅ 
[Define upload behavior](#define_upload_behavior) | ✅  | ✅  | ✅  | ✅ 
[Control access to uploaded media](#control_access_to_uploaded_media) | | ✅ | ✅ 
[Track uploads](#track_uploads) | |  ✅  | ✅ |
[Transform on upload](#transform_on_upload) | ✅  | ✅  | ✅  | ✅ 
[Prepare delivery transformations](#prepare_delivery_transformations_on_upload_cache_warm_up) | | ✅  | ✅ |

### Ways to upload

#### API and SDKs

There are many ways to allow users to upload their content to your site. Using the [Upload API](image_upload_api_reference), either directly, or via an [SDK](cloudinary_sdks), you can tailor how images and videos are uploaded, analyzed and managed to suit your needs.

The following code shows how to:

* Upload a local image called **shirt.jpg**
* Request [color and quality analysis](semantic_data_extraction)
* Run the [Google Auto Tagging](google_auto_tagging_addon#adding_resource_tags_to_images) add-on 
* Automatically add the detected categories as tags to the asset

```multi
|ruby 
Cloudinary::Uploader.upload("shirt.jpg",  
  quality_analysis: true,
  colors: true,
  categorization: "google_tagging",
  auto_tagging: 0.7)

|php_2
use Cloudinary\Api\Upload\UploadApi;

(new UploadApi())->upload('shirt.jpg', [
  'quality_analysis' => true,  
  'colors' => true, 
  'categorization' => 'google_tagging', 
  'auto_tagging' => 0.7]);
    
  
|python
cloudinary.uploader.upload("shirt.jpg", 
  quality_analysis = True, 
  colors = True,  
  categorization = "google_tagging",
  auto_tagging = 0.7)

|nodejs
cloudinary.v2.uploader
.upload("shirt.jpg", { 
  quality_analysis: true, 
  colors: true, 
  categorization: "google_tagging",
  auto_tagging: 0.7})
.then(result=>console.log(result));
  
|java
Map params = ObjectUtils.asMap(
    "quality_analysis", true,
    "colors", true,
    "categorization", "google_tagging", 
    "auto_tagging", 0.7);
Map uploadResult = cloudinary.uploader().upload(new File("shirt.jpg"), params);

|csharp
var uploadParams = new ImageUploadParams()
    {
        File = new FileDescription(@"shirt.jpg"), 
        QualityAnalysis = true,
        Colors = true,        
        Categorization = "google_tagging",
        AutoTagging = 0.7};
var uploadResult = cloudinary.Upload(uploadParams);

|android
MediaManager.get().upload("shirt.jpg")
   .unsigned("preset1")
   .option("quality_analysis", "true")
   .option("colors", "true")
   .option("categorization", "google_tagging")
   .option("auto_tagging", "0.7")
   .dispatch();

|swift
let params = CLDUploadRequestParams().setQualityAnalysis(true).setColors(true).setCategorization("google_tagging").setAutoTagging(0.7)
let request = cloudinary.createUploader().upload(data: fileUrl, uploadPreset: "preset1", params: params)

|curl
curl https://api.cloudinary.com/v1_1/demo/image/upload -X POST --data 'file=https://www.example.com/shirt.jpg&quality_analysis=true&colors=true&categorization="google_tagging"&auto_tagging=0.7&timestamp=173719931&api_key=436464676&signature=a788d68f86a6f868af'
```

#### Upload widget

For a complete, interactive user interface that enables users to upload files from a variety of sources, and includes options to crop on upload and limit file types, amongst others, consider implementing the Cloudinary [Upload widget](upload_widget). 

This example of the Upload widget restricts file types to images only and displays the uploaded image following a successful upload:

Try the Upload widget

  
                

Some of the [community-developed libraries](community_sdks) have a `CldUploadWidget` component that makes it easy to drop the widget into your app.

Watch a clip about the Upload widget from the [Cloudinary Academy UGC workshop](https://training.cloudinary.com/courses/using-cloudinarys-incoming-transformations-for-perfectly-crafted-user-generated-content-45-minute-workshop):

  This video is brought to you by Cloudinary's video player - embed your own!Use the controls to set the playback speed, navigate to chapters of interest and select subtitles in your preferred language.

> **TIP**: Head to the [Cloudinary Academy](https://training.cloudinary.com) to take the full workshop or browse others - free for all Cloudinary users!
#### Minisite

An easy way for non-developers to create a hosted, standalone site for the Upload widget to allow uploads to their product environment is to create a minisite - check out this [blog post](https://cloudinary.com/blog/no-code-uploads-to-cloudinary) to learn more.

#### Portals

If you're on an [Enterprise plan](https://cloudinary.com/pricing#pricing-enterprise), you can use the **external uploader** feature of [Portals](dam_admin_portals) to allow third-party stakeholders to upload assets directly to your product environment using the Upload Widget, embedded within the portal. 

You can configure the external uploader to:

* Automatically apply auto-tagging
* Assign an identifying tag to all assets uploaded via the portal

#### Media Library 

For trusted content providers, there's also the option to provide them with their own [Media Library user](dam_admin_users_groups#role_based_permissions) login to your product environment, where they can not only upload, but also search, view and download assets within the folders that they have permission to see.

### Define upload behavior

You can use [upload presets](upload_presets) to define a set of upload options that are applied every time a user uploads content to your site. For example, you can specify that all assets are [moderated](#moderate) on upload, or that certain [transformations are applied](#transform_on_upload).

Watch a clip about upload presets from the [Cloudinary Academy UGC workshop](https://training.cloudinary.com/courses/using-cloudinarys-incoming-transformations-for-perfectly-crafted-user-generated-content-45-minute-workshop):

  This video is brought to you by Cloudinary's video player - embed your own!Use the controls to set the playback speed, navigate to chapters of interest and select subtitles in your preferred language.

> **TIP**: Head to the [Cloudinary Academy](https://training.cloudinary.com) to take the full workshop or browse others - free for all Cloudinary users!
### Control access to uploaded media

By default, files uploaded to your product environment are publicly available via a URL. If you want to control who can access your assets and whether or not they can transform them, you should consider the different [media access methods](control_access_to_media).

### Track uploads

You can get notified when content is uploaded to your site via [webhook notifications](notifications). Use these notifications to trigger further steps in your workflow automatically, or prompt subsequent interaction.

### Transform on upload

You can apply transformations to images and videos as they're uploaded. These are called [incoming transformations](eager_and_incoming_transformations#incoming_transformations) and result in the transformed assets being stored, rather than the original assets. Incoming transformations are useful to limit the size of uploaded assets, and allow you to standardize a set of transformations for your use case. 

> **TIP**: You can also [transform](#transform_and_customize) images and videos on delivery (leaving the original intact), which allow users to make customizations on the fly, apply different transformations to the same assets, and make optimizations based on the user's device.

Watch a clip about incoming transformations from the [Cloudinary Academy UGC workshop](https://training.cloudinary.com/courses/using-cloudinarys-incoming-transformations-for-perfectly-crafted-user-generated-content-45-minute-workshop):

  This video is brought to you by Cloudinary's video player - embed your own!Use the controls to set the playback speed, navigate to chapters of interest and select subtitles in your preferred language.

> **TIP**: Head to the [Cloudinary Academy](https://training.cloudinary.com) to take the full workshop or browse others - free for all Cloudinary users!
#### Limit dimensions of images and videos

If you know that when displaying your users' images or videos they'll never exceed certain dimensions, then you can resize the media to a defined [limit](resizing_and_cropping#limit) on upload to save storage costs. 

#### Truncate long videos

To prevent users from uploading overly long videos, you can set a limit and [truncate](video_trimming_and_concatenating#trimming_videos) anything longer than that limit. 

#### Strip metadata

For privacy reasons, and also to reduce storage costs, it's advisable to [remove metadata](transformation_reference#fl_force_strip) (IPTC, EXIF and XMP) associated with images on upload.

### Prepare delivery transformations on upload (cache warm up)

It can sometimes take more than a couple of a seconds to transform an image or video on the fly for delivery, for example, when transforming long videos or using generative AI transformations. You can prepare derived (transformed) versions of an asset in advance of delivering them for the first time by using [eager transformations](eager_and_incoming_transformations#eager_transformations) to warm up the cache.

You can specify eager transformations in an [upload preset](#define_upload_behavior), or use the `eager` parameter in the `upload` call:

```multi
|ruby  
Cloudinary::Uploader.upload("sample.jpg",
  eager: [
    {width: 400, height: 300, crop: "pad"}, 
    {width: 260, height: 200, crop: "crop", gravity: "north"}])
 
|php_2
$cloudinary->uploadApi()->upload("sample.jpg", [ 
  "eager" => [
    ["width" => 400, "height" => 300, "crop" => "pad"],
    ["width" => 260, "height" => 200, "crop" => "crop", "gravity" => "north"]]]);

|python
cloudinary.uploader.upload("sample.jpg", 
  eager = [
    {"width": 400, "height": 300, "crop": "pad"},
    {"width": 260, "height": 200, "crop": "crop", "gravity": "north"}])

|nodejs
cloudinary.v2.uploader
.upload("sample.jpg", 
  { eager: [
    { width: 400, height: 300, crop: "pad" }, 
    { width: 260, height: 200, crop: "crop", gravity: "north"} ]})
.then(result=>console.log(result)); 
  
|java
cloudinary.uploader().upload("sample.jpg", 
  ObjectUtils.asMap(
    "eager", Arrays.asList(
      new EagerTransformation().width(400).height(300).crop("pad"),
      new EagerTransformation().width(260).height(200).crop("crop").gravity("north"))));

|csharp
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"sample.jpg"),
  EagerTransforms = new List<Transformation>(){
   new EagerTransformation().Width(400).Height(300).Crop("pad"),
   new EagerTransformation().Width(260).Height(200).Crop("crop").Gravity("north")}};
var uploadResult = cloudinary.Upload(uploadParams);

|go
resp, err := cld.Upload.Upload(ctx, "sample.jpg", uploader.UploadParams{
      Eager: "c_pad,h_300,w_400|c_crop,g_north,h_200,w_260"})

|android
MediaManager.get().upload("sample.jpg")
  .option("eager", Arrays.asList(
      new EagerTransformation().width(400).height(300).crop("pad"),
      new EagerTransformation().width(260).height(200).crop("crop").gravity("north"))).dispatch();

|swift
let params = CLDUploadRequestParams()
  .setEager([
    CLDTransformation().setWidth(400).setHeight(300).setCrop("pad"),
    CLDTransformation().setWidth(260).setHeight(200).setCrop("crop").setGravity("north")])
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: "sample.jpg", params: params)

|cli
cld uploader upload sample.jpg eager='w_400,h_300,c_pad|w_260,h_200,c_crop,g_north'

|curl
curl https://api.cloudinary.com/v1_1/demo/image/upload -X POST --data 'file=sample.jpg&eager=w_400,h_300,c_pad|w_260,h_200,c_crop,g_north&timestamp=173719931&api_key=436464676&signature=a788d68f86a6f868af'
```

## Manage and analyze

> **NOTE**: Most of the functionality described in this section can (and should) be invoked as part of the [upload](#upload) flow, however you can also manage and analyze your assets once they've already been uploaded.

The following table shows recommended features (marked ✅) for the four different [example UGC cases](#popular_applications_of_ugc):

{table:class=no-borders overview textcenter}  | Profile pictures | Video reviews | Marketplace products | Try before you buy
---|---|---|---|---
[Moderate](#moderate) | ✅  | ✅  | ✅  | 
[Detect malware](#detect_malware) | ✅  | ✅  | ✅  | ✅ 
[Analyze quality and accessibility](#analyze_quality_and_accessibility) | ✅ | | ✅ |
[Analyze content](#analyze_content) | | ✅ | ✅ |
[Transcribe and localize video subtitles](#transcribe_and_localize_video_subtitles) | | ✅ | ✅ | 
[Generate video chapters](#generate_video_chapters) | | ✅ | ✅ | 
[Add logic to uploads](#add_logic_to_uploads) | | | ✅ | 
[Set up a media workflow](#set_up_a_media_workflow) | | | ✅ | ✅ 

### Moderate

You need to ensure that the content that users are uploading is not harmful, offensive or inappropriate for your site. Depending on the volume of uploads, you could use manual and/or automatic moderation.

#### Moderate manually

If you request [manual moderation](moderate_assets#moderating_assets_manually) for all uploads, then someone needs to check all uploaded assets and manually decide if they're appropriate or not. 

#### Moderate automatically

If you have a large number of files being uploaded to your site, then you'll want to apply automatic moderation on upload. There are various AI-powered add-ons that you can use to block inappropriate or offensive images and videos: 
* The [Amazon Rekognition AI Moderation add-on](aws_rekognition_ai_moderation_addon) leverages Amazon Rekognition's AI to automatically identify and moderate potentially unsafe content in images, suitable for social media platforms and e-commerce websites. 

* The [Amazon Rekognition Video Moderation add-on](aws_rekognition_video_moderation_addon) specializes in video content moderation for video-sharing platforms, ensuring live-streamed and pre-recorded videos comply with guidelines. 

* The [Google AI Video Moderation add-on](google_ai_video_moderation_addon) employs Google's AI technology to assess and moderate user-generated videos, ideal for video-hosting services. 

* The [WebPurify Image Moderation add-on](webpurify_image_moderation_addon) automatically filters out inappropriate images in real-time across various platforms, from social media to e-commerce websites, ensuring adherence to content guidelines and legal standards.
You can still manually override the decisions made by the AI, if they're not 100% accurate.  

#### Brand-aligned moderation

Cloudinary is working together with design partners on a brand-aligned moderation solution. This solution will allow you to moderate images based on your customized brand guidelines.

For example, it will allow you to:

* Select widely accepted, common moderation presets
* Add custom moderation criteria using natural language
* Create multiple moderation policies for different use cases (for example, different policies for product images and campaign images)
* Automate the moderation of images at scale

[Reach out](https://support.cloudinary.com/hc/en-us/requests/new) if you want to learn more or are interested in becoming a design partner.

---

Watch a clip about moderation from the [Cloudinary Academy UGC workshop](https://training.cloudinary.com/courses/using-cloudinarys-incoming-transformations-for-perfectly-crafted-user-generated-content-45-minute-workshop):

  This video is brought to you by Cloudinary's video player - embed your own!Use the controls to set the playback speed, navigate to chapters of interest and select subtitles in your preferred language.

> **TIP**: Head to the [Cloudinary Academy](https://training.cloudinary.com) to take the full workshop or browse others - free for all Cloudinary users!
### Detect malware

It's important to ensure that your product environment remains malware-free, so when allowing users to upload files to your site, you'll want to scan them for threats. You can use the [Perception Point Malware Detection add-on](perception_point_malware_detection_addon) to do this.

### Analyze quality and accessibility

As you don't know what's being uploaded to your product environment, you may want to analyze the content for [quality](image_quality_analysis) and [accessibility](accessibility_analysis) and take steps to improve these aspects if necessary, for example, see [Improve image quality](#improve_image_quality). 

Watch a clip about analyzing quality from the [Cloudinary Academy UGC workshop](https://training.cloudinary.com/courses/using-cloudinarys-incoming-transformations-for-perfectly-crafted-user-generated-content-45-minute-workshop):

  This video is brought to you by Cloudinary's video player - embed your own!Use the controls to set the playback speed, navigate to chapters of interest and select subtitles in your preferred language.

> **TIP**: Head to the [Cloudinary Academy](https://training.cloudinary.com) to take the full workshop or browse others - free for all Cloudinary users!
### Analyze content

Content analysis add-ons that use AI to determine what's in an image or video can help you to organize assets uploaded by your users, make them easier to find, as well as check that what's being uploaded is expected. For example, if your site is for selling cars, you'd want to check that the image contains a car, or at least a car part.
There are various auto-tagging add-ons available that automatically add tags to your assets on or after upload to your product environment. Some of the add-ons have broad tagging capabilities, such as the [Amazon Rekognition](aws_rekognition_auto_tagging_addon), [Google Image](google_auto_tagging_addon), and [Imagga](imagga_auto_tagging_addon) auto-tagging add-ons for images, and the [Google Video](google_automatic_video_tagging_addon) and [Microsoft Azure Video Indexer](microsoft_azure_video_indexer_addon#video_categorization) auto-tagging add-ons for videos. You can use these add-ons in conjunction with the [Google Translation add-on](translation_addons) to translate your tags to different languages.

Others are more specific in terms of what they detect, for example you can use the [Amazon Rekognition Celebrity Detection add-on](aws_rekognition_celebrity_and_face_detection_addon) to detect celebrities, or the [Cloudinary AI Content Analysis add-on](cloudinary_ai_content_analysis_addon#automatic_image_tagging) to detect objects in a specific object model.

You can also try out the [Cloudinary AI Vision add-on](cloudinary_ai_vision_addon) to interpret and respond to visual content queries. This is particularly useful for determining if user-generated content is suitable for your site as you can be very specific in what you allow or reject based on components of the image.
Based on the content of the image, your workflow could also automatically set other [custom metadata](custom_metadata) on your assets.

Watch a clip about analyzing content from the [Cloudinary Academy UGC workshop](https://training.cloudinary.com/courses/using-cloudinarys-incoming-transformations-for-perfectly-crafted-user-generated-content-45-minute-workshop):

  This video is brought to you by Cloudinary's video player - embed your own!Use the controls to set the playback speed, navigate to chapters of interest and select subtitles in your preferred language.

> **TIP**: Head to the [Cloudinary Academy](https://training.cloudinary.com) to take the full workshop or browse others - free for all Cloudinary users!
### Transcribe and localize video subtitles

When a user uploads a video with speech, you can automatically [generate a transcript](video_transcription), which you can use for subtitles, captions or other purposes. 

A customer-provided video review may be valuable to other potential customers in different countries. Using Cloudinary's [auto transcription](video_transcription) feature together with the [Google Translate](translation_addons) add-on can substantially broaden the audience of these videos by providing subtitles in different languages.

Use the `auto_transcription` parameter when uploading the video, with the `translate` option set to the different languages. 

```multi
|nodejs
cloudinary.v2.uploader
.upload("my-video.mp4", 
  { resource_type: "video", 
    auto_transcription: {
      "translate": ["fr-FR", "es", "de"]
    }
  })
.then(result=>console.log(result));

|curl
curl https://api.cloudinary.com/v1_1/demo/video/upload -X POST -F 'file=@/path/to/my-video.mp4' -F 'auto_transcription={"translate": ["fr-FR", "es", "de"]}' -F 'timestamp=173719931' -F 'api_key=436464676' -F 'signature=a781d61f86a6f818af'
```

This automatically creates the transcript files, which the Video Player can display when you add `subtitles` and `captions` in the `textTracks` option of your [Cloudinary Video Player](cloudinary_video_player) configuration:

```js
{
    textTracks: {
      captions: {
        label: 'English (Original)',
        default: true,
      },
      options: {
        theme: 'videojs-default',
      },
      subtitles: [
      {
        label: 'French',
        language: 'fr-FR',
      },
      {
        label: 'Spanish',
        language: 'es',
      },
      {
        label: 'German',
        language: 'de',
      }
    ]
  }
}
```

Here's an example of a video with subtitles. Click the **Captions** option at the bottom of the Video Player to see all the language options:

### Generate video chapters

Videos can be analyzed automatically on upload to determine where different sections (chapters) start and end. These [video chapter markers](video_player_customization#video_chapters) can be used by video players to allow users to jump to a different part of the video and understand what that section is about.

### Add logic to uploads

You can add logic to uploads performed by users in order to conditionally change something, for example add tags or metadata based on information returned about the uploaded asset. You can decide if your JavaScript code is evaluated [before](upload_parameters#eval_modify_upload_options_before_upload) or [after](upload_parameters#on_success_update_metadata_after_upload) the upload.

### Set up a media workflow

You can use [MediaFlows](mediaflows) to define actions to take after someone uploads media to your site. This is a standalone product, and uses a web-based drag-and-drop interface to simplify the creation of workflows. In addition to defining how the media behaves, you can also set up a flow to delete uploaded assets after a certain period of time, when they're no longer needed.

Watch a clip about MediaFlows from the [Cloudinary Academy UGC workshop](https://training.cloudinary.com/courses/using-cloudinarys-incoming-transformations-for-perfectly-crafted-user-generated-content-45-minute-workshop):

  This video is brought to you by Cloudinary's video player - embed your own!Use the controls to set the playback speed, navigate to chapters of interest and select subtitles in your preferred language.

> **TIP**: Head to the [Cloudinary Academy](https://training.cloudinary.com) to take the full workshop or browse others - free for all Cloudinary users!
## Transform and customize

There are [many transformations](transformation_reference) that you could make available to your users once they've uploaded their images or videos. Unlike [incoming transformations](#transform_on_upload), these transformations don't affect the stored asset, but create different versions for on-the-fly delivery.  

This section presents a few ideas that you may want to consider.

The following table shows recommended features (marked ✅) for the four different [example UGC cases](#popular_applications_of_ugc):

{table:class=no-borders overview textcenter}  | Profile pictures | Video reviews | Marketplace products | Try before you buy
---|---|---|---|---
[Improve image quality](#improve_image_quality) | ✅ | | ✅ | 
[Change the aspect ratio of an image](#change_the_aspect_ratio_of_an_image) | ✅ | | ✅ | ✅
[Change the aspect ratio of a video](#change_the_aspect_ratio_of_a_video) | | ✅ | ✅ |
[Standardize product images](#standardize_product_images) | | | ✅ |
[Conditionally apply transformations](#conditionally_apply_transformations) | | | ✅ |
[Apply a watermark](#apply_a_watermark) | | | ✅ | 
[Recompose an image for personalization](#recompose_an_image_for_personalization) | | | ✅  | ✅
[Help customers try before they buy](#help_customers_try_before_they_buy) | | | ✅  | ✅

> **TIP**: For additional e-commerce focused examples, see [Visual differentiators](ecommerce_visual_differentiators) in the Retail and e-commerce guide.

### Improve image quality

To ensure that your users' images are displayed at their best, there are various transformations that you can apply to improve the way they look. Check out our [image enhancement options](effects_and_artistic_enhancements#image_enhancement_options), which you can combine to achieve the best results.

Here, the image on the right uses generative restore, upscale, enhance and improve:

  
  

![Enhanced wedding image](https://res.cloudinary.com/demo/image/upload/e_gen_restore/e_upscale/e_enhance/e_improve/c_scale,w_300/docs/small-wedding-couple "with_image:false")

```nodejs
cloudinary.image("docs/small-wedding-couple", {transformation: [
  {effect: "gen_restore"},
  {effect: "upscale"},
  {effect: "enhance"},
  {effect: "improve"},
  {width: 300, crop: "scale"}
  ]})
```

```react
new CloudinaryImage("docs/small-wedding-couple")
  .effect(generativeRestore())
  .effect(upscale())
  .effect(enhance())
  .adjust(improve())
  .resize(scale().width(300));
```

```vue
new CloudinaryImage("docs/small-wedding-couple")
  .effect(generativeRestore())
  .effect(upscale())
  .effect(enhance())
  .adjust(improve())
  .resize(scale().width(300));
```

```angular
new CloudinaryImage("docs/small-wedding-couple")
  .effect(generativeRestore())
  .effect(upscale())
  .effect(enhance())
  .adjust(improve())
  .resize(scale().width(300));
```

```js
new CloudinaryImage("docs/small-wedding-couple")
  .effect(generativeRestore())
  .effect(upscale())
  .effect(enhance())
  .adjust(improve())
  .resize(scale().width(300));
```

```python
CloudinaryImage("docs/small-wedding-couple").image(transformation=[
  {'effect': "gen_restore"},
  {'effect': "upscale"},
  {'effect': "enhance"},
  {'effect': "improve"},
  {'width': 300, 'crop': "scale"}
  ])
```

```php
(new ImageTag('docs/small-wedding-couple'))
	->effect(Effect::generativeRestore())
	->effect(Effect::upscale())
	->effect(Effect::enhance())
	->adjust(Adjust::improve())
	->resize(Resize::scale()->width(300));
```

```java
cloudinary.url().transformation(new Transformation()
  .effect("gen_restore").chain()
  .effect("upscale").chain()
  .effect("enhance").chain()
  .effect("improve").chain()
  .width(300).crop("scale")).imageTag("docs/small-wedding-couple");
```

```ruby
cl_image_tag("docs/small-wedding-couple", transformation: [
  {effect: "gen_restore"},
  {effect: "upscale"},
  {effect: "enhance"},
  {effect: "improve"},
  {width: 300, crop: "scale"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Effect("gen_restore").Chain()
  .Effect("upscale").Chain()
  .Effect("enhance").Chain()
  .Effect("improve").Chain()
  .Width(300).Crop("scale")).BuildImageTag("docs/small-wedding-couple")
```

```dart
cloudinary.image('docs/small-wedding-couple').transformation(Transformation()
	.effect(Effect.generativeRestore())
	.effect(Effect.upscale())
	.effect(Effect.enhance())
	.adjust(Adjust.improve())
	.resize(Resize.scale().width(300)));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setEffect("gen_restore").chain()
  .setEffect("upscale").chain()
  .setEffect("enhance").chain()
  .setEffect("improve").chain()
  .setWidth(300).setCrop("scale")).generate("docs/small-wedding-couple")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .effect("gen_restore").chain()
  .effect("upscale").chain()
  .effect("enhance").chain()
  .effect("improve").chain()
  .width(300).crop("scale")).generate("docs/small-wedding-couple");
```

```flutter
cloudinary.image('docs/small-wedding-couple').transformation(Transformation()
	.effect(Effect.generativeRestore())
	.effect(Effect.upscale())
	.effect(Effect.enhance())
	.adjust(Adjust.improve())
	.resize(Resize.scale().width(300)));
```

```kotlin
cloudinary.image {
	publicId("docs/small-wedding-couple")
	 effect(Effect.generativeRestore())
	 effect(Effect.upscale())
	 effect(Effect.enhance())
	 adjust(Adjust.improve())
	 resize(Resize.scale() { width(300) }) 
}.generate()
```

```jquery
$.cloudinary.image("docs/small-wedding-couple", {transformation: [
  {effect: "gen_restore"},
  {effect: "upscale"},
  {effect: "enhance"},
  {effect: "improve"},
  {width: 300, crop: "scale"}
  ]})
```

```react_native
new CloudinaryImage("docs/small-wedding-couple")
  .effect(generativeRestore())
  .effect(upscale())
  .effect(enhance())
  .adjust(improve())
  .resize(scale().width(300));
```

> **TIP**: [Watch a video tutorial](enhance_and_restore_images_tutorial) that shows how to apply these transformations using JavaScript.

### Change the aspect ratio of an image

If you need to change the aspect ratio of an image to fit a certain display layout, you have the options of padding the image to fill the extra dimensions, or cropping out certain parts of the image.

If padding, you can choose a [background color](effects_and_artistic_enhancements#setting_background_color) for the padding, use an [automatically determined color](effects_and_artistic_enhancements#content_aware_padding), or you can choose to use [generative AI](generative_ai_transformations#generative_fill) to fill the extra dimensions with realistic pixels. 

b_black 

b_auto

b_gen_fill

![Generative fill background](https://res.cloudinary.com/demo/image/upload/ar_1.0,b_gen_fill,c_pad,w_200/docs/bench-house.jpg "with_image:false")

```nodejs
cloudinary.image("docs/bench-house.jpg", {aspect_ratio: "1.0", background: "gen_fill", width: 200, crop: "pad"})
```

```react
new CloudinaryImage("docs/bench-house.jpg").resize(
  pad()
    .width(200)
    .aspectRatio("1.0")
    .background(generativeFill())
);
```

```vue
new CloudinaryImage("docs/bench-house.jpg").resize(
  pad()
    .width(200)
    .aspectRatio("1.0")
    .background(generativeFill())
);
```

```angular
new CloudinaryImage("docs/bench-house.jpg").resize(
  pad()
    .width(200)
    .aspectRatio("1.0")
    .background(generativeFill())
);
```

```js
new CloudinaryImage("docs/bench-house.jpg").resize(
  pad()
    .width(200)
    .aspectRatio("1.0")
    .background(generativeFill())
);
```

```python
CloudinaryImage("docs/bench-house.jpg").image(aspect_ratio="1.0", background="gen_fill", width=200, crop="pad")
```

```php
(new ImageTag('docs/bench-house.jpg'))
	->resize(Resize::pad()->width(200)
->aspectRatio(1.0)
	->background(
	Background::generativeFill())
	);
```

```java
cloudinary.url().transformation(new Transformation().aspectRatio("1.0").background("gen_fill").width(200).crop("pad")).imageTag("docs/bench-house.jpg");
```

```ruby
cl_image_tag("docs/bench-house.jpg", aspect_ratio: "1.0", background: "gen_fill", width: 200, crop: "pad")
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation().AspectRatio("1.0").Background("gen_fill").Width(200).Crop("pad")).BuildImageTag("docs/bench-house.jpg")
```

```dart
cloudinary.image('docs/bench-house.jpg').transformation(Transformation()
	.resize(Resize.pad().width(200)
.aspectRatio('1.0')
	.background(
	Background.generativeFill())
	));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setAspectRatio("1.0").setBackground("gen_fill").setWidth(200).setCrop("pad")).generate("docs/bench-house.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation().aspectRatio("1.0").background("gen_fill").width(200).crop("pad")).generate("docs/bench-house.jpg");
```

```flutter
cloudinary.image('docs/bench-house.jpg').transformation(Transformation()
	.resize(Resize.pad().width(200)
.aspectRatio('1.0')
	.background(
	Background.generativeFill())
	));
```

```kotlin
cloudinary.image {
	publicId("docs/bench-house.jpg")
	 resize(Resize.pad() { width(200)
 aspectRatio(1.0F)
	 background(
	Background.generativeFill())
	 }) 
}.generate()
```

```jquery
$.cloudinary.image("docs/bench-house.jpg", {aspect_ratio: "1.0", background: "gen_fill", width: 200, crop: "pad"})
```

```react_native
new CloudinaryImage("docs/bench-house.jpg").resize(
  pad()
    .width(200)
    .aspectRatio("1.0")
    .background(generativeFill())
);
```

If cropping, you'll want to make sure you keep the most important part of the image in the crop, which may not necessarily be in the center. You can use [automatic cropping](resizing_and_cropping#c_auto) with [automatic gravity](resizing_and_cropping#automatic_cropping_g_auto) to achieve this.

Uploaded image 

Automatic Crop

![Automatically cropped mountain scene](https://res.cloudinary.com/demo/image/upload/ar_1.0,c_auto,g_auto,w_200/mountain_scene.jpg "with_image:false")

```nodejs
cloudinary.image("mountain_scene.jpg", {aspect_ratio: "1.0", gravity: "auto", width: 200, crop: "auto"})
```

```react
new CloudinaryImage("mountain_scene.jpg").resize(
  auto()
    .width(200)
    .aspectRatio("1.0")
    .gravity(autoGravity())
);
```

```vue
new CloudinaryImage("mountain_scene.jpg").resize(
  auto()
    .width(200)
    .aspectRatio("1.0")
    .gravity(autoGravity())
);
```

```angular
new CloudinaryImage("mountain_scene.jpg").resize(
  auto()
    .width(200)
    .aspectRatio("1.0")
    .gravity(autoGravity())
);
```

```js
new CloudinaryImage("mountain_scene.jpg").resize(
  auto()
    .width(200)
    .aspectRatio("1.0")
    .gravity(autoGravity())
);
```

```python
CloudinaryImage("mountain_scene.jpg").image(aspect_ratio="1.0", gravity="auto", width=200, crop="auto")
```

```php
(new ImageTag('mountain_scene.jpg'))
	->resize(Resize::auto()->width(200)
->aspectRatio(1.0)
	->gravity(
	Gravity::autoGravity())
	);
```

```java
cloudinary.url().transformation(new Transformation().aspectRatio("1.0").gravity("auto").width(200).crop("auto")).imageTag("mountain_scene.jpg");
```

```ruby
cl_image_tag("mountain_scene.jpg", aspect_ratio: "1.0", gravity: "auto", width: 200, crop: "auto")
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation().AspectRatio("1.0").Gravity("auto").Width(200).Crop("auto")).BuildImageTag("mountain_scene.jpg")
```

```dart
cloudinary.image('mountain_scene.jpg').transformation(Transformation()
	.resize(Resize.auto().width(200)
.aspectRatio('1.0')
	.gravity(
	Gravity.autoGravity())
	));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setAspectRatio("1.0").setGravity("auto").setWidth(200).setCrop("auto")).generate("mountain_scene.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation().aspectRatio("1.0").gravity("auto").width(200).crop("auto")).generate("mountain_scene.jpg");
```

```flutter
cloudinary.image('mountain_scene.jpg').transformation(Transformation()
	.resize(Resize.auto().width(200)
.aspectRatio('1.0')
	.gravity(
	Gravity.autoGravity())
	));
```

```kotlin
cloudinary.image {
	publicId("mountain_scene.jpg")
	 resize(Resize.auto() { width(200)
 aspectRatio(1.0F)
	 gravity(
	Gravity.autoGravity())
	 }) 
}.generate()
```

```jquery
$.cloudinary.image("mountain_scene.jpg", {aspect_ratio: "1.0", gravity: "auto", width: 200, crop: "auto"})
```

```react_native
new CloudinaryImage("mountain_scene.jpg").resize(
  auto()
    .width(200)
    .aspectRatio("1.0")
    .gravity(autoGravity())
);
```

### Change the aspect ratio of a video

Similar to changing the aspect ratio of an image, you can resize a video to fit specific dimensions either by padding the video to fill the extra dimensions, or by cropping out certain parts of the video.

If padding, you can choose a [background color](video_effects_and_enhancements#background_color) for the padding, or [blur the video](video_resizing_and_cropping#example_3_pad_with_blurred_video_background) for the padding.

  
    
    
    
  
Pad with a pink background<code>b_pink,c_pad

  
    
    
    
  
Pad with blurred background<code>c_pad,b_blurred:400:15

![Blurred background](https://res.cloudinary.com/demo/video/upload/b_blurred:400:15,c_pad,h_300,w_300/q_auto/docs/g_auto_demo.mp4 "with_image:false")

```nodejs
cloudinary.video("docs/g_auto_demo", {transformation: [
  {background: "blurred:400:15", height: 300, width: 300, crop: "pad"},
  {quality: "auto"}
  ]})
```

```react
new CloudinaryVideo("docs/g_auto_demo.mp4")
  .resize(
    pad()
      .width(300)
      .height(300)
      .background(blurred().intensity(400).brightness(15))
  )
  .delivery(quality(auto()));
```

```vue
new CloudinaryVideo("docs/g_auto_demo.mp4")
  .resize(
    pad()
      .width(300)
      .height(300)
      .background(blurred().intensity(400).brightness(15))
  )
  .delivery(quality(auto()));
```

```angular
new CloudinaryVideo("docs/g_auto_demo.mp4")
  .resize(
    pad()
      .width(300)
      .height(300)
      .background(blurred().intensity(400).brightness(15))
  )
  .delivery(quality(auto()));
```

```js
new CloudinaryVideo("docs/g_auto_demo.mp4")
  .resize(
    pad()
      .width(300)
      .height(300)
      .background(blurred().intensity(400).brightness(15))
  )
  .delivery(quality(auto()));
```

```python
CloudinaryVideo("docs/g_auto_demo").video(transformation=[
  {'background': "blurred:400:15", 'height': 300, 'width': 300, 'crop': "pad"},
  {'quality': "auto"}
  ])
```

```php
(new VideoTag('docs/g_auto_demo.mp4'))
	->resize(Resize::pad()->width(300)
->height(300)
	->background(
	Background::blurred()->intensity(400)
->brightness(15))
	)
	->delivery(Delivery::quality(
	Quality::auto()));
```

```java
cloudinary.url().transformation(new Transformation()
  .background("blurred:400:15").height(300).width(300).crop("pad").chain()
  .quality("auto")).videoTag("docs/g_auto_demo");
```

```ruby
cl_video_tag("docs/g_auto_demo", transformation: [
  {background: "blurred:400:15", height: 300, width: 300, crop: "pad"},
  {quality: "auto"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Background("blurred:400:15").Height(300).Width(300).Crop("pad").Chain()
  .Quality("auto")).BuildVideoTag("docs/g_auto_demo")
```

```dart
cloudinary.video('docs/g_auto_demo.mp4').transformation(Transformation()
	.resize(Resize.pad().width(300)
.height(300)
	.background(
	Background.blurred().intensity(400)
.brightness(15))
	)
	.delivery(Delivery.quality(
	Quality.auto())));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setBackground("blurred:400:15").setHeight(300).setWidth(300).setCrop("pad").chain()
  .setQuality("auto")).generate("docs/g_auto_demo.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .background("blurred:400:15").height(300).width(300).crop("pad").chain()
  .quality("auto")).resourceType("video").generate("docs/g_auto_demo.mp4");
```

```flutter
cloudinary.video('docs/g_auto_demo.mp4').transformation(Transformation()
	.resize(Resize.pad().width(300)
.height(300)
	.background(
	Background.blurred().intensity(400)
.brightness(15))
	)
	.delivery(Delivery.quality(
	Quality.auto())));
```

```kotlin
cloudinary.video {
	publicId("docs/g_auto_demo.mp4")
	 resize(Resize.pad() { width(300)
 height(300)
	 background(
	Background.blurred() { intensity(400)
 brightness(15) })
	 })
	 delivery(Delivery.quality(
	Quality.auto())) 
}.generate()
```

```jquery
$.cloudinary.video("docs/g_auto_demo", {transformation: [
  {background: "blurred:400:15", height: 300, width: 300, crop: "pad"},
  {quality: "auto"}
  ]})
```

```react_native
new CloudinaryVideo("docs/g_auto_demo.mp4")
  .resize(
    pad()
      .width(300)
      .height(300)
      .background(blurred().intensity(400).brightness(15))
  )
  .delivery(quality(auto()));
```

If cropping, you'll want to make sure you keep the most important part of the video in the crop, which may not necessarily be in the center. You can use [fill cropping](video_resizing_and_cropping#fill) with [automatic gravity](video_resizing_and_cropping#automatic_gravity_for_crops_g_auto) to achieve this.

  
    
    
    
  
Uploaded video

  
    
    
    
  
Crop with automatic gravity

![Crop with automatic gravity](https://res.cloudinary.com/demo/video/upload/ar_1.0,c_fill,g_auto,h_200/q_auto/docs/walking_talking.mp4 "with_image:false")

```nodejs
cloudinary.video("docs/walking_talking", {transformation: [
  {aspect_ratio: "1.0", gravity: "auto", height: 200, crop: "fill"},
  {quality: "auto"}
  ]})
```

```react
new CloudinaryVideo("docs/walking_talking.mp4")
  .resize(
    fill()
      .height(200)
      .aspectRatio("1.0")
      .gravity(autoGravity())
  )
  .delivery(quality(auto()));
```

```vue
new CloudinaryVideo("docs/walking_talking.mp4")
  .resize(
    fill()
      .height(200)
      .aspectRatio("1.0")
      .gravity(autoGravity())
  )
  .delivery(quality(auto()));
```

```angular
new CloudinaryVideo("docs/walking_talking.mp4")
  .resize(
    fill()
      .height(200)
      .aspectRatio("1.0")
      .gravity(autoGravity())
  )
  .delivery(quality(auto()));
```

```js
new CloudinaryVideo("docs/walking_talking.mp4")
  .resize(
    fill()
      .height(200)
      .aspectRatio("1.0")
      .gravity(autoGravity())
  )
  .delivery(quality(auto()));
```

```python
CloudinaryVideo("docs/walking_talking").video(transformation=[
  {'aspect_ratio': "1.0", 'gravity': "auto", 'height': 200, 'crop': "fill"},
  {'quality': "auto"}
  ])
```

```php
(new VideoTag('docs/walking_talking.mp4'))
	->resize(Resize::fill()->height(200)
->aspectRatio(1.0)
	->gravity(
	Gravity::autoGravity())
	)
	->delivery(Delivery::quality(
	Quality::auto()));
```

```java
cloudinary.url().transformation(new Transformation()
  .aspectRatio("1.0").gravity("auto").height(200).crop("fill").chain()
  .quality("auto")).videoTag("docs/walking_talking");
```

```ruby
cl_video_tag("docs/walking_talking", transformation: [
  {aspect_ratio: "1.0", gravity: "auto", height: 200, crop: "fill"},
  {quality: "auto"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .AspectRatio("1.0").Gravity("auto").Height(200).Crop("fill").Chain()
  .Quality("auto")).BuildVideoTag("docs/walking_talking")
```

```dart
cloudinary.video('docs/walking_talking.mp4').transformation(Transformation()
	.resize(Resize.fill().height(200)
.aspectRatio('1.0')
	.gravity(
	Gravity.autoGravity())
	)
	.delivery(Delivery.quality(
	Quality.auto())));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setAspectRatio("1.0").setGravity("auto").setHeight(200).setCrop("fill").chain()
  .setQuality("auto")).generate("docs/walking_talking.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .aspectRatio("1.0").gravity("auto").height(200).crop("fill").chain()
  .quality("auto")).resourceType("video").generate("docs/walking_talking.mp4");
```

```flutter
cloudinary.video('docs/walking_talking.mp4').transformation(Transformation()
	.resize(Resize.fill().height(200)
.aspectRatio('1.0')
	.gravity(
	Gravity.autoGravity())
	)
	.delivery(Delivery.quality(
	Quality.auto())));
```

```kotlin
cloudinary.video {
	publicId("docs/walking_talking.mp4")
	 resize(Resize.fill() { height(200)
 aspectRatio(1.0F)
	 gravity(
	Gravity.autoGravity())
	 })
	 delivery(Delivery.quality(
	Quality.auto())) 
}.generate()
```

```jquery
$.cloudinary.video("docs/walking_talking", {transformation: [
  {aspect_ratio: "1.0", gravity: "auto", height: 200, crop: "fill"},
  {quality: "auto"}
  ]})
```

```react_native
new CloudinaryVideo("docs/walking_talking.mp4")
  .resize(
    fill()
      .height(200)
      .aspectRatio("1.0")
      .gravity(autoGravity())
  )
  .delivery(quality(auto()));
```

### Standardize product images

If your website is a marketplace that allows businesses to sell their products, you can help them to standardize their product images, supporting branding, and saving them valuable time ensuring that images meet specific requirements of the platform. 

For example, [remove backgrounds](background_removal), apply the same background color, center objects, and round corners. 

Uploaded image 

Standardized product image

![Standardized product image](https://res.cloudinary.com/demo/image/upload/e_background_removal/e_trim/b_lightgray,c_lpad,w_1.1/r_20/docs/cupcake.png "with_image:false")

```nodejs
cloudinary.image("docs/cupcake.png", {transformation: [
  {effect: "background_removal"},
  {effect: "trim"},
  {background: "lightgray", width: "1.1", crop: "lpad"},
  {radius: 20}
  ]})
```

```react
new CloudinaryImage("docs/cupcake.png")
  .effect(backgroundRemoval())
  .reshape(trim())
  .resize(
    limitPad()
      .width(1.1)
      .background(color("lightgray"))
  )
  .roundCorners(byRadius(20));
```

```vue
new CloudinaryImage("docs/cupcake.png")
  .effect(backgroundRemoval())
  .reshape(trim())
  .resize(
    limitPad()
      .width(1.1)
      .background(color("lightgray"))
  )
  .roundCorners(byRadius(20));
```

```angular
new CloudinaryImage("docs/cupcake.png")
  .effect(backgroundRemoval())
  .reshape(trim())
  .resize(
    limitPad()
      .width(1.1)
      .background(color("lightgray"))
  )
  .roundCorners(byRadius(20));
```

```js
new CloudinaryImage("docs/cupcake.png")
  .effect(backgroundRemoval())
  .reshape(trim())
  .resize(
    limitPad()
      .width(1.1)
      .background(color("lightgray"))
  )
  .roundCorners(byRadius(20));
```

```python
CloudinaryImage("docs/cupcake.png").image(transformation=[
  {'effect': "background_removal"},
  {'effect': "trim"},
  {'background': "lightgray", 'width': "1.1", 'crop': "lpad"},
  {'radius': 20}
  ])
```

```php
(new ImageTag('docs/cupcake.png'))
	->effect(Effect::backgroundRemoval())
	->reshape(Reshape::trim())
	->resize(Resize::limitPad()->width(1.1)
	->background(
	Background::color(Color::LIGHTGRAY))
	)
	->roundCorners(RoundCorners::byRadius(20));
```

```java
cloudinary.url().transformation(new Transformation()
  .effect("background_removal").chain()
  .effect("trim").chain()
  .background("lightgray").width(1.1).crop("lpad").chain()
  .radius(20)).imageTag("docs/cupcake.png");
```

```ruby
cl_image_tag("docs/cupcake.png", transformation: [
  {effect: "background_removal"},
  {effect: "trim"},
  {background: "lightgray", width: 1.1, crop: "lpad"},
  {radius: 20}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Effect("background_removal").Chain()
  .Effect("trim").Chain()
  .Background("lightgray").Width(1.1).Crop("lpad").Chain()
  .Radius(20)).BuildImageTag("docs/cupcake.png")
```

```dart
cloudinary.image('docs/cupcake.png').transformation(Transformation()
	.effect(Effect.backgroundRemoval())
	.reshape(Reshape.trim())
	.resize(Resize.limitPad().width(1.1)
	.background(
	Background.color(Color.LIGHTGRAY))
	)
	.roundCorners(RoundCorners.byRadius(20)));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setEffect("background_removal").chain()
  .setEffect("trim").chain()
  .setBackground("lightgray").setWidth(1.1).setCrop("lpad").chain()
  .setRadius(20)).generate("docs/cupcake.png")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .effect("background_removal").chain()
  .effect("trim").chain()
  .background("lightgray").width(1.1).crop("lpad").chain()
  .radius(20)).generate("docs/cupcake.png");
```

```flutter
cloudinary.image('docs/cupcake.png').transformation(Transformation()
	.addTransformation("e_background_removal/e_trim/b_lightgray,c_lpad,w_1.1/r_20"));
```

```kotlin
cloudinary.image {
	publicId("docs/cupcake.png")
	 effect(Effect.backgroundRemoval())
	 reshape(Reshape.trim())
	 resize(Resize.limitPad() { width(1.1F)
	 background(
	Background.color(Color.LIGHTGRAY))
	 })
	 roundCorners(RoundCorners.byRadius(20)) 
}.generate()
```

```jquery
$.cloudinary.image("docs/cupcake.png", {transformation: [
  {effect: "background_removal"},
  {effect: "trim"},
  {background: "lightgray", width: "1.1", crop: "lpad"},
  {radius: 20}
  ]})
```

```react_native
new CloudinaryImage("docs/cupcake.png")
  .effect(backgroundRemoval())
  .reshape(trim())
  .resize(
    limitPad()
      .width(1.1)
      .background(color("lightgray"))
  )
  .roundCorners(byRadius(20));
```

### Conditionally apply transformations

You can apply [conditional transformations](video_conditional_expressions) to selectively transform certain images or videos. This is great for UGC use cases where you don't know what your users are uploading. You can test attributes of the media, or look at tags that may have been applied on upload.

For example, if the uploaded video has a portrait aspect ratio, then apply blurred padding when delivering it, otherwise fill the display area with the video:

  
    
    
    
  
Portrait video

  
    
    
    
  
Landscape video

![Conditional transformation](https://res.cloudinary.com/demo/video/upload/c_scale,h_200/if_ar_lt_1.0/b_blurred,c_pad,h_200,w_300/if_else/c_fill,h_200,w_300/if_end/docs/woman-camera-landscape.mp4 "with_image:false")

```nodejs
cloudinary.video("docs/woman-camera-landscape", {transformation: [
  {height: 200, crop: "scale"},
  {if: "ar_lt_1.0"},
  {background: "blurred", height: 200, width: 300, crop: "pad"},
  {if: "else"},
  {height: 200, width: 300, crop: "fill"},
  {if: "end"}
  ]})
```

```react
new CloudinaryVideo("docs/woman-camera-landscape.mp4")
  .resize(scale().height(200))
  .conditional(
    ifCondition(
      "aspect_ratio < 1.0",
      new Transformation().resize(
        pad().width(300).height(200).background(blurred())
      )
    ).otherwise(new Transformation().resize(fill().width(300).height(200)))
  );
```

```vue
new CloudinaryVideo("docs/woman-camera-landscape.mp4")
  .resize(scale().height(200))
  .conditional(
    ifCondition(
      "aspect_ratio < 1.0",
      new Transformation().resize(
        pad().width(300).height(200).background(blurred())
      )
    ).otherwise(new Transformation().resize(fill().width(300).height(200)))
  );
```

```angular
new CloudinaryVideo("docs/woman-camera-landscape.mp4")
  .resize(scale().height(200))
  .conditional(
    ifCondition(
      "aspect_ratio < 1.0",
      new Transformation().resize(
        pad().width(300).height(200).background(blurred())
      )
    ).otherwise(new Transformation().resize(fill().width(300).height(200)))
  );
```

```js
new CloudinaryVideo("docs/woman-camera-landscape.mp4")
  .resize(scale().height(200))
  .conditional(
    ifCondition(
      "aspect_ratio < 1.0",
      new Transformation().resize(
        pad().width(300).height(200).background(blurred())
      )
    ).otherwise(new Transformation().resize(fill().width(300).height(200)))
  );
```

```python
CloudinaryVideo("docs/woman-camera-landscape").video(transformation=[
  {'height': 200, 'crop': "scale"},
  {'if': "ar_lt_1.0"},
  {'background': "blurred", 'height': 200, 'width': 300, 'crop': "pad"},
  {'if': "else"},
  {'height': 200, 'width': 300, 'crop': "fill"},
  {'if': "end"}
  ])
```

```php
(new VideoTag('docs/woman-camera-landscape.mp4'))
	->resize(Resize::scale()->height(200))
	->conditional(Conditional::ifCondition("aspect_ratio < 1.0",(new Transformation())
	->resize(Resize::pad()->width(300)
->height(200)
	->background(
	Background::blurred())
	))
	->otherwise((new Transformation())
	->resize(Resize::fill()->width(300)
->height(200)))
	);
```

```java
cloudinary.url().transformation(new Transformation()
  .height(200).crop("scale").chain()
  .if("ar_lt_1.0").chain()
  .background("blurred").height(200).width(300).crop("pad").chain()
  .if("else").chain()
  .height(200).width(300).crop("fill").chain()
  .if("end")).videoTag("docs/woman-camera-landscape");
```

```ruby
cl_video_tag("docs/woman-camera-landscape", transformation: [
  {height: 200, crop: "scale"},
  {if: "ar_lt_1.0"},
  {background: "blurred", height: 200, width: 300, crop: "pad"},
  {if: "else"},
  {height: 200, width: 300, crop: "fill"},
  {if: "end"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Height(200).Crop("scale").Chain()
  .If("ar_lt_1.0").Chain()
  .Background("blurred").Height(200).Width(300).Crop("pad").Chain()
  .If("else").Chain()
  .Height(200).Width(300).Crop("fill").Chain()
  .If("end")).BuildVideoTag("docs/woman-camera-landscape")
```

```dart
cloudinary.video('docs/woman-camera-landscape.mp4').transformation(Transformation()
	.addTransformation("c_scale,h_200/if_ar_lt_1.0/b_blurred,c_pad,h_200,w_300/if_else/c_fill,h_200,w_300/if_end"));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setHeight(200).setCrop("scale").chain()
  .setIf("ar_lt_1.0").chain()
  .setBackground("blurred").setHeight(200).setWidth(300).setCrop("pad").chain()
  .setIf("else").chain()
  .setHeight(200).setWidth(300).setCrop("fill").chain()
  .setIf("end")).generate("docs/woman-camera-landscape.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .height(200).crop("scale").chain()
  .if("ar_lt_1.0").chain()
  .background("blurred").height(200).width(300).crop("pad").chain()
  .if("else").chain()
  .height(200).width(300).crop("fill").chain()
  .if("end")).resourceType("video").generate("docs/woman-camera-landscape.mp4");
```

```flutter
cloudinary.video('docs/woman-camera-landscape.mp4').transformation(Transformation()
	.addTransformation("c_scale,h_200/if_ar_lt_1.0/b_blurred,c_pad,h_200,w_300/if_else/c_fill,h_200,w_300/if_end"));
```

```kotlin
cloudinary.video {
	publicId("docs/woman-camera-landscape.mp4")
	 addTransformation("c_scale,h_200/if_ar_lt_1.0/b_blurred,c_pad,h_200,w_300/if_else/c_fill,h_200,w_300/if_end") 
}.generate()
```

```jquery
$.cloudinary.video("docs/woman-camera-landscape", {transformation: [
  {height: 200, crop: "scale"},
  {if: "ar_lt_1.0"},
  {background: "blurred", height: 200, width: 300, crop: "pad"},
  {if: "else"},
  {height: 200, width: 300, crop: "fill"},
  {if: "end"}
  ]})
```

```react_native
new CloudinaryVideo("docs/woman-camera-landscape.mp4")
  .resize(scale().height(200))
  .conditional(
    ifCondition(
      "aspect_ratio < 1.0",
      new Transformation().resize(
        pad().width(300).height(200).background(blurred())
      )
    ).otherwise(new Transformation().resize(fill().width(300).height(200)))
  );
```

### Apply a watermark

You may want to add a [watermark](layers#watermarking) to images or videos uploaded to your site, either for branding purposes, or so that other people can't download and use the media for their own benefit. 

When watermarks are applied with [anti-removal](video_layers#smart_anti_removal), it makes them much harder to remove:

![Video with anti-removal overlay](https://res.cloudinary.com/demo/video/upload/c_scale,w_500/l_cloudinary_icon_blue/c_scale,w_150/o_50/e_anti_removal:60,fl_layer_apply,g_north_east/old_camera.mp4)

```nodejs
cloudinary.video("old_camera", {transformation: [
  {width: 500, crop: "scale"},
  {overlay: "cloudinary_icon_blue"},
  {width: 150, crop: "scale"},
  {opacity: 50},
  {effect: "anti_removal:60", flags: "layer_apply", gravity: "north_east"}
  ]})
```

```react
new CloudinaryVideo("old_camera.mp4").resize(scale().width(500)).overlay(
  source(
    image("cloudinary_icon_blue").transformation(
      new Transformation().resize(scale().width(150)).adjust(opacity(50))
    )
  )
    .position(new Position().gravity(compass("north_east")))
    .blendMode(antiRemoval(60))
);
```

```vue
new CloudinaryVideo("old_camera.mp4").resize(scale().width(500)).overlay(
  source(
    image("cloudinary_icon_blue").transformation(
      new Transformation().resize(scale().width(150)).adjust(opacity(50))
    )
  )
    .position(new Position().gravity(compass("north_east")))
    .blendMode(antiRemoval(60))
);
```

```angular
new CloudinaryVideo("old_camera.mp4").resize(scale().width(500)).overlay(
  source(
    image("cloudinary_icon_blue").transformation(
      new Transformation().resize(scale().width(150)).adjust(opacity(50))
    )
  )
    .position(new Position().gravity(compass("north_east")))
    .blendMode(antiRemoval(60))
);
```

```js
new CloudinaryVideo("old_camera.mp4").resize(scale().width(500)).overlay(
  source(
    image("cloudinary_icon_blue").transformation(
      new Transformation().resize(scale().width(150)).adjust(opacity(50))
    )
  )
    .position(new Position().gravity(compass("north_east")))
    .blendMode(antiRemoval(60))
);
```

```python
CloudinaryVideo("old_camera").video(transformation=[
  {'width': 500, 'crop': "scale"},
  {'overlay': "cloudinary_icon_blue"},
  {'width': 150, 'crop': "scale"},
  {'opacity': 50},
  {'effect': "anti_removal:60", 'flags': "layer_apply", 'gravity': "north_east"}
  ])
```

```php
(new VideoTag('old_camera.mp4'))
	->resize(Resize::scale()->width(500))
	->overlay(Overlay::source(
	Source::image("cloudinary_icon_blue")
	->transformation((new Transformation())
	->resize(Resize::scale()->width(150))
	->adjust(Adjust::opacity(50)))
	)
	->position((new Position())
	->gravity(
	Gravity::compass(
	Compass::northEast()))
	)
	->blendMode(
	BlendMode::antiRemoval(60))
	);
```

```java
cloudinary.url().transformation(new Transformation()
  .width(500).crop("scale").chain()
  .overlay(new Layer().publicId("cloudinary_icon_blue")).chain()
  .width(150).crop("scale").chain()
  .opacity(50).chain()
  .effect("anti_removal:60").flags("layer_apply").gravity("north_east")).videoTag("old_camera");
```

```ruby
cl_video_tag("old_camera", transformation: [
  {width: 500, crop: "scale"},
  {overlay: "cloudinary_icon_blue"},
  {width: 150, crop: "scale"},
  {opacity: 50},
  {effect: "anti_removal:60", flags: "layer_apply", gravity: "north_east"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Width(500).Crop("scale").Chain()
  .Overlay(new Layer().PublicId("cloudinary_icon_blue")).Chain()
  .Width(150).Crop("scale").Chain()
  .Opacity(50).Chain()
  .Effect("anti_removal:60").Flags("layer_apply").Gravity("north_east")).BuildVideoTag("old_camera")
```

```dart
cloudinary.video('old_camera.mp4').transformation(Transformation()
	.addTransformation("c_scale,w_500/l_cloudinary_icon_blue/c_scale,w_150/o_50/e_anti_removal:60,fl_layer_apply,g_north_east"));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setWidth(500).setCrop("scale").chain()
  .setOverlay("cloudinary_icon_blue").chain()
  .setWidth(150).setCrop("scale").chain()
  .setOpacity(50).chain()
  .setEffect("anti_removal:60").setFlags("layer_apply").setGravity("north_east")).generate("old_camera.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .width(500).crop("scale").chain()
  .overlay(new Layer().publicId("cloudinary_icon_blue")).chain()
  .width(150).crop("scale").chain()
  .opacity(50).chain()
  .effect("anti_removal:60").flags("layer_apply").gravity("north_east")).resourceType("video").generate("old_camera.mp4");
```

```flutter
cloudinary.video('old_camera.mp4').transformation(Transformation()
	.addTransformation("c_scale,w_500/l_cloudinary_icon_blue/c_scale,w_150/o_50/e_anti_removal:60,fl_layer_apply,g_north_east"));
```

```kotlin
cloudinary.video {
	publicId("old_camera.mp4")
	 resize(Resize.scale() { width(500) })
	 overlay(Overlay.source(
	Source.image("cloudinary_icon_blue") {
	 transformation(Transformation {
	 resize(Resize.scale() { width(150) })
	 adjust(Adjust.opacity(50)) })
	 }) {
	 position(Position() {
	 gravity(
	Gravity.compass(
	Compass.northEast()))
	 })
	 blendMode(
	BlendMode.antiRemoval(60))
	 }) 
}.generate()
```

```jquery
$.cloudinary.video("old_camera", {transformation: [
  {width: 500, crop: "scale"},
  {overlay: new cloudinary.Layer().publicId("cloudinary_icon_blue")},
  {width: 150, crop: "scale"},
  {opacity: 50},
  {effect: "anti_removal:60", flags: "layer_apply", gravity: "north_east"}
  ]})
```

```react_native
new CloudinaryVideo("old_camera.mp4").resize(scale().width(500)).overlay(
  source(
    image("cloudinary_icon_blue").transformation(
      new Transformation().resize(scale().width(150)).adjust(opacity(50))
    )
  )
    .position(new Position().gravity(compass("north_east")))
    .blendMode(antiRemoval(60))
);
```

> **TIP**: If you're concerned about who can access the assets uploaded to your product environment, there are various ways to [control access to your media](control_access_to_media).

### Recompose an image for personalization

Using the [extract](transformation_reference#e_extract) transformation, you can isolate parts of an image and recompose the image using layers. Using natural language prompts, you can make the transformation as generic as you need it to be so that it can be reused on lots of different images, assuming they have particular contents. 

For example, if a user uploads a photo of themselves with a pet, say, for personalizing a t-shirt, you can extract just their heads, and recompose the image so they're side by side, like this:

Uploaded image 

Recomposed image

![Recomposed image of an owner and their pet](https://res.cloudinary.com/demo/image/upload/e_extract:prompt_the%20head%20of%20the%20person/e_trim/%24pwidth_w/l_docs:owner_and_pet/e_extract:prompt_the%20head%20of%20the%20animal/e_trim/fl_layer_apply,x_%24pwidth_mul_-1/c_lpad,b_gray,w_1.3/e_vignette:50/docs/owner_and_pet.png "with_image:false")

```nodejs
cloudinary.image("docs/owner_and_pet.png", {transformation: [
  {effect: "extract:prompt_the head of the person"},
  {effect: "trim"},
  {variables: [["$pwidth", "w"]]},
  {overlay: "docs:owner_and_pet"},
  {effect: "extract:prompt_the head of the animal"},
  {effect: "trim"},
  {flags: "layer_apply", x: "$pwidth * -1"},
  {background: "gray", width: "1.3", crop: "lpad"},
  {effect: "vignette:50"}
  ]})
```

```react
new CloudinaryImage("docs/owner_and_pet.png")
  .effect(extract("the head of the person"))
  .reshape(trim())
  .addVariable(set("pwidth", expression("width")))
  .overlay(
    source(
      image("docs/owner_and_pet").transformation(
        new Transformation()
          .effect(extract("the head of the animal"))
          .reshape(trim())
      )
    ).position(new Position().offsetX(expression("$pwidth * -1")))
  )
  .resize(
    limitPad()
      .width(1.3)
      .background(color("gray"))
  )
  .effect(vignette().strength(50));
```

```vue
new CloudinaryImage("docs/owner_and_pet.png")
  .effect(extract("the head of the person"))
  .reshape(trim())
  .addVariable(set("pwidth", expression("width")))
  .overlay(
    source(
      image("docs/owner_and_pet").transformation(
        new Transformation()
          .effect(extract("the head of the animal"))
          .reshape(trim())
      )
    ).position(new Position().offsetX(expression("$pwidth * -1")))
  )
  .resize(
    limitPad()
      .width(1.3)
      .background(color("gray"))
  )
  .effect(vignette().strength(50));
```

```angular
new CloudinaryImage("docs/owner_and_pet.png")
  .effect(extract("the head of the person"))
  .reshape(trim())
  .addVariable(set("pwidth", expression("width")))
  .overlay(
    source(
      image("docs/owner_and_pet").transformation(
        new Transformation()
          .effect(extract("the head of the animal"))
          .reshape(trim())
      )
    ).position(new Position().offsetX(expression("$pwidth * -1")))
  )
  .resize(
    limitPad()
      .width(1.3)
      .background(color("gray"))
  )
  .effect(vignette().strength(50));
```

```js
new CloudinaryImage("docs/owner_and_pet.png")
  .effect(extract("the head of the person"))
  .reshape(trim())
  .addVariable(set("pwidth", expression("width")))
  .overlay(
    source(
      image("docs/owner_and_pet").transformation(
        new Transformation()
          .effect(extract("the head of the animal"))
          .reshape(trim())
      )
    ).position(new Position().offsetX(expression("$pwidth * -1")))
  )
  .resize(
    limitPad()
      .width(1.3)
      .background(color("gray"))
  )
  .effect(vignette().strength(50));
```

```python
CloudinaryImage("docs/owner_and_pet.png").image(transformation=[
  {'effect': "extract:prompt_the head of the person"},
  {'effect': "trim"},
  {'variables': [["$pwidth", "w"]]},
  {'overlay': "docs:owner_and_pet"},
  {'effect': "extract:prompt_the head of the animal"},
  {'effect': "trim"},
  {'flags': "layer_apply", 'x': "$pwidth * -1"},
  {'background': "gray", 'width': "1.3", 'crop': "lpad"},
  {'effect': "vignette:50"}
  ])
```

```php
(new ImageTag('docs/owner_and_pet.png'))
	->effect(Effect::extract("the head of the person"))
	->reshape(Reshape::trim())
	->addVariable(Variable::set("pwidth",
	Expression::expression("width")))
	->overlay(Overlay::source(
	Source::image("docs/owner_and_pet")
	->transformation((new Transformation())
	->effect(Effect::extract("the head of the animal"))
	->reshape(Reshape::trim()))
	)
	->position((new Position())
	->offsetX(
	Expression::expression("$pwidth * -1"))
	)
	)
	->resize(Resize::limitPad()->width(1.3)
	->background(
	Background::color(Color::GRAY))
	)
	->effect(Effect::vignette()->strength(50));
```

```java
cloudinary.url().transformation(new Transformation()
  .effect("extract:prompt_the head of the person").chain()
  .effect("trim").chain()
  .variables(variable("$pwidth","w")).chain()
  .overlay(new Layer().publicId("docs:owner_and_pet")).chain()
  .effect("extract:prompt_the head of the animal").chain()
  .effect("trim").chain()
  .flags("layer_apply").x("$pwidth * -1").chain()
  .background("gray").width(1.3).crop("lpad").chain()
  .effect("vignette:50")).imageTag("docs/owner_and_pet.png");
```

```ruby
cl_image_tag("docs/owner_and_pet.png", transformation: [
  {effect: "extract:prompt_the head of the person"},
  {effect: "trim"},
  {variables: [["$pwidth", "w"]]},
  {overlay: "docs:owner_and_pet"},
  {effect: "extract:prompt_the head of the animal"},
  {effect: "trim"},
  {flags: "layer_apply", x: "$pwidth * -1"},
  {background: "gray", width: 1.3, crop: "lpad"},
  {effect: "vignette:50"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Effect("extract:prompt_the head of the person").Chain()
  .Effect("trim").Chain()
  .Variables("$pwidth", w).Chain()
  .Overlay(new Layer().PublicId("docs:owner_and_pet")).Chain()
  .Effect("extract:prompt_the head of the animal").Chain()
  .Effect("trim").Chain()
  .Flags("layer_apply").X("$pwidth * -1").Chain()
  .Background("gray").Width(1.3).Crop("lpad").Chain()
  .Effect("vignette:50")).BuildImageTag("docs/owner_and_pet.png")
```

```dart
cloudinary.image('docs/owner_and_pet.png').transformation(Transformation()
	.effect(Effect.extract("the head of the person"))
	.reshape(Reshape.trim())
	.addVariable(Variable.set("pwidth",
	Expression.expression("width")))
	.overlay(Overlay.source(
	Source.image("docs/owner_and_pet")
	.transformation(new Transformation()
	.effect(Effect.extract("the head of the animal"))
	.reshape(Reshape.trim()))
	)
	.position(Position()
	.offsetX(
	Expression.expression("$pwidth * -1"))
	)
	)
	.resize(Resize.limitPad().width(1.3)
	.background(
	Background.color(Color.GRAY))
	)
	.effect(Effect.vignette().strength(50)));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setEffect("extract:prompt_the head of the person").chain()
  .setEffect("trim").chain()
  .chain()
  .setOverlay("docs:owner_and_pet").chain()
  .setEffect("extract:prompt_the head of the animal").chain()
  .setEffect("trim").chain()
  .setFlags("layer_apply").setX("$pwidth * -1").chain()
  .setBackground("gray").setWidth(1.3).setCrop("lpad").chain()
  .setEffect("vignette:50")).generate("docs/owner_and_pet.png")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .effect("extract:prompt_the head of the person").chain()
  .effect("trim").chain()
  .variables(variable("$pwidth","w")).chain()
  .overlay(new Layer().publicId("docs:owner_and_pet")).chain()
  .effect("extract:prompt_the head of the animal").chain()
  .effect("trim").chain()
  .flags("layer_apply").x("$pwidth * -1").chain()
  .background("gray").width(1.3).crop("lpad").chain()
  .effect("vignette:50")).generate("docs/owner_and_pet.png");
```

```flutter
cloudinary.image('docs/owner_and_pet.png').transformation(Transformation()
	.effect(Effect.extract("the head of the person"))
	.reshape(Reshape.trim())
	.addVariable(Variable.set("pwidth",
	Expression.expression("width")))
	.overlay(Overlay.source(
	Source.image("docs/owner_and_pet")
	.transformation(new Transformation()
	.effect(Effect.extract("the head of the animal"))
	.reshape(Reshape.trim()))
	)
	.position(Position()
	.offsetX(
	Expression.expression("$pwidth * -1"))
	)
	)
	.resize(Resize.limitPad().width(1.3)
	.background(
	Background.color(Color.GRAY))
	)
	.effect(Effect.vignette().strength(50)));
```

```kotlin
cloudinary.image {
	publicId("docs/owner_and_pet.png")
	 effect(Effect.extract("the head of the person"))
	 reshape(Reshape.trim())
	 addVariable(Variable.set("pwidth",
	Expression.expression("width")))
	 overlay(Overlay.source(
	Source.image("docs/owner_and_pet") {
	 transformation(Transformation {
	 effect(Effect.extract("the head of the animal"))
	 reshape(Reshape.trim()) })
	 }) {
	 position(Position() {
	 offsetX(
	Expression.expression("\$pwidth * -1"))
	 })
	 })
	 resize(Resize.limitPad() { width(1.3F)
	 background(
	Background.color(Color.GRAY))
	 })
	 effect(Effect.vignette() { strength(50) }) 
}.generate()
```

```jquery
$.cloudinary.image("docs/owner_and_pet.png", {transformation: [
  {effect: "extract:prompt_the head of the person"},
  {effect: "trim"},
  {variables: [["$pwidth", "w"]]},
  {overlay: new cloudinary.Layer().publicId("docs:owner_and_pet")},
  {effect: "extract:prompt_the head of the animal"},
  {effect: "trim"},
  {flags: "layer_apply", x: "$pwidth * -1"},
  {background: "gray", width: "1.3", crop: "lpad"},
  {effect: "vignette:50"}
  ]})
```

```react_native
new CloudinaryImage("docs/owner_and_pet.png")
  .effect(extract("the head of the person"))
  .reshape(trim())
  .addVariable(set("pwidth", expression("width")))
  .overlay(
    source(
      image("docs/owner_and_pet").transformation(
        new Transformation()
          .effect(extract("the head of the animal"))
          .reshape(trim())
      )
    ).position(new Position().offsetX(expression("$pwidth * -1")))
  )
  .resize(
    limitPad()
      .width(1.3)
      .background(color("gray"))
  )
  .effect(vignette().strength(50));
```

### Help customers try before they buy

A popular use case of UGC is to allow customers to visualize how your product will look in their environment, or applied to their personal items. 

For example, let a customer try a different color of paint on their walls using [generative recolor](generative_ai_transformations#generative_recolor):

Uploaded image 

Recolored walls

![Recolored walls](https://res.cloudinary.com/demo/image/upload/e_gen_recolor:prompt_wall;to-color_066a85;multiple_true/docs/diy-kitchen.jpg "with_image:false")

```nodejs
cloudinary.image("docs/diy-kitchen.jpg", {effect: "gen_recolor:prompt_wall;to-color_066a85;multiple_true"})
```

```react
new CloudinaryImage("docs/diy-kitchen.jpg").effect(
  generativeRecolor("wall", "#066a85").detectMultiple()
);
```

```vue
new CloudinaryImage("docs/diy-kitchen.jpg").effect(
  generativeRecolor("wall", "#066a85").detectMultiple()
);
```

```angular
new CloudinaryImage("docs/diy-kitchen.jpg").effect(
  generativeRecolor("wall", "#066a85").detectMultiple()
);
```

```js
new CloudinaryImage("docs/diy-kitchen.jpg").effect(
  generativeRecolor("wall", "#066a85").detectMultiple()
);
```

```python
CloudinaryImage("docs/diy-kitchen.jpg").image(effect="gen_recolor:prompt_wall;to-color_066a85;multiple_True")
```

```php
(new ImageTag('docs/diy-kitchen.jpg'))
	->effect(Effect::generativeRecolor("wall",Color::rgb("066a85"))->detectMultiple());
```

```java
cloudinary.url().transformation(new Transformation().effect("gen_recolor:prompt_wall;to-color_066a85;multiple_true")).imageTag("docs/diy-kitchen.jpg");
```

```ruby
cl_image_tag("docs/diy-kitchen.jpg", effect: "gen_recolor:prompt_wall;to-color_066a85;multiple_true")
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation().Effect("gen_recolor:prompt_wall;to-color_066a85;multiple_true")).BuildImageTag("docs/diy-kitchen.jpg")
```

```dart
cloudinary.image('docs/diy-kitchen.jpg').transformation(Transformation()
	.effect(Effect.generativeRecolor("wall",Color.rgb("066a85")).detectMultiple()));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setEffect("gen_recolor:prompt_wall;to-color_066a85;multiple_true")).generate("docs/diy-kitchen.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation().effect("gen_recolor:prompt_wall;to-color_066a85;multiple_true")).generate("docs/diy-kitchen.jpg");
```

```flutter
cloudinary.image('docs/diy-kitchen.jpg').transformation(Transformation()
	.effect(Effect.generativeRecolor("wall",Color.rgb("066a85")).detectMultiple()));
```

```kotlin
cloudinary.image {
	publicId("docs/diy-kitchen.jpg")
	 effect(Effect.generativeRecolor("wall",Color.rgb("066a85")) { detectMultiple() }) 
}.generate()
```

```jquery
$.cloudinary.image("docs/diy-kitchen.jpg", {effect: "gen_recolor:prompt_wall;to-color_066a85;multiple_true"})
```

```react_native
new CloudinaryImage("docs/diy-kitchen.jpg").effect(
  generativeRecolor("wall", "#066a85").detectMultiple()
);
```

Or, try out a particular frame on their painting. Here, the painting is [underlaid](layers#image_underlays) beneath the frame, and resized relative to the frame:

Frame for sale 

Uploaded painting

Framed painting for visualization

![Framed painting](https://res.cloudinary.com/demo/image/upload/u_docs:painting-woman-cat/c_scale,fl_relative,w_0.5/fl_layer_apply/e_trim/docs/picture-frame.png "with_image:false")

```nodejs
cloudinary.image("docs/picture-frame.png", {transformation: [
  {underlay: "docs:painting-woman-cat"},
  {flags: "relative", width: "0.5", crop: "scale"},
  {flags: "layer_apply"},
  {effect: "trim"}
  ]})
```

```react
new CloudinaryImage("docs/picture-frame.png")
  .underlay(
    source(
      image("docs/painting-woman-cat").transformation(
        new Transformation().resize(scale().width(0.5).relative())
      )
    )
  )
  .reshape(trim());
```

```vue
new CloudinaryImage("docs/picture-frame.png")
  .underlay(
    source(
      image("docs/painting-woman-cat").transformation(
        new Transformation().resize(scale().width(0.5).relative())
      )
    )
  )
  .reshape(trim());
```

```angular
new CloudinaryImage("docs/picture-frame.png")
  .underlay(
    source(
      image("docs/painting-woman-cat").transformation(
        new Transformation().resize(scale().width(0.5).relative())
      )
    )
  )
  .reshape(trim());
```

```js
new CloudinaryImage("docs/picture-frame.png")
  .underlay(
    source(
      image("docs/painting-woman-cat").transformation(
        new Transformation().resize(scale().width(0.5).relative())
      )
    )
  )
  .reshape(trim());
```

```python
CloudinaryImage("docs/picture-frame.png").image(transformation=[
  {'underlay': "docs:painting-woman-cat"},
  {'flags': "relative", 'width': "0.5", 'crop': "scale"},
  {'flags': "layer_apply"},
  {'effect': "trim"}
  ])
```

```php
(new ImageTag('docs/picture-frame.png'))
	->underlay(Underlay::source(
	Source::image("docs/painting-woman-cat")
	->transformation((new Transformation())
	->resize(Resize::scale()->width(0.5)
	->relative()
	))
	))
	->reshape(Reshape::trim());
```

```java
cloudinary.url().transformation(new Transformation()
  .underlay(new Layer().publicId("docs:painting-woman-cat")).chain()
  .flags("relative").width(0.5).crop("scale").chain()
  .flags("layer_apply").chain()
  .effect("trim")).imageTag("docs/picture-frame.png");
```

```ruby
cl_image_tag("docs/picture-frame.png", transformation: [
  {underlay: "docs:painting-woman-cat"},
  {flags: "relative", width: 0.5, crop: "scale"},
  {flags: "layer_apply"},
  {effect: "trim"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Underlay(new Layer().PublicId("docs:painting-woman-cat")).Chain()
  .Flags("relative").Width(0.5).Crop("scale").Chain()
  .Flags("layer_apply").Chain()
  .Effect("trim")).BuildImageTag("docs/picture-frame.png")
```

```dart
cloudinary.image('docs/picture-frame.png').transformation(Transformation()
	.underlay(Underlay.source(
	Source.image("docs/painting-woman-cat")
	.transformation(new Transformation()
	.resize(Resize.scale().width(0.5)
	.relative()
	))
	))
	.reshape(Reshape.trim()));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setUnderlay("docs:painting-woman-cat").chain()
  .setFlags("relative").setWidth(0.5).setCrop("scale").chain()
  .setFlags("layer_apply").chain()
  .setEffect("trim")).generate("docs/picture-frame.png")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .underlay(new Layer().publicId("docs:painting-woman-cat")).chain()
  .flags("relative").width(0.5).crop("scale").chain()
  .flags("layer_apply").chain()
  .effect("trim")).generate("docs/picture-frame.png");
```

```flutter
cloudinary.image('docs/picture-frame.png').transformation(Transformation()
	.underlay(Underlay.source(
	Source.image("docs/painting-woman-cat")
	.transformation(new Transformation()
	.resize(Resize.scale().width(0.5)
	.relative()
	))
	))
	.reshape(Reshape.trim()));
```

```kotlin
cloudinary.image {
	publicId("docs/picture-frame.png")
	 underlay(Underlay.source(
	Source.image("docs/painting-woman-cat") {
	 transformation(Transformation {
	 resize(Resize.scale() { width(0.5F)
	 relative()
	 }) })
	 }))
	 reshape(Reshape.trim()) 
}.generate()
```

```jquery
$.cloudinary.image("docs/picture-frame.png", {transformation: [
  {underlay: new cloudinary.Layer().publicId("docs:painting-woman-cat")},
  {flags: "relative", width: "0.5", crop: "scale"},
  {flags: "layer_apply"},
  {effect: "trim"}
  ]})
```

```react_native
new CloudinaryImage("docs/picture-frame.png")
  .underlay(
    source(
      image("docs/painting-woman-cat").transformation(
        new Transformation().resize(scale().width(0.5).relative())
      )
    )
  )
  .reshape(trim());
```

## Optimize and deliver

The following table shows recommended features (marked ✅) for the four different [example UGC cases](#popular_applications_of_ugc):

{table:class=no-borders overview textcenter}  | Profile pictures | Video reviews | Marketplace products | Try before you buy
---|---|---|---|---
[On-the-fly optimizations](#on_the_fly_optimizations) | ✅ | ✅  | ✅  | ✅ 
[Cloudinary Video Player](#cloudinary_video_player) | | ✅  | ✅  |  

### On-the-fly optimizations

User-generated content is no different to pre-defined content when it comes to optimizing delivery of assets to different devices. You'll want to make the image or video as light as possible for fast page-load times. You can do this by automatically detecting the best [format](media_optimization#format) to deliver the media, automatically compressing the media to maintain appropriate [quality](media_optimization#quality), and [resizing](media_optimization#resize) the media on the server side to its display dimensions on the client side.

Here's the profile picture, cropped to the right size for the display (`ar_3:4,c_fill,g_face,h_300`), delivered in the best format (`f_auto`) and optimal quality (`q_auto`):

![Optimized profile picture](https://res.cloudinary.com/demo/image/upload/ar_3:4,c_fill,g_face,h_300/f_auto/q_auto/docs/profile-pic.jpg)

```nodejs
cloudinary.image("docs/profile-pic.jpg", {transformation: [
  {aspect_ratio: "3:4", gravity: "face", height: 300, crop: "fill"},
  {quality: "auto"}
  ]})
```

```react
new CloudinaryImage("docs/profile-pic.jpg")
  .resize(
    fill()
      .height(300)
      .aspectRatio("3:4")
      .gravity(focusOn(face()))
  )
  .delivery(format(auto()))
  .delivery(quality(auto()));
```

```vue
new CloudinaryImage("docs/profile-pic.jpg")
  .resize(
    fill()
      .height(300)
      .aspectRatio("3:4")
      .gravity(focusOn(face()))
  )
  .delivery(format(auto()))
  .delivery(quality(auto()));
```

```angular
new CloudinaryImage("docs/profile-pic.jpg")
  .resize(
    fill()
      .height(300)
      .aspectRatio("3:4")
      .gravity(focusOn(face()))
  )
  .delivery(format(auto()))
  .delivery(quality(auto()));
```

```js
new CloudinaryImage("docs/profile-pic.jpg")
  .resize(
    fill()
      .height(300)
      .aspectRatio("3:4")
      .gravity(focusOn(face()))
  )
  .delivery(format(auto()))
  .delivery(quality(auto()));
```

```python
CloudinaryImage("docs/profile-pic.jpg").image(transformation=[
  {'aspect_ratio': "3:4", 'gravity': "face", 'height': 300, 'crop': "fill"},
  {'quality': "auto"}
  ])
```

```php
(new ImageTag('docs/profile-pic.jpg'))
	->resize(Resize::fill()->height(300)
->aspectRatio("3:4")
	->gravity(
	Gravity::focusOn(
	FocusOn::face()))
	)
	->delivery(Delivery::format(
	Format::auto()))
	->delivery(Delivery::quality(
	Quality::auto()));
```

```java
cloudinary.url().transformation(new Transformation()
  .aspectRatio("3:4").gravity("face").height(300).crop("fill").chain()
  .quality("auto")).imageTag("docs/profile-pic.jpg");
```

```ruby
cl_image_tag("docs/profile-pic.jpg", transformation: [
  {aspect_ratio: "3:4", gravity: "face", height: 300, crop: "fill"},
  {quality: "auto"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .AspectRatio("3:4").Gravity("face").Height(300).Crop("fill").Chain()
  .Quality("auto")).BuildImageTag("docs/profile-pic.jpg")
```

```dart
cloudinary.image('docs/profile-pic.jpg').transformation(Transformation()
	.resize(Resize.fill().height(300)
.aspectRatio("3:4")
	.gravity(
	Gravity.focusOn(
	FocusOn.face()))
	)
	.delivery(Delivery.format(
	Format.auto()))
	.delivery(Delivery.quality(
	Quality.auto())));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setAspectRatio("3:4").setGravity("face").setHeight(300).setCrop("fill").chain()
  .setQuality("auto")).generate("docs/profile-pic.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .aspectRatio("3:4").gravity("face").height(300).crop("fill").chain()
  .quality("auto")).generate("docs/profile-pic.jpg");
```

```flutter
cloudinary.image('docs/profile-pic.jpg').transformation(Transformation()
	.resize(Resize.fill().height(300)
.aspectRatio("3:4")
	.gravity(
	Gravity.focusOn(
	FocusOn.face()))
	)
	.delivery(Delivery.format(
	Format.auto()))
	.delivery(Delivery.quality(
	Quality.auto())));
```

```kotlin
cloudinary.image {
	publicId("docs/profile-pic.jpg")
	 resize(Resize.fill() { height(300)
 aspectRatio("3:4")
	 gravity(
	Gravity.focusOn(
	FocusOn.face()))
	 })
	 delivery(Delivery.format(
	Format.auto()))
	 delivery(Delivery.quality(
	Quality.auto())) 
}.generate()
```

```jquery
$.cloudinary.image("docs/profile-pic.jpg", {transformation: [
  {aspect_ratio: "3:4", gravity: "face", height: 300, crop: "fill"},
  {quality: "auto"}
  ]})
```

```react_native
new CloudinaryImage("docs/profile-pic.jpg")
  .resize(
    fill()
      .height(300)
      .aspectRatio("3:4")
      .gravity(focusOn(face()))
  )
  .delivery(format(auto()))
  .delivery(quality(auto()));
```
> **NOTE**:
>
> If you're on a plan that includes [optimization by default settings](optimize_by_default_settings), you can select the **Automatic format** setting instead of modifying your URLs.
### Cloudinary Video Player

If users are uploading videos, you can take advantage of the [Cloudinary Video Player](cloudinary_video_player) to display them. 

The Cloudinary Video Player is a versatile HTML5-based solution designed for seamless video delivery across devices. It supports responsive layouts, offers built-in controls, and allows for video transformations at both player and individual video levels. The player supports popular video formats, adaptive bitrate streaming, and can host multiple players with different configurations on the same page. Customization options include themes, captions, chapters, and seek thumbnails, along with AI-driven highlights and event triggers.

Here's an example of the video player, playing a video with highlighted captions, seek thumbnails and AI-based highlights graph:

