Menu Search
Jump to the content X X
Smashing Conf New York

You know, we use ad-blockers as well. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf New York, dedicated to smart front-end techniques and design patterns.

Let The Content Delivery Network Optimize Your Images

Sometimes you have to step back and ask why a tradition exists. In mobile-first design1, serving an image in three sizes — one for smartphones, one for tablets and one for desktops — using media queries and responsive images has become a tradition. But is it the best solution?

It’s most likely better than doing nothing, but how well does it actually work? And is there room for improvement? In this article, we’ll look closely at how well the one-size-per-form-factor approach really works and how we can use smart content delivery networks to improve image performance.

Further Reading on SmashingMag: Link

Images Drive Payload And Performance Link

Performance is a complex aspect of making a website. Here, we’ll focus on images because it’s low-hanging fruit on the tree of performance. The effort you spend on optimizing image delivery will most likely have visible and measurable results — especially if you have a website with many images, such as an e-commerce website or an online news website.

Over time, websites have become more image-heavy. Research by Radware6 indicates that the average e-commerce web page is over 1.3 MB; 64%7 of that payload comes from images. More than half of your users (and potential customers) will abandon your website if it takes longer than three seconds8 to load. Literally millions of dollars are at stake in this question of how images affect web performance.

Picking The Right Sizes: Breakpoints Link

The three image sizes referred to above are usually implemented with responsive images (and a polyfill) or with JavaScript that hijacks image-loading.

The latter was the way to go9 until responsive images came around. The idea was that the browser shouldn’t load the images by reading the HTML, but instead should load and execute JavaScript to figure out which images to download. Usually, it would query the viewport’s width, compare that width to the static breakpoints and then select the best fit out of a few predefined image sizes. As we now know, this approach has two major problems. First, it breaks browser preloading10; the browser can’t start loading images referenced in the markup right away, rather having to wait for the JavaScript to execute. Secondly, there is a significant risk of an oversized version of an image being downloaded because you have only a few predefined image sizes to pick from.

Replacing this JavaScript-based image-loading with the new responsive images11 specification addresses the preloading issue. However, the risk of an oversized version of an image being downloaded is just as significant if you have breakpoints for only three image sizes.

Picking the right, and right number of, breakpoints is not an easy task. Even if tools12 exist to help you in the process, breakpoints tend to be a moving target. The ideal breakpoints today could change tomorrow due to new screen sizes and form factors.

How Many Breakpoints Do You Need? Link

How serious is the problem of breakpoints for images? Asked differently, how many versions do you need to save more? Over time, the number of image requests will increase the variety of devices and screen sizes visiting your website.

An experiment done by ScientiaMobile13 found that it takes on average only eight requests for a given image to surpass three breakpoints. The experiment collected data over four months and compared the size of the image actually served to the optimal size for the particular device and screen size. Due to the wide diversity of devices of different forms and shapes accessing the web over time, statistically, the ninth image request will require a size that does not exist and most likely will get the performance penalty of downloading a larger and heavier image than necessary. The more requests you get for a given image’s URL, the more fragmented will be the devices making the requests: At 180 requests, you will surpass 11 breakpoints. At 1,000 image requests, you will surpass 20 breakpoints.

Description of the image.14

How far will three sizes of an image get you? The actual number of requests for an image will vary according to traffic to the website. The curve shown above represents an equation that statistically best fits the image request and breakpoint data collected. (Image: ScientiaMobile2015) (View large version16)

Note that this experiment only covers image sizes. Especially with responsive images, you should also consider alternative image formats (such as GIF, JPG, PNG and WebP) for more efficient file compression. For example, you could send WebP to devices supporting it and PNG to others. This means you would need to render a few formats for each image size. You can see how this quickly multiplies image versions and requires additional logic to serve the appropriate version.

The experiment further explains17 that the strategy of using media queries and breakpoints to serve three different images to different device sizes reduces the payload served down to 63% of the original scenario in which only one size is served to all devices. But we can go further: Introducing content negotiation and server-side image optimization and resizing would reduce the payload to 16%!

Description of the image.18

Using a content delivery network — in this case, ImageEngine19 — can reduce the payload by 84%. (Image: ScientiaMobile2015) (View large version21)

Dynamically optimizing images for any device and screen size will, according to the experiment above, reduce the payload by about 75% compared to using the three static breakpoints.

Smart Content Delivery Networks Link

As we’ve seen, displaying an image on a web page might not be as easy as it sounds if your performance budget is tight. There are many factors to account for. Picking the best breakpoints, image formats, image sizes, compression rate and implementation is challenging enough, but the solution should also be future-friendly. As new devices and form factors are launched into an already diverse landscape, supporting legacy devices becomes just as important as supporting the latest fashion. Automating this process seems to be worthy of serious consideration.

We are starting to see several turnkey solutions that optimize images in this manner. These solutions are smart content delivery networks (CDNs), and they have intelligence built in at the edge of the network. These CDNs offer device-aware image optimization by combining three elements: device detection, real-time image optimization and a classic CDN cache geographically close to the end user. Unlike regular CDNs that do not have an interest in minimizing your payload, smart CDNs seek to improve web performance by tailoring your payload to the capabilities of the device and even network conditions.

What options do you have if you want to implement a dynamic image-optimization CDN on your website? Be aware that there are a lot of image-manipulation services for performing static operations such as resizing, cropping and filtering. This is not what we’re looking for. Nor are we looking for a service that uses JavaScript to determine the best size and format of an image.

We’re looking for a CDN that implements server-side logic, or “edge logic,” using client hints22 or device detection to determine the best image size and format. This is known as content negotiation23. This makes the list significantly shorter. Let’s compare the most prominent contenders:

Client hints Device detection Push or pull
Cloudinary24 yes no push/pull
imgix25 yes no push
ImageEngine26 yes yes pull

All of the above use client hints to determine the best size. Client hints is a fairly new initiative, currently implemented only in Blink-based browsers, and it includes some additional information about preferred image sizes in the HTTP request. The server can use this information to generate a properly sized image. Even though support and adoption of client hints are growing, only about 3% of image requests27 come with client hints. This number is expected to grow. In the near future, however, it would be a good idea to pick a CDN with device detection built in, so that all images are optimized. If you want to play around with the concept a bit, look for a pull-based CDN (which requires less configuration) with a trial option or a free tier.

All of the CDNs mentioned above require registration. Cloudinary have a free tier. ImageEngine a and Imgix has a trial concept, which is convenient if you want to try before you buy. Let’s have a closer look at ImageEngine. ImageEngine is pull-based, which means you don’t have to upload your images anywhere before you start. With ImageEngine, you simply keep images on your server, and ImageEngine will pull images from there on demand.

Once registered for ImageEngine28, you will get a dedicated hostname, which is your CDN’s URL. The only thing left to do is prefix all of your image sources with that hostname.

Say your original image tag is like this:

<img src="" alt="My dog">

Your new image tag with ImageEngine would look like this:

<img src="//{personal-token}" alt="My dog">

In this example, ImageEngine makes use of client hints and device detection to determine the optimal pixel size, compression ratio and image format for each device requesting the image. If you want to be more specific, all services listed above support explicit “commands” to override any automatically detected parameters. For ImageEngine, requesting a 360-pixel-wide image in WebP format would look like this:

<img src="//{personal-token}" alt="My dog">

Of course, to make use of client hints, remember to enable it in your markup. Put this in your <head> tag:

<meta http-equiv="Accept-CH" content="DPR, Viewport-Width, Width">

ImageEngine even has a WordPress plugin29, which handles all of this automatically for you.

The process for imgix and Cloudinary is similar, aside from some additional setup.

All of the services can, of course, be combined with responsive images. With any CDN that supports client hints or device detection, the sometimes verbose markup for responsive images becomes much more maintainable. Responsive images with client hints is covered in greater detail in the article “Leaner Responsive Images With Client Hints30” here on Smashing Magazine.

Conclusion Link

Moving from one image for all kinds of devices to the common one-size-per-form-factor approach is definitely a step in the right direction. The downside is that, from a performance perspective, the approach is too general. There is more juice to be squeezed. However, from a development and maintenance perspective, it might make sense because three image sizes, or breakpoints, are manageable. The logistics are still fairly easy to maintain. But we must not forget why we do this. We’re not doing this for ourselves as developers, but for our end users. Hence, automating this process if we can makes sense. This is not a job for humans. Offloading this task is a win-win: easier maintenance and less data transfer.

Smart CDNs give you core CDN functionality, as well as dynamic and automatic image optimization for any size and form factor by using client hints and device detection at the edge of the network. Experiments suggest that payload savings can run as high as 84% compared to serving one static image, and run around 75% compared to the common one-size-per-form-factor approach.

Luckily, a few smart CDNs are out there already. It’s fairly easy to get started and measure the difference. Once you’ve created an account, you can put up a simple page and run it through WebPagetest31 to see the difference.

(da, vf, al, il)

Footnotes Link

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31

↑ Back to top Tweet itShare on Facebook

Jon Arne Sæterås (jonarnes most places on the webs) is a mobile guy. He has been an active member and thought leader in the global mobile community since the late nineties. His dream is to make the web mobile.
Jon Arne is a developer by trade who believes that making the end user happy is the key to success. He is dedicated to building innovative technology that achieves an optimal user experience.
Jon Arne is also an occasional writer, blogger, speaker and book reviewer.

  1. 1

    Rafael Corrêa Gomes

    April 26, 2017 2:27 pm

    Thanks for sharing!

  2. 2

    Great writeup! I’m currently working on a similar service as a side project which is aimed at requiring no configuration and doing as much as possible on its own.
    I’m also working on a vue.js and a wordpress plugin to automatically select the correct image size without any work to do on developer side.
    Also webp selection is done serverside so the developer doesn’t have to worry about that either. If you would like to get free private beta access, feel free to contact me on twitter @Sopamo or via the (german) website
    I always struggled to be able to find time to integrate optimized and responsive images, especially on smaller projects. That’s why I decided to just prefix the existing image paths of the existing website with the image delivery service:

    is rewritten to:

    It doesn’t get easier than that :)

    I’d also love to hear your feedback what’s important for you regarding image optimization – all the existing solutions had way too much work involved which could easily be done serverside or be automated.

    • 3

      Whoops, I didn’t realize the links would be turned into actual links, they obviously don’t work because is not in my beta program ;)

  3. 4


    We have been using this technique combined with your lazy load lib for a while. In our e-commerces, all product photos have same aspect ratio, so we first load 1 same bulk, low size image for all products. As they are responsive, depending on the place where the photo is located, they render with their exact size. So, we now have the size we need in real render time, and combined with the device dppx, we ask cloudinary for the exact size for the image.

    • 5

      Do you reload the pictures on browser resize? That could also happen on mobile, e.g. reusing the same image in different context or for a picture zoom.

      I cannot find a good solution for that. Either a too low resolution is used or a picture is loaded twice with different resolutions.

      • 6

        No. We don’t reload on window resize nor orientation change although it would be easy.
        For a zoomed image we use another call to cloudinary for a bigger image. As you said, two different image versions.
        You can check the way it works on
        You will notice no t-shirt image is loaded at first until the Lazy Load XT starts doing its magic. When Lazy Load XT looks for the srcAttr which contains the image url, we calculate the exact image width we need for that device. This is the code we use:

        $.extend($.lazyLoadXT, {
        updateEvent:"load orientationchange resize scroll",
        srcAttr: function(img){
        if ($(img).hasClass("cloudinary")) {

        var imgWidth = img.width();

        if(imgWidth == 0){
        if(img.width() == 0){
        imgWidth = 300;

        var dpr = window.devicePixelRatio || 1;

        if (isNaN(parseFloat(dpr)) || !isFinite(dpr)) {
        dpr = 1;
        imgWidth = parseInt(parseFloat(dpr) * parseFloat(imgWidth));

        //html imgage code:

        return img[0].getAttribute('data-src').replace(/c_fill,w_d*/, "c_fill,w_"+imgWidth);
        } else {
        return img[0].getAttribute('data-src');


  4. 8

    Chris Atomix

    April 27, 2017 3:03 am

    We’ve done some testing with Imgix, and it definitely supports Pull, your comparison chart only shows Push. If they don’t have a copy of the original image, they pull it from your server (the path you define in the settings), otherwise they hang onto a copy of it for about 30 days. All resized/modified versions are created from that copy, so it’s only fetched from your server about 12 times a year, at least this is how I understand it based on the Q&A I had with them in their Slack channel.

  5. 11

    Anthony Larkin

    May 6, 2017 1:21 am

    Great write up, Jon. Automating this work with a CDN is the way to go and the pull model makes it a lot simpler. Using device detection to determine the correct image size (breakpoint) and format is a great practice but many solutions don’t support all three: WebP (Chrome/android), JPEG XR (WIN/Surface), and JPEG 2000 (iOS/Safari).

    It’s possible that converting an image to WebP for a given image might actually be less optimal for byte savings than a compressed JPEG or PNG, as an example. Your solution should factor the ultimate byte savings into it’s format choice, on a per image basis, rather than a universal policy to be sure you’re not inadvertently making file sizes larger.

    Optimizing the quality setting can also help you shave bytes. It would take hours upon hours of subjective tuning to get the quality setting right for every image, and using the same setting for all will give you inconsistent results as images will respond differently. Using a solution that analyzes and adjusts each image individually to a threshold determined by a mathematical comparison of visual similarity versus a numeric value helps you maximize byte savings without sacrificing visual quality.

    Akamai has a solution called Image Manager that you might want to check out. Raphael explains how to set it up in this blog (see step 3 for an example with resource hints).


Leave a Comment

You may use simple HTML to add links or lists to your comment. Also, use <pre><code class="language-*">...</code></pre> to mark up code snippets. We support -js, -markup and -css for comments.

↑ Back to top