Meteor-example-cloudinary is a sample Meteor application that illustrates the use of Cloudinary for image uploading and display. The combination of Cloudinary’s unsigned uploading and javascript upload widget makes it quite simple to implement non-trivial image uploading and manipulation.

To illustrate these features, this sample application:

All of these constraints can be changed to suit for your own requirements, but they hopefully provide a useful starting point for many application use cases.

Please note that the overall structure of meteor-example-cloudinary is based on two other sample applications:

Please refer to these applications for more details on structure. This documentation focuses on cloudinary-specific issues.

Cloudinary Setup

To run this application, you must first define and configure a Cloudinary account.

Set up your Cloudinary account

To run this application, you must first sign up for a free Cloudinary account. The free plan (as of Summer, 2017) offers 75K total images, 2 GB storage, and 5 GB monthly bandwidth. This should be enough for demo purposes.

During the initial user configuration wizard, the “Account Settings” dialog will provide the option to enable unsigned uploads. You should enable this feature.

Create an “upload preset”

Now create an “upload preset” to allow unsigned uploading. You create an upload preset in the Settings / Upload area of your Cloudinary management dashboard. After it’s been created, you will see something like this:

Note that unsigned uploading enables anyone who obtains your upload preset string to upload new images to your Cloudinary account (but not edit or delete any existing images). If this creates a security risk for your application, then you will want to switch to signed uploading prior to putting your application into production.

(The upload preset string shown in this documentation has subsequently been changed.)

Define an incoming transformation so that you store only the cropped image

By default, Cloudinary will store the entire selected image along with the coordinates of the cropped portion. To specify that Cloudinary should store only the result of cropping, you must define an incoming transformation. For this application, you want to create an incoming transformation that specifies the mode as “crop” and the gravity as “custom”. Here’s what the dialog looks like:

Application setup

Download and install the application.

First, install Meteor.

Second, download a zip file containing a snapshot of meteor-example-cloudinary.

Third, expand the zip file, cd into the app directory, and install the required libraries with:

$ meteor npm install

Create config/settings.production.json

Make a copy of config/settings.development.json, and call it settings.production.json. (This file is git-ignored, so you can put your upload preset information in it and it will not be committed to GitHub.)

Edit this file to contain your account’s cloud name and upload preset. For example:

  "public": {
    "cloudinary": {"cloud_name": "ddv7bs7cx", "upload_preset": "i2jfxuwv"}

Note that I’ve subsequently changed the value for my upload preset.

Run the program

Now you can run the application by invoking the “start” script in the package.json file:

$ meteor npm run start

Note regarding bcrypt warning. You will get the following message when you run this application:

Note: you are using a pure-JavaScript implementation of bcrypt.
While this implementation will work correctly, it is known to be
approximately three times slower than the native implementation.
In order to use the native implementation instead, run

  meteor npm install --save bcrypt

in the root directory of your application.

On some operating systems (particularly Windows), installing bcrypt is much more difficult than implied by the above message. Bcrypt is only used in Meteor for password checking, so the performance implications are negligible until your site has very high traffic. You can safely ignore this warning without any problems.

If all goes well, the template application will appear at http://localhost:3000.


When the application runs for the first time, the home page (actually, the only page) should look like this:

If you click the submit button without filling in either the name or image fields, the system will note an error:

Let’s say we want to add an image of Jerry Garcia, which we have conveniently located on our desktop. We can type his name into the “Name” field, and then click the “Upload image file” button, which brings up the Cloudinary Upload Widget:

Then we can click “Select File”, and choose the file of Jerry on our desktop. The widget then displays the image along with the cropping square:

The requirement to crop, and the constraint that the crop yield a square, is easily changed in the example source code.

If you now click “Upload”, two things happen. First, the image is uploaded to Cloudinary. Second, you are returned to the Meteor form and the image field is filled in with the file name (“jerry”):

At this point, the image has already been uploaded to Cloudinary, but since we have not yet submitted this form, the Meteor application does not know about the image. So, let’s click “Submit” to submit the form with the pointer to the uploaded image. Once we do that, the page looks like this:

After pressing submit, the form submission process adds a new document to a Meteor collection containing the image name and the URLs returned by the Cloudinary upload widget for a thumbnail view as well as the full size (cropped) image. The page has a simple table below the form to display all of the documents in this collection. It is reactively updated with the new contents of the collection.

Note that if we go to our Cloudinary Media Library page, we can now see the uploaded image, which is stored in its cropped and down-sampled form:

Code Walkthrough

For more details on how this application is constructed, please watch a brief overview by clicking on the image below:

Cloudinary documentation

Here are some links to Cloudinary documentation that I found useful when developing this application: