Cloudinary Blog

Direct upload made easy, from browser or mobile app to the cloud

Direct image upload to the cloud made easy

Handling user uploaded images on your website can be a time consuming task. In this post, we'll show how Cloudinary's cloud-based image management service can help you turn user uploading into a lightweight operation that bypasses your servers altogether.

How do you handle user uploads today? If images are uploaded directly to your servers, this requires some heavy server-side processing, bandwidth and storage space. One way to offload images is to transfer them to cloud storage. But if you're handling the upload operation on your own servers (and then transferring them to the cloud), this is still wasteful of server resources.

A smarter option is to enable uploading of images directly from users' browsers to the cloud. In a previous post, we showed how to do this with Cloudinary's cloud-based image management solution, via our jQuery plugin. We also enable this for mobile apps via the iOS and Android SDKs. But this still requires a small server-side component to handle authentication.

Now we're happy to introduce a new option that simplifies the upload process and completely bypasses your servers - Direct unsigned upload. You can now upload directly from the browser or app to Cloudinary with no predefined authentication. Instead, upload options are controlled by centralized configuration. This is easier to implement and is more suitable for modern client-side and mobile apps with a fast, dynamic UI.

Direct unsigned uploading of images to the cloud: how it works

Cloudinary is an image management solution that allows you to upload your images to the cloud, perform powerful image manipulations on-the-fly, and deliver them to users via a fast CDN.

Previously, we required that all images uploaded are signed with your account's API secret. Now, you can call Cloudinary's upload API without signing with your API secret (we call this 'unsigned'). This allows you to perform upload directly from a browser or mobile app without going through your servers at all. For security reasons, not all upload parameters can be specified directly when performing unsigned upload calls.

First, you need to enable unsigned uploading for your Cloudinary account from the Upload Settings page. If you don't have a Cloudinary account already, you can set it up for free.

Enable unsigned upload

Enabling unsigned uploading creates an 'upload preset' with a unique name, which explicitly allows uploading of images without the API secret. The preset also defines which upload options will be applied to images that are uploaded unsigned.

You can edit the preset at any point in time, to define the parameters that will be used for all images that are uploaded unsigned from user browsers or mobile apps. Read more about upload presets in this post: Centralized control for image upload.

Now, in order to perform unsigned upload, simply call Cloudinary's upload API while setting the upload_preset parameter to the unique name. No need to set the API Key and Secret credentials of your account.

The following code samples show a direct unsigned upload API call in Objective-C for iOS, Java for Android and Ruby:

Cloudinary::Uploader.unsigned_upload("sample.jpg", "zcudy0uz", :cloud_name => "demo")
CLCloudinary *cloudinary = [[CLCloudinary alloc] init];
[cloudinary.config setValue:@"demo" forKey:@"cloud_name"];

NSString *imageFilePath = [[NSBundle mainBundle] pathForResource:@"logo" 

CLUploader* uploader = [[CLUploader alloc] init:cloudinary delegate:self];
[uploader unsignedUpload:imageFilePath uploadPreset:@"zcudy0uz" options:@{}];
InputStream getAssetStream(String filename) throws IOException {
  return getInstrumentation().getContext().getAssets().open(filename);

Map config = new HashMap();
config.put("cloud_name", "demo");
Cloudinary cloudinary = new Cloudinary(config);

cloudinary.uploader().unsignedUpload(getAssetStream("sample.jpg"), "zcudy0uz", 

Upload options for unsigned image uploads

The 'unsigned upload preset' discussed in the previous section globally controls all upload requests coming directly from user browsers or mobile apps, which are not signed with the account API Secret. For example, you can define via the preset that after upload, Cloudinary should eagerly generate thumbnails, mark images for moderation, detect faces, analyze colors and more - and these operations will be performed after every unsigned image upload.

In addition to these global parameters in the 'unsigned upload preset', there are certain parameters you can specify for specific unsigned upload requests: public_id to assign a unique identifier to the uploaded image (while not overwriting an existing image with the same ID), tags to add tags, folder to store the image in a folder, context key-value pairs of meta data, and face_coordinates to specify custom coordinates for incoming cropping or further thumbnail generation.

The following code samples show a more advanced example: specifying a custom public ID of user_sample_image_1002, making it possible to later access the uploaded image, and assigning a tag to simplify management of the images. In addition, we show an example of building a dynamic URL that performs an on-the-fly image manipulation: generating a 150x100 face-detection-based thumbnail of the uploaded images for embedding in your application.

Cloudinary::Uploader.unsigned_upload("sample.jpg", "zcudy0uz", :cloud_name => "demo", 
  :public_id => "user_sample_image_1001", :tags => "ruby_upload")
NSData *imageData = [NSData dataWithContentsOfFile:imageFilePath];

[uploader unsignedUpload:imageData uploadPreset:@"zcudy0uz" options:[NSDictionary dictionaryWithObjectsAndKeys:@"user_sample_image_1002", @"public_id", @"tags", @"ios_upload", nil] withCompletion:^(NSDictionary *successResult, NSString *errorResult, NSInteger code, id context) {

    if (successResult) {

      NSString* publicId = [successResult valueForKey:@"public_id"];
      NSLog(@"Upload success. Public ID=%@, Full result=%@", publicId, successResult);
      CLTransformation *transformation = [CLTransformation transformation];
      [transformation setWidthWithInt: 150];
      [transformation setHeightWithInt: 100];
      [transformation setCrop: @"fill"];
      [transformation setGravity:@"face"];
      NSLog(@"Result: %@", [cloudinary url:publicId options:@{@"transformation": transformation, @"format": @"jpg"}]);                

    } else {

      NSLog(@"Upload error: %@, %d", errorResult, code);            


  } andProgress:^(NSInteger bytesWritten, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite, id context) {
    NSLog(@"Upload progress: %d/%d (+%d)", totalBytesWritten, totalBytesExpectedToWrite, bytesWritten);
InputStream getAssetStream(String filename) throws IOException {
  return getInstrumentation().getContext().getAssets().open(filename);

Map config = new HashMap();
config.put("cloud_name", "demo");
Cloudinary cloudinary = new Cloudinary(config);

cloudinary.uploader().unsignedUpload(getAssetStream("sample.jpg"), "zcudy0uz", 
  Cloudinary.asMap("public_id", "user_sample_image_1001", "tags", "android_upload"));

The response of the API call includes the public ID of the uploaded image, URLs for accessing the image through a CDN and additional details. Here's another example of Cloudinary's dynamic image manipulation: a 150x100 face-detection-based thumbnail of the uploaded image.

cl_image_tag("user_sample_image_1001.jpg", :height=>100, :gravity=>"face", :width=>150, :crop=>"thumb")
cl_image_tag("user_sample_image_1001.jpg", array("height"=>100, "gravity"=>"face", "width"=>150, "crop"=>"thumb"))
CloudinaryImage("user_sample_image_1001.jpg").image(height=100, gravity="face", width=150, crop="thumb")
cloudinary.image("user_sample_image_1001.jpg", {height: 100, gravity: "face", width: 150, crop: "thumb"})
cloudinary.url().transformation(new Transformation().height(100).gravity("face").width(150).crop("thumb")).imageTag("user_sample_image_1001.jpg")
cl.imageTag('user_sample_image_1001.jpg', {height: 100, gravity: "face", width: 150, crop: "thumb"}).toHtml();
$.cloudinary.image("user_sample_image_1001.jpg", {height: 100, gravity: "face", width: 150, crop: "thumb"})
<Image publicId="user_sample_image_1001.jpg" >
        <Transformation height="100" gravity="face" width="150" crop="thumb" />
<cl-image public-id="user_sample_image_1001.jpg" >
        <cl-transformation height="100" gravity="face" width="150" crop="thumb">
cloudinary.Api.UrlImgUp.Transform(new Transformation().Height(100).Gravity("face").Width(150).Crop("thumb")).BuildImageTag("user_sample_image_1001.jpg")
Face detection based thumbnail

Direct uploading from the browser using jQuery

Cloudinary's jQuery plugin allows you to easily add an upload control to your web site, which allows to directly upload an image from their browsers to the cloud. Now you can use dynamic Javascript code to add direct upload controls to your rich client-side web application.

First, include Cloudinary's jQuery plugin and all dependent Javascript files (if you use our server-side client libraries for rendering your pages, there are helper methods for including all required JS files).

<script src='jquery.min.js' type='text/javascript'></script>
<script src='jquery.ui.widget.js' type='text/javascript'></script>
<script src='jquery.iframe-transport.js' type='text/javascript'></script>
<script src='jquery.fileupload.js' type='text/javascript'></script>
<script src='jquery.cloudinary.js' type='text/javascript'></script>

Now you can use the unsigned_upload_tag method to create a new tag specifying an unsigned direct upload. You need to specify the cloud name of your Cloudinary account and the unique name of an unsigned upload preset defined in your account.

  { cloud_name: 'demo' }));

Direct uploading is initiated automatically after a file is selected or dragged. An input field is automatically added to your form with the identifier of the uploaded image for referencing in your model.

Further upload options can be specified, and you can bind to upload progress and completion events, to update your application and UI accordingly. In addition, you can transform an existing input file field into an unsigned direct upload widget.

The following sample Javascript code demonstrates these options. When an 'upload completed' call is received, it dynamically adds an image tag to the page, with a dynamically-generated 150x100 face-detection based thumbnail of the uploaded image, while applying a saturation increase effect.

  { cloud_name: 'demo', tags: 'browser_uploads' }, 
  { multiple: true }
).bind('cloudinarydone', function(e, data) {

    { format: 'jpg', width: 150, height: 100, 
      crop: 'thumb', gravity: 'face', effect: 'saturation:50' } ))}

).bind('cloudinaryprogress', function(e, data) { 

    Math.round((data.loaded * 100.0) / + '%'); 


Direct uploading from the browser uses modern cross-origin resource sharing (CORS) methods. In order to support old Internet Explorer browsers, you should place cloudinary_cors.html in the root of your web application (or set the callback upload parameter to the correct relative path or URL of this file in your web site).

Server-side upload tag rendering

When we introduced signed direct uploading from the browser a while ago, we added view helper methods for rendering direct file upload input fields from the server-side code of your favorite development frameworks.

If your web pages are rendered on the server-side and you still wish to support unsigned uploads, you can use the following new view helper methods for Ruby on Rails, PHP, Java and Node.js:

cl_unsigned_image_upload_tag(:photo, "zcudy0uz", :cloud_name => "demo", 
  :tags => "test_upload")
<?php echo cl_unsigned_image_upload_tag('zcudy0uz', 
    $upload_preset, array("cloud_name" => "demo", "tags" => "test_upload")); ?>
cloudinary.uploader.unsigned_image_upload_tag('photo', 'zcudy0uz', 
  { cloud_name: 'demo', tags: 'test_upload' });
cloudinary.uploader().unsignedImageUploadTag("image_id", zcudy0uz, 
  Cloudinary.asMap("tags", "test_upload"), Map<String, Object> htmlOptions);

cloudinary.uploader().imageUploadTag("image_id", options, htmlOptions);

Sample client-side web projects

We've updated the sample projects of Cloudinary's client libraries (Ruby on Rails, PHP,  Django, Java) to demonstrate unsigned direct uploading with server-side rendering of the initial upload control.

In addition, to demonstrate direct unsigned uploading in client-side-only apps, we've build a sample photo album project in AngularJS. Our project uses the jQuery plugin to perform direct uploading to Cloudinary, and then uses Cloudinary to list uploaded images, further manipulate images, and deliver them via a fast CDN.

The Angular sample project is available as an open source GitHub project.


Direct uploading to the cloud from a browser or mobile app is very powerful. Unsigned uploading makes this much simpler to use in modern apps, while security measures are taken to detect and prevent abuse attempts.

This means that Cloudinary takes care of the entire image management flow - simply call the upload API from your mobile app, or include a single jQuery line in your web app, and images are uploaded directly to Cloudinary. No need for a server-side component at all, you can control upload options using presets from a centralized location, and then dynamically manipulate your images and deliver them from a fast CDN, using nothing but client-side code.

Direct uploading from the browser is one of Cloudinary's most popular features. However, the need to generate server-side signature made usage a bit more complex, especially for modern, dynamic, client-side apps. With our new unsigned upload support, and the new utility methods of the jQuery plugin and other frameworks, we believe direct upload has become much simpler, and you should definitely try it out. Any feedback will be appreciated!

Recent Blog Posts

Find images & videos with a robust new search engine

Great content is hard to come by. You can invest a lot of time and effort in building a great media library, but if content managers and editors can't quickly find what they need at the right time, it's almost useless (and frustrating). Good search capabilities allow you to provide them with a better experience: present relevant content or a well-organized catalog by a variety of criteria such as tags, folders, size, resolution, aspect ratio, faces, colors and many more.

Read more
Video at Large Scale - Contributions from the Developer Community

Video is an increasingly important component for websites - whether it’s to inform visitors, enhance user experience or support sales and marketing efforts. But delivering high-quality video at large scale can be quite a challenge. You need to consider encoding, format, bandwidth usage, delivery and the devices on which visitors may be watching the video, to name just a few concerns.

Read more

Image Optimization in WordPress

By Prosper Otemuyiwa
Image Optimization in WordPress

WordPress is the number one content management system (CMS) in use today, running approximately 27 percent of the entire internet. Several high-traffic websites run on WordPress, and many utilize media, such as images and videos, to attract users and meet their needs.


Read more

Build a Vue Watermarking App for your Image Gallery

By Christian Nwamba
Build a Vue Watermarking App for your Image Gallery

If you intend to build a photo gallery online, you have to seriously consider how to protect the images from users who are not buying them. While visitors need to see the picture before purchasing, there needs to be a way to ensure that even serious buyers are not tempted to use the images without agreeing to your license terms.

Read more

Should You Transform Images On Upload or On Demand?

By Christian Nwamba
Should You Transform Images On Upload or On Demand?

As a developer, you hope and anticipate that your website or mobile application will be accessed by different users on various devices. To improve the user-experience, irrespective of the viewing device, you need to make sure that each image adapts to different graphic layouts, device resolutions and other viewing requirements. For example, for an E-Commerce site, one image will be displayed on different pages — home page, product page, shopping cart and more — and will be viewed on a desktop, cellphone or a tablet. This means that you need to create numerous versions of every image and for a website with hundreds of images, manual manipulation is not scalable.

Read more
Introducing Website Speed Test: An Image Analysis Tool Integrated with WebPagetest

Because images dominate page weight, methodical image optimization can have a significant effect on conversions and user experience. And the performance tools you choose to use can have a powerful impact on how websites are built and maintained. One such popular open source tool is WebPagetest. It is designed to measure and analyze webpage performance, which is why Cloudinary chose to partner with our friends over there to launch Website Speed Test.

Read more