Transformations on upload

Cloudinary's transformations can be used while uploading an asset in one of two ways:

  • Eager transformations: Generate transformed assets during the upload call so that those transformations will already be available for delivery before your users access them for the first time. These transformations are generated in addition to storing the original asset as is. This is especially useful for transformations that can take a while to generate.
  • Incoming transformations: Transform the original asset before storing it in your Cloudinary account. This can be useful for example to limit images to a maximum resolution or videos to a maximum duration.

Eager transformations

Cloudinary can either transform your assets on demand, when first accessed by your visitors as 'lazy transformations', or during the asset upload process as eager transformations. Eager transformations are generated in addition to storing the original asset as is and you request multiple eager transformations during a single upload command.

When transforming on demand during delivery, all transformed assets are generated on-the-fly, stored persistently, cached and delivered through a fast CDN. The time required for generating a transformation depends on various factors: original asset dimensions, asset file size, requested dimensions, applied effects and specific transformations. Once generated for the first time on the first request of a visitor, the transformed asset is henceforth cached and delivered through a fast CDN for all subsequent requests.

The eager approach requires a little planning, but is recommended if you want to make sure that all transformed assets are ready for fast delivery even for the first visitors to your assets. This is especially useful for video transformations, transformations that perform AI analyses, or other asynchronous operations, such as those performed by some Cloudinary add-ons.

For these cases, you can eagerly generate the required transformations during the upload process so all transformed assets will already be available before your users access them for the first time. Eager transformations are also useful in the case that you want to enable Strict Transformations for your account and limit access to dynamic URLs (for more information, see Control access to assets).

This option accepts either a single transformation or an array of transformations, where each transformation is represented by a hash of transformation parameters. For more details on available transformation parameters, see the Image transformation reference and Video transformation reference.

Note
When using the REST API rather than an SDK, the eager parameter receives a list of transformation strings separated with a pipe character (|). Chained transformations are separated with a slash (/). For example, the following eager value will generate two transformations: crop out a 400x400 region centered on the largest detected face and then scale down to a width and height of 50 pixels, and crop to a width and height of 30 pixels with south gravity:

Copy to clipboard
eager=c_crop,w_400,h_400,g_face/w_50,h_50,c_scale|w_30,h_30,c_crop,g_south

For more details, see Uploading with a direct call to the REST API)

The following example uploads the sample.jpg image and then additionally generates two transformed images:

  1. Pad to a width of 400 pixels and height of 300 pixels.
  2. Crop to a width of 260 pixels and a height of 200 pixels with north gravity.
Ruby:
Copy to clipboard
Cloudinary::Uploader.upload("sample.jpg",
  :eager => [
    {:width => 400, :height => 300, :crop => :pad}, 
    {:width => 260, :height => 200, :crop => :crop, :gravity => :north}])
PHP:
Copy to clipboard
\Cloudinary\Uploader::upload("sample.jpg", array( 
  "eager" => array(
    array("width" => 400, "height" => 300, "crop" => "pad"),
    array("width" => 260, "height" => 200, "crop" => "crop", "gravity" => "north"))));
Python:
Copy to clipboard
cloudinary.uploader.upload("sample.jpg", 
  eager = [
    {"width": 400, "height": 300, "crop": "pad"},
    {"width": 260, "height": 200, "crop": "crop", "gravity": "north"}])
Node.js:
Copy to clipboard
cloudinary.v2.uploader.upload("sample.jpg", 
  { eager: [
    { width: 400, height: 300, crop: "pad" }, 
    { width: 260, height: 200, crop: "crop", gravity: "north"} ]}, 
  function(error, result) {console.log(result, error); });
Java:
Copy to clipboard
cloudinary.uploader().upload("sample.jpg", 
  ObjectUtils.asMap(
    "eager", Arrays.asList(
      new Transformation().width(400).height(300).crop("pad"),
      new Transformation().width(260).height(200).crop("crop").gravity("north"))));
.Net:
Copy to clipboard
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"sample.jpg"),
  EagerTransforms = new List<Transformation>(){
   new Transformation().Width(400).Height(300).Crop("pad"),
   new Transformation().Width(260).Height(200).Crop("crop").Gravity("north")}};
var uploadResult = cloudinary.Upload(uploadParams);
iOS:
Copy to clipboard
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)

The delivery URLs for these eagerly generated transformations:

Ruby:
Copy to clipboard
cl_image_tag("sample.jpg", :width=>400, :height=>300, :crop=>"pad")
PHP:
Copy to clipboard
cl_image_tag("sample.jpg", array("width"=>400, "height"=>300, "crop"=>"pad"))
Python:
Copy to clipboard
CloudinaryImage("sample.jpg").image(width=400, height=300, crop="pad")
Node.js:
Copy to clipboard
cloudinary.image("sample.jpg", {width: 400, height: 300, crop: "pad"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().width(400).height(300).crop("pad")).imageTag("sample.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('sample.jpg', {width: 400, height: 300, crop: "pad"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("sample.jpg", {width: 400, height: 300, crop: "pad"})
React:
Copy to clipboard
<Image publicId="sample.jpg" >
  <Transformation width="400" height="300" crop="pad" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="sample.jpg" >
  <cld-transformation width="400" height="300" crop="pad" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="sample.jpg" >
  <cl-transformation width="400" height="300" crop="pad">
  </cl-transformation>
</cl-image>
.Net:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Width(400).Height(300).Crop("pad")).BuildImageTag("sample.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().width(400).height(300).crop("pad")).generate("sample.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setWidth(400).setHeight(300).setCrop("pad")).generate("sample.jpg")!, cloudinary: cloudinary)
sample.jpg padded to a width of 400 pixels and height of 300 pixels

Ruby:
Copy to clipboard
cl_image_tag("sample.jpg", :width=>260, :height=>200, :gravity=>"north", :crop=>"crop")
PHP:
Copy to clipboard
cl_image_tag("sample.jpg", array("width"=>260, "height"=>200, "gravity"=>"north", "crop"=>"crop"))
Python:
Copy to clipboard
CloudinaryImage("sample.jpg").image(width=260, height=200, gravity="north", crop="crop")
Node.js:
Copy to clipboard
cloudinary.image("sample.jpg", {width: 260, height: 200, gravity: "north", crop: "crop"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().width(260).height(200).gravity("north").crop("crop")).imageTag("sample.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('sample.jpg', {width: 260, height: 200, gravity: "north", crop: "crop"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("sample.jpg", {width: 260, height: 200, gravity: "north", crop: "crop"})
React:
Copy to clipboard
<Image publicId="sample.jpg" >
  <Transformation width="260" height="200" gravity="north" crop="crop" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="sample.jpg" >
  <cld-transformation width="260" height="200" gravity="north" crop="crop" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="sample.jpg" >
  <cl-transformation width="260" height="200" gravity="north" crop="crop">
  </cl-transformation>
</cl-image>
.Net:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Width(260).Height(200).Gravity("north").Crop("crop")).BuildImageTag("sample.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().width(260).height(200).gravity("north").crop("crop")).generate("sample.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setWidth(260).setHeight(200).setGravity("north").setCrop("crop")).generate("sample.jpg")!, cloudinary: cloudinary)
sample.jpg cropped to a width of 260 pixels and a height of 200 pixels with north gravity

Note
When using the SDK for a dynamically-typed language, the transformation parameters can be specified directly, without specifying the transformation parameter, as seen for example in the examples for Ruby, PHP, Python, and Node.js above.

You can also generate eager transformations for previously uploaded assets using the explicit API method.

Eager asynchronous transformations

You can tell Cloudinary to generate eager transformations in the background by setting the eager_async parameter to true. This is useful when you use direct uploading from the browser and you don't want your users to have to wait for the transformation(s) to finish processing. In addition, you can set the optional eager_notification_url parameter to receive a webhook notification when the transformation generation is completed. For details, see Notifications.

The upload method supports the following parameters for eager asynchronous transformations:

  • eager - A list of transformations to create for the uploaded asset during the upload process, instead of lazily generating them when first accessed by your site's visitors. This option accepts either a single transformation or an array of transformations, where each transformation is represented by a hash of parameters. For details on available transformation pararmeters, see the Image transformation reference and Video transformation reference.
  • eager_async - A Boolean value determining whether to generate the eager transformations asynchronously in the background after the file is finished uploading or synchronously as part of the upload call. Default: false.
  • eager_notification_url - An HTTP or HTTPS URL to notify your application (a webhook) when the generation of eager transformations is completed. If a transformation fails for some reason, the response includes "state=failed" and the reason.

For example, the following method will upload the sample.jpg image and then eagerly generate two transformed images as follows:

  1. Pad to a width and height of 300 pixels.
  2. Crop to a width of 160 pixels and a height of 100 pixels with south gravity.

Furthermore, the transformations will be performed asynchronously after the file finishes uploading, with a callback URL to notify your application once the upload is complete and a different callback URL to notify your application once the transformations are complete:

Ruby:
Copy to clipboard
Cloudinary::Uploader.upload("sample.jpg",
  :eager => [
    { :width => 300, :height => 300, :crop => :pad}, 
    { :width => 160, :height => 100, :crop => :crop, :gravity => :south}], 
  :eager_async => true, 
  :eager_notification_url => "https://mysite.example.com/eager_endpoint",
  :notification_url => "https://mysite.example.com/upload_endpoint")
PHP:
Copy to clipboard
\Cloudinary\Uploader::upload("sample.jpg", 
  array( 
    "eager" => array(
        array("width" => 300, "height" => 300, "crop" => "pad"),
        array("width" => 160, "height" => 100, "crop" => "crop", "gravity" => "south")),
    "eager_async" => TRUE,
    "eager_notification_url" => "https://mysite.example.com/eager_endpoint",
    "notification_url" => "https://mysite.example.com/upload_endpoint"));
Python:
Copy to clipboard
cloudinary.uploader.upload("sample.jpg", 
  eager = [
    {"width": 300, "height": 300, "crop": "pad"},
    {"width": 160, "height": 100, "crop": "crop", "gravity": "south"}],
  eager_async = true,
  eager_notification_url = "https://mysite.example.com/eager_endpoint",
  notification_url = "https://mysite.example.com/upload_endpoint")
Node.js:
Copy to clipboard
cloudinary.v2.uploader.upload("sample.jpg", 
  { eager: [
      { width: 300, height: 300, crop: "pad" }, 
      { width: 160, height: 100, crop: "crop", gravity: "south"} ],                                   
    eager_async: true,
    eager_notification_url: "https://mysite.example.com/eager_endpoint",
    notification_url: "https://mysite.example.com/upload_endpoint" }, 
  function(error, result) {console.log(result, error); });
Java:
Copy to clipboard
cloudinary.uploader().upload("sample.jpg", 
  ObjectUtils.asMap(
    "eager", Arrays.asList(
      new Transformation().width(300).height(300).crop("pad"),
      new Transformation().width(160).height(100).crop("crop").gravity("south")),
    "eager_async", true,
    "eager_notification_url", "https://mysite.example.com/eager_endpoint",
    "notification_url", "https://mysite.example.com/upload_endpoint"));
.Net:
Copy to clipboard
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"sample.jpg"),
  EagerTransforms = new List<Transformation>(){
   new Transformation().Width(300).Height(300).Crop("pad"),
   new Transformation().Width(160).Height(100).Crop("crop").Gravity("south")},
  EagerAsync = true,
  EagerNotificationUrl = "https://mysite.example.com/eager_endpoint",
  NotificationUrl = "https://mysite.example.com/upload_endpoint"};
var uploadResult = cloudinary.Upload(uploadParams);

Eager notification response

When the eager transformations are completed, an HTTP POST request will be sent to the eager notification webhook URL you provided, with details about the requested eager transformations including the HTTP and HTTPS URLs for accessing the derived assets. For example:

Copy to clipboard
{
  "notification_type":"eager", 
  "eager":[{
    "transformation":"jpg", 
    "width":190, 
    "height":100, 
    "bytes":1805410,
    "url":"http://res.cloudinary.com/demo/image/upload/h_100,w_190/v1517971772/qvd.jpg", 
    "secure_url":"https://res.cloudinary.com/demo/image/upload/h_100,w_190/v1517971772/qvd.jpg" }], 
  "public_id":"qvd", 
  "batch_id":"6ebf1479dd8b71eb4e632620520f7347978a37ee7e30595a119c0efb957fb8c3ff96"
}

For more information on Eager notification URLs and responses, see the Notifications documentation.

Incoming transformations

Assets uploaded to Cloudinary are stored in your account as-is, by default. During or after the upload, you can generate derived assets from these originals by asking Cloudinary to apply transformations.

However, in some cases, you may want to modify the original assets before storing them in your account, by applying an incoming transformation as part of the upload request. Any supported image or video transformation parameter can be specified for your incoming transformation. Contrary to eager transformations, incoming transformations are applied before saving the asset in your account. This is especially useful to normalize user-generated content, for example to limit the resolution size or clip a long video to a maximum duration.

For example, to limit the dimensions of an uploaded image to a width of 2000 pixels and a height of 1000 pixels:

Ruby:
Copy to clipboard
Cloudinary::Uploader.upload("sample.jpg", 
  :width => 2000, :height => 1000, :crop => :limit)
PHP:
Copy to clipboard
\Cloudinary\Uploader::upload("sample.jpg", 
  array("width" => 2000, "height" => 1000, "crop" => "limit"));
Python:
Copy to clipboard
cloudinary.uploader.upload("sample.jpg", 
  "width" = 2000, "height" = 1000, "crop" = "limit")
Node.js:
Copy to clipboard
cloudinary.v2.uploader.upload("sample.jpg",
  { width: 2000, height: 1000, crop: "limit" },
  function(error, result) { console.log(result, error); });
Java:
Copy to clipboard
cloudinary.uploader().upload("sample.jpg",
  ObjectUtils.asMap("transformation", 
    new Transformation().width(2000).height(1000).crop("limit")));
.Net:
Copy to clipboard
var uploadParams = new ImageUploadParams() {
  File = new FileDescription(@"sample.jpg"),
  Transformation = new Transformation().Width(2000).Height(1000).Crop("limit")};
var uploadResult = cloudinary.Upload(uploadParams);
iOS:
Copy to clipboard
let params = CLDUploadRequestParams()
  .setTransformation(
    CLDTransformation().setWidth(2000).setHeight(1000).setCrop("limit"))
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)

Note
When using the SDK for a dynamically-typed language, the transformation parameters can be specified directly, without specifying the transformation parameter, as seen for example in the examples for Ruby, PHP, Python, and Node.js above.

✔️ Feedback sent!