Image uploads with Cloudinary

A front-end only approach to image uploads; how to offload the server-side hassle to Cloudinary.

Cloudinary to the rescue

If you've arrived here from the Handling image uploads tutorial then congratulations on making it this far and now don't be mad but there was an easier alternative all along - Cloudinary.

Cloudinary is a software–as-a-service (SaaS) solution for image management hosted in the cloud.

To be clear I've picked Cloudinary here because it was recommended to me by a friend, there are other image management services out there; Uploadcare was another I stumbled upon that looked promising.

Setting up your Cloudinary account

If you don't have a Cloudinary account already then register one (it's free for the base tier and only takes a few seconds). Once you have an account log into the site to access the console. On the console's dashboard in the Account Details section you'll see your Cloud name - make a note of it as we'll need it later.

We also need to configure our account to accept unsigned uploads, this is what allows us to off-load all of the server-side image handling to Cloudinary. Select the Settings link within the console navigation then select the Upload tab. Scroll to the bottom of the page and locate the section labelled Upload presets. If unsigned uploading is not enabled click the Enable unsigned uploading link to enable it.

Your account may already have an upload preset defined. If so click the Edit option next to it, if not select the Add upload preset link. There are a lot of options on the next screen but we're only interested in the first 2; the Preset name and Mode.

The Preset name will by default be assigned a unique code, you can leave this as is or rename it to something more memorable, either way make a note of it as we'll need it later. By default the Mode will be set as Signed, change this to Unsigned and then save your changes.

That's it as far as configuring Cloudinary goes, next we need to configure our editor to talk to Cloudinary's API.

This post from Cloudinary offers some details on the signed vs. unsigned upload approaches and the restrictions applied to unsigned uploads.

Building an image uploader for Cloudinary

In this section we're going to put together an image uploader for the Cloudinary API. If you're not familar with the basics of setting up an image uploader then I recommend you read the first couple of sections of the Handling image uploads tutorial (stop when you get to the code examples).

Cloudinary provides API libraries for a number of popular languages including a JQuery plugin for JavaScript, but in the spirit of ContentTools we'll avoid using any specific framework and write our own set of functions to handle calling Cloudinary's (REST) API from the browser.

There's quite a bit of code ahead so if you prefer to learn using rather than reading you'll find all the code in the sandbox folder of the repo. The image uploader code is in the file named cloudinary-image-uploader.coffee and at the top of the sandbox.coffee file you'll find instructions on how to set the sandbox demo up to use Cloudinary.

Before we can get to the good stuff (it's a relative term), we first need to define some settings for the Cloudinary API and a function to act as our image uploader. Use the cloud and upload preset names you set up in the Cloudinary console in place of mycloud and ctpreset in the code below:

You'll notice we've defined functions to handle the cancelUpload and clear events. These aren't affected by the integration with Cloudinary but to avoid any confusion:

cancelUpload handles a user cancelling their file upload.

clear handles a user clearing an uploaded image from the dialog.

Cloudinary URLs

When you upload an image to Cloudinary a URL is returned that can be used both to retrieve the uploaded image and also to transform it. Transforming the image requires the URL's path to be modified to include the details of each transformation to be applied. For example:

We'll be using the rotate, crop and fit transformations and so we need a way to parse Cloudinary URLs and build new ones. Add the following code after the cloudinaryImageUploader function (not inside it):

Uploading an image

Uploading to Cloudinary is no different than uploading to your own web server except we need to pass the name of our upload preset when POSTing so that the service knows to accept unsigned requests. The following code should go inside the cloudinaryImageUploader function:

If you were paying close attention you might have noticed that we're applying a transform to the image as soon as we get its URL back from Cloudinary. The transform applied resizes the image to make sure it fits within a 600 pixel square, that way if the user uploads a larger image we'll still only load a smaller version for the dialog - which is more efficient.

Rotating images

To rotate an image all we need to do is change our image URL to include a rotate transformation and Cloudinary will do the rest:

Resizing images

Now that we can insert an image into the page we need to handle what happens when a user resizes it. This isn't part of the image uploader's responsibility (though for the sake of simplicity we'll tag it on the end of our image uploader file for now). The responsibility instead falls to the ContentEdit.Root node, we need to capture any image resize event and update the image's src URL to match its new size:

The resize event handling doesn't request a resized version of the image from Cloudinary until the user applies their changes, instead the browser will simply scale the original image. This may lead to the image appearing to lose quality when scaled up (only whilst editing) but crucially we don't request unnecessary transformations from Cloudinary.

Limitations

It's all too good to be true, well sort of. There are some limitations to what you can do with unsigned requests and URL changes. Of chief concern to us are:

Images and image variations cannot be removed using an unsigned request.

So using Cloudinary as a service to simplify image uploads and transformations is awesome but in most cases you'll want to use signed uploads and support image removal via a URL on your server (manually removing them from the Cloudinary console is just less fun). Even so server-side integration is not complex and Cloudinary provide a number of guides for popular frameworks.

ContentTools was created by Anthony Blackshaw - a founder of and
developer at getme.
The project is maintained by the crew at getme
along with our contributors.
The code is licensed under MIT.