Cloudinary Blog

How to Improve Your Shopify’s Store Loading Times using Cloudinary

Improving Shopify Store Loading Times with Cloudinary's Shopify image optimization

Having a commanding presence in e-commerce is very important for the average entrepreneur or merchant today. Building a brand for your business online can be tricky. It’s frustrating having HD images from your product photographer and not having the right tools to optimize the image size and delivery time without losing the quality of the image. This causes latency in your online stores and piles up bad experiences for your users, resulting in losing conversions and revenues.

It does not have to be that way ― with Shopify and Cloudinary, you are just one step away from having the perfect e-commerce store. In this article, you will learn the basics of creating your store with Shopify and integrating it with Cloudinary, so you can manage your images.

With Cloudinary managing your images, you are assured of optimized media content delivery which leads to improved performance, shorter website load times, and more conversion.

What is Shopify?

Shopify is an e-commerce platform that enables you to set up your own online shop. It supports uploading products and setting up payments and shipping, among other activities.

What is Cloudinary?

Cloudinary is a SaaS offering that provides solutions for image and video management, including server or client-side upload, a huge range of on-the-fly image and video manipulation options, quick CDN delivery, and powerful asset management options.

Cloudinary enables web and mobile developers to address all their media management needs with simple bits of code in their favorite programming languages or frameworks, leaving them free to focus primarily on their own product's value proposition.

Getting Started with Shopify

To create a Shopify platform, follow this step-by-step process:

1. Sign Up with Shopify

Visit Shopify and create an account using the signup form. Fill in the necessary details where required.

shopify image optimization

2. Start Setting Up Your Online Shop

After signing up, you will be directed to your store admin screen. From there, you can modify what your store looks like, upload products, set up payments and shipping.

shopify image optimization

3. Pick a Theme

You can choose a theme from Shopify’s theme store. Themes can be modified by editing their HTML and CSS files.

shopify image optimization

For a more detailed tutorial about how to build an online store with Shopify, check out this cool article here.

Integrating Cloudinary with your Store

What’s a store without descriptive images? What’s your product if you can’t successfully manipulate images to tell your audience a convincing story? Even if you already took care of having the best images, how frustrating it can be if these are loaded so slowly and your potential customers leave the store before becoming real customers. You can solve all these using Cloudinary. In addition to creating light-weight images that reduce the loading time of your page, Cloudinary’ offers other awesome features from which you can benefit..

To get our fetch URL, which we will need later, we’ll have to sign up for a free Cloudinary account:

shopify image optimization

Cloudinary also offers a dashboard where you can manage your media contents that are uploaded to your cloud. You can also apply transformations to these images via the Media Library page on the dashboard.

shopify image optimization

Bearing in mind that the integration is technical and requires editing our Shopify Theme code, let’s take the following steps to set up Cloudinary:

STEP 1: Edit your “settings_schema.json” file

On the homepage of your store, navigate to: Online Store > Themes > Actions > Edit Code > Config.

Open the settings_schema.json file:

shopify image optimization

In between the very first "[" and the "{" insert the following code into settings_schema.json. Then go to the next line and insert a comma right before the start of the next opening "{":

    {
      "name": "Cloudinary",
      "settings": [
        {
          "type": "paragraph",
          "content": "Load all your images leveraging Cloudinary's remote image Fetch for best page load performance."
        },
        {
          "type": "checkbox",
          "id": "enableCloudinary",
          "label": "Enable Cloudinary"
        },
        {
          "type": "text",
          "id": "cloudinaryUrl",
          "label": "Cloudinary Fetch URL",
          "info": "Note- Your Cloudinary Fetch url containing your domain, cloud name, and global transformations to apply to all images"
        }
      ]
    }

STEP 2: Add a New “Snippet”

On your store’s homepage, navigate to: Online Store > Themes > Actions > Edit Code > Snippets.

Add a new snippet and name it cloudinary.liquid

Insert the following code into cloudinary.liquid and hit the Save button.

{%if settings.enableCloudinary and settings.cloudinaryUrl != blank %}
     {% assign baseUrl = settings.cloudinaryUrl %}
     {%if img contains "?" %}
          {% assign imgUrl = img | split: "?" %}
          {% assign fetchQuery = "?" | append: imgUrl.last | url_encode %}
          {% assign fetchUrl = imgUrl.first | append: fetchQuery %}
     {% else %}
          {% assign fetchUrl = img %} 
     {% endif %}
     {%if transformation and transformation !=blank %}
          {% assign baseUrl = baseUrl | append: '/|' | append: transformation | replace:'fetch//', 'fetch/' %}
     {% endif %}
     {% assign cloudinaryURL = baseUrl | append: '/https:' | append: fetchUrl | replace: 'https:http','http' | replace:'/|/','/' | replace:'//|','/' |
    replace:'/|','/' %}
{% else %}
     {% assign cloudinaryURL = img %}
{% endif %}

shopify image optimization

STEP 3: Configure Your Cloudinary Settings

From the store homepage, navigate to: Online Store > Themes > Customize > General Settings

Click on the Cloudinary section

shopify image optimization

Tick the Enable Cloudinary checkbox

shopify image optimization

Insert the Cloudinary fetch URL, which is below the input box and hit the Save button

shopify image optimization

An example of the fetch URL would be something like the following:

//res.cloudinary.com/demo/image/fetch/q_auto,f_auto,fl_lossy

The demo parameter should be replaced with your Cloudinary cloud name.

You can read more about the auto property which applies global transformations to your images for optimization reasons

STEP 4: Update Your Section's Theme

On the store homepage, navigate to: Online Store > Themes > Actions> Edit Code > Sections

Click on the section or sections that you want to update. Let's start with the product-template.liquid file so that our product images will be optimized for delivery by Cloudinary.

<!-- from product-template.liquid -->

<div class="grid product-single">
  <div class="grid__item product-single__photos {{ product_image_width }}{% if section.settings.image_size == 'full' %} product-single__photos--full{% endif %}">
    {%- assign featured_image = product.selected_or_first_available_variant.featured_image | default: product.featured_image -%}
    {% for image in product.images %}
      {% capture img_id %}FeaturedImage-{{ section.id }}-{{ image.id }}{% endcapture %}
      {% capture img_class %}product-featured-img{% endcapture %}
      {% capture zoom_img_id %}FeaturedImageZoom-{{ section.id }}-{{ image.id }}{% endcapture %}
      {% capture img_wrapper_id %}{{ zoom_img_id }}-wrapper{% endcapture %}
      {%- assign img_url = image | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}
      {% include 'image-style' with small_style: true, width: height, height: height, wrapper_id: img_wrapper_id, img_id: img_id %}
      <div id="{{ img_wrapper_id }}" class="product-single__photo-wrapper js">
        <div id="{{ zoom_img_id }}" style="padding-top:{{ 1 | divided_by: image.aspect_ratio | times: 100}}%;" class="product-single__photo{% if enable_zoom %} js-zoom-enabled{% endif %}{% if product.images.size > 1 %} product-single__photo--has-thumbnails{% endif %}{% unless featured_image == image %} hide{% endunless %}" data-image-id="{{ image.id }}"{% if enable_zoom %} data-zoom="{{ image | img_url: product_image_zoom_size, scale: product_image_scale }}"{% endif %}>
          <img id="{{ img_id }}"
               class="feature-row__image {{ img_class }} lazyload{% unless featured_image == image %} lazypreload{% endunless %}"
               src="{{ image | img_url: '300x300' }}"
               data-src="{{ img_url }}"
               data-widths="[180, 360, 540, 720, 900, 1080, 1296, 1512, 1728, 2048]"
               data-aspectratio="{{ image.aspect_ratio }}"
               data-sizes="auto"
               alt="{{ image.alt | escape }}">
        </div>
      </div>
    {% endfor %}
. . .

First, assign a new “img” variable to a copy of the existing code for the image src. This existing code is being used to generate the Shopify CDN hosted image URL so we'll want a copy of that so that we can modify it. Let's be sure to include this code above the original src. For example:

    {% assign img = image | img_url: '300x300' %}
     <img id="{{ img_id }}"
          class="feature-row__image {{ img_class }} lazyload{% unless featured_image == image %} lazypreload{% endunless %}"
          src="{{ image | img_url: '300x300' }}"

Next, replace that original image src code with our new cloudinaryURL variable. For example:

    {% assign img = image | img_url: '300x300' %}
     <img id="{{ img_id }}"
          class="feature-row__image {{ img_class }} lazyload{% unless featured_image == image %} lazypreload{% endunless %}"
          src="{{ cloudinaryURL }}"

And finally, include your cloudinary.liquid snippet and pass in the new img variable. The Cloudinary snippet will prepend the product URL with your Cloudinary fetch URL and return the final result in the cloudinaryURL variable:

   {% assign img = image | img_url: '300x300' %}
   {% include 'cloudinary', img:img %}
     <img id="{{ img_id }}"
          class="feature-row__image {{ img_class }} lazyload{% unless featured_image == image %} lazypreload{% endunless %}"
          src="{{ cloudinaryURL }}"

Congratulations! You're product images will now be optimized and delivered by Cloudinary. And we can even change the imge_url filter from 300x300 to large to let Cloudinary perform the smart crop at a higher image quality using inline transformations. These inline transformations are an optional argument to the cloudinary.liquid snippet, but they can be leveraged to further customize your images for your specific templates in addition to any global transformations you may have configured. For example:

   {% assign img = image | img_url: 'large' %}
   {% include 'cloudinary', img:img, transformation: 'w_300,h_300,c_fill,g_auto' %}
     <img id="{{ img_id }}"
          class="feature-row__image {{ img_class }} lazyload{% unless featured_image == image %} lazypreload{% endunless %}"
          src="{{ cloudinaryURL }}"

Let's do the same thing for the zoom overlay image, too, and see it all put together:

<!-- from product-template.liquid -->

<div class="grid product-single">
  <div class="grid__item product-single__photos {{ product_image_width }}{% if section.settings.image_size == 'full' %} product-single__photos--full{% endif %}">
    {%- assign featured_image = product.selected_or_first_available_variant.featured_image | default: product.featured_image -%}
    {% for image in product.images %}
      {% capture img_id %}FeaturedImage-{{ section.id }}-{{ image.id }}{% endcapture %}
      {% capture img_class %}product-featured-img{% endcapture %}
      {% capture zoom_img_id %}FeaturedImageZoom-{{ section.id }}-{{ image.id }}{% endcapture %}
      {% capture img_wrapper_id %}{{ zoom_img_id }}-wrapper{% endcapture %}
      {%- assign img_url = image | img_url: '1x1' | replace: '_1x1.', '_{width}x.' -%}
      {% include 'image-style' with small_style: true, width: height, height: height, wrapper_id: img_wrapper_id, img_id: img_id %}
      {% assign img=image | img_url: product_image_zoom_size, scale: product_image_scale %}
      {% include 'cloudinary', img:img %}
      <div id="{{ img_wrapper_id }}" class="product-single__photo-wrapper js">
        <div id="{{ zoom_img_id }}" style="padding-top:{{ 1 | divided_by: image.aspect_ratio | times: 100}}%;" class="product-single__photo{% if enable_zoom %} js-zoom-enabled{% endif %}{% if product.images.size > 1 %} product-single__photo--has-thumbnails{% endif %}{% unless featured_image == image %} hide{% endunless %}" data-image-id="{{ image.id }}"{% if enable_zoom %} data-zoom="{{ cloudinaryURL }}"{% endif %}>
          {% assign img = image | img_url: 'large' %}
          {% include 'cloudinary', img:img, transformation: 'w_300,h_300,c_fill,g_auto' %}
          <img id="{{ img_id }}"
               class="feature-row__image {{ img_class }} lazyload{% unless featured_image == image %} lazypreload{% endunless %}"
               src="{{ cloudinaryURL }}"
               data-src="{{ cloudinaryURL }}"
               data-widths="[180, 360, 540, 720, 900, 1080, 1296, 1512, 1728, 2048]"
               data-aspectratio="{{ image.aspect_ratio }}"
               data-sizes="auto"
               alt="{{ image.alt | escape }}">
        </div>
      </div>
    {% endfor %}
. . .

Few Points to Take Away

  1. One click enable/disable of the Cloudinary integration - ideal for performance A/B testing on demand.
  2. The integration uses Cloudinary’s 3rd party proxy "Fetch" protocol so you can still use your Shopify media library as is and we'll import, manipulate and deliver all your images via Cloudinary automatically.
  3. You'll have access to both Global transformation settings (common transformations for all assets) as well as location specific / template specific transformation settings. The only downside is that you'll need to update your image references in your existing snippets / templates as shown in the integration guide. However, you also have full control to edit the integration to your needs using this version as a starting point.

Adjust Cloudinary settings (for existing accounts)

Go to your account's Security settings page (https://cloudinary.com/console/settings/security) and make sure that the checkbox near "Fetched URL" setting is not checked. Uncheck it as necessary.

Further down on this page, in the box of "Allowed fetch domains", make sure that the box is empty or that "https://cdn.shopify.com" is specified. If there are domains listed in the box and Shopify is not specified than add "https://cdn.shopify.com". If the box is blank, then leave it blank.

Conclusion

Image optimization in websites is a very important feature that cannot be overlooked. The same can be said for online stores. Having a store that displays its content in the best possible way and display it immediately will not only speak well of your brand, but will play a huge role in dictating sales volume and other important factors in the long run. Some of these factors include customer acquisition rate, conversion rate, and whether or not they keep visiting your site after the first few experiences. For a more detailed overview on how to optimize images on your websites, you can check out this article by Prosper Otemuyiwa .

UPDATE - Dec 2017: Due to the wonderful response to this article and the custom integration work that we've undertaken since it went live, we've adjusted our snippet code for greater flexibility and expanded the code examples listed out above.

Recent Blog Posts

An Eye-Opening Talk: Building Apps for the Next Billion Users in Africa

William (iChuloo) Imoh, who hails from Lagos, Nigeria, recently embarked on a U.S. speaking tour, February 20-March 12, during which he powwowed with technical and product teams and communities at such renowned enterprises as Netlify, Pluralsight, Lucidchart, Twilio, and more in Salt Lake City, Dallas, Las Vegas, and San Francisco. On March 5, he gave an enlightening talk, entitled International Developers and Development: Building for the Next Billion Users at Cloudinary in Santa Clara, California. Below is a synopsis. For details, see the related slides.

Read more
The Debut of the Cloudinary Customer Advisory Board

Focus on customers has always been Cloudinary’s mantra. Because we owe them our success, we are constantly reaching out to our customers, not just for feedback on our offerings, but also for their vision, wish list, and buy-in of what Cloudinary can do to meet their needs and make them succeed. About six months ago, it occurred to us that it would be beneficial if we could meet regularly with those who are behind innovation at our key customers—executives, product gurus, developers, content managers—to swap strategies, product roadmaps, best practices, and such. In particular, we’d like to solicit actionable feedback as a foundation for our plans of product enhancements.

Read more
Media Management With the Cloudinary-Netlify CMS Integration

Static sites and the JAMstack are quickly becoming a standard for developing safe and performant websites with an optimal workflow for developers. Netlify CMS (not to be confused with the company that created it, Netlify) is an open source content management solution that works especially with static site generators such as Gatsby, Hugo, etc... enabling content storage in your Git repository along with your code for easier versioning, multichannel publishing, and direct content updates in Git.

Read more
Vitaly Friedman's Insights on Media Conferences

Vitaly Friedman is a die-hard devotee of beautiful content. Born in Minsk, Belarus, he studied Computer Science and Mathematics in Germany, unearthing in himself a passion for typography, writing, and design in the interim. After a six-year stint as a freelance designer and developer, he co-founded Smashing Magazine, a leading online publication on web design and development. You can follow SmashingMag on Twitter @SmashingMag.

Read more