Image optimization

Image optimization involves delivering images with the smallest possible file size while maintaining visual quality. Optimizing images means saving bytes and improving performance for your website: the fewer bytes per image, the faster the browser can download and render the content on your users’ screens. Research shows that this speed is directly related to visitor satisfaction and even monetary conversions.

For example, surveys performed by akamai.com and Gomez reported statistics including:

  • Half of web users expect a website to load within two seconds.
  • A 1-second delay in page load time can decrease visitor satisfaction by 16% and can also lead to a drop in conversion of 7% or more.
  • Load time is a major contributing factor to page abandonment, and the abandonment increases as a percentage with every second of load time, with nearly 40% of users abandoning a page after 3 seconds.
  • 73% of mobile internet users report that they’ve experienced problems with page load times on their devices.

These statistics are from 2009 and 2010, and it’s reasonable to assume that visitors’ expectations have only increased over time.

Most of the time, it is images, and in some cases videos, that have the most impact on slow load time. According to HTTP Archive, around 64% of a website’s average weight is images. Video accounts for another 9%.

Cloudinary’s built-in fast CDN delivery helps to get all resources to your users quickly. Additionally, Cloudinary automatically performs certain optimizations on all transformed images by default. But beyond this, Cloudinary also provides many features that enable you to further optimize images to fit your needs.

This page provides an overview of considerations that can impact image optimization and covers the various Cloudinary optimization features and options you can use to make sure your images are delivered to your users in the quickest and best way possible. Specifically, this page covers:

What is image optimization?

Optimizing an image involves delivering images in the format, dimensions, resolution, and quality that will yield the smallest possible file size while ensuring that the resulting image is appropriate for the specific content, the overall page design, the requesting device, and the expectations of your site visitors.

The following table summarizes the main elements that impact image file size and potential solutions for addressing those issues. However, in many cases, implementing the solutions on your own can be very time or labor intensive. Click the link on each issue to learn how to use Cloudinary functionality to implement these solutions with minimal or no coding.

Issue Problem Possible Solutions
Image quality Often photographs are delivered at their original extra-high resolution, for fear of losing too much visual quality or to make sure users with high-res (retina display and DPR 2+) devices will get the quality they expect. The result is a huge file and slow delivery speeds. In most cases, you can significantly lower quality without a significant visual impact. Consider your image purpose and audience, and use the lowest possible quality that is acceptable for the image content, audience, and purpose.

When it’s important to deliver top-quality images for high-res devices, use the <picture> element and its srcset attribute to deliver different resolutions for different devices.
Image format
  • All image formats use some form of image compression. Some image formats are also lossy, meaning they discard some pixel data. Lossy formats work quite well for some image content, but not for others.
  • Different browsers support a variety of formats that may be more efficient than the standard JPG, PNG, and GIF formats. Delivering the standard formats for all browsers misses out on valuable savings from newer formats like JPEG-XR and WebP.
  • Small images, like buttons and logos are often a larger percentage of site images than designers realize and many appear on every page. These types of images don’t look good in lossy formats, but delivering them as PNGs results in a large cumulative size for these images, which can slow your page load time.
  • Make sure each image is delivered in the right format for its image content. See Image format support and usage.
  • Take advantage of CDN services or other tools/logic to check which browser is making the request and deliver different formats for different browsers using the <picture> element and its srcset attribute.
  • Instead of large animated GIFs, deliver animated WebP or use JPEG-XR (with CSS Animations (using the step property) to supported browsers, or convert to an MP4. You can also consider delivering lossy animated GIFs to get a smaller file when image quality is not a top priority.
  • Vector graphics (SVG) are based on line, point, and shape markup, rather than pixels. Using vectors for geometric graphics, enables sharp results at every resolution and zoom, with a minimal file size.
  • CSS3 effects and animations along with web fonts can sometimes be used to produce resolution-independent resources at a fraction of the size of the corresponding image.
  • Image Sprites: When vectors and CSS3 cannot replace raster images, using a single CSS image sprite, rather than many images, reduces server requests and thus saves bandwidth.
Image metadata By default, images contain a lot of metadata stored by cameras and graphics applications, but this data is completely unnecessary in delivered images. As a best practice, keep the metadata in your original copy of the graphics, but remove it in delivered images.
Image sizing and resizing If you need to display an image at a size smaller than the original, and you rely on the browser to resize images, then you are delivering unnecessarily large files.

This applies both to a standard image resize, and responsive design, which requires multiple different images sizes.
The required dimensions can be determined on the server-side (before it is delivered to the browser).

For responsive design, use the element and its srcset attribute to deliver different size images at different breakpoints.

Even when resizing on the server-side, keep in mind that you can crop to focus on important content, and not just scale down your images.

Default optimizations

Whenever you apply any transformation to an image, Cloudinary performs the following optimizations by default:

  • Strips all associated metadata from the transformed image file (the original image is left untouched). To override this behavior and deliver a transformed image with its metadata intact, add the keep_iptc flag.
  • Applies an automatic quality adjustment to generated WebP, GIF, JPEG, and JPEG-XR formats. To override the default adjustments, set the quality parameter in your transformation.
  • Runs optimization algorithms to minimize the file size without impairing the visual quality when generating images in the PNG, JPEG or GIF format.

How to optimize image quality

Adjusting the quality of your images to a level that still provides good visual output, is one of the most powerful tools in image optimization. You can often deliver images at less than half of the original file size with little to no visually noticeable difference.

Set the appropriate default quality for your account

As mentioned above, when you deliver an image with any transformation applied, it also uses a default quality setting. Depending on the content, purpose, and audience for the majority of your images, you may want to modify the default image quality level in the Upload Settings for your account.

You can choose a fixed quality level, or use one of the q_auto options as the default.

Set a specific quality setting for selected images

When you want image transformations to use a quality setting that is different to the default set for your account, or if you are not performing any other transformations on your image, specify the quality level as a transformation using the quality (q_) parameter.

For example, the q_60 parameter below decreases the delivered file size from 118 KB to 73 KB:

Ruby:
cl_image_tag("sample.jpg", :quality=>60)
PHP:
cl_image_tag("sample.jpg", array("quality"=>60))
Python:
CloudinaryImage("sample.jpg").image(quality=60)
Node.js:
cloudinary.image("sample.jpg", {quality: 60})
Java:
cloudinary.url().transformation(new Transformation().quality(60)).imageTag("sample.jpg")
JS:
cl.imageTag('sample.jpg', {quality: 60}).toHtml();
jQuery:
$.cloudinary.image("sample.jpg", {quality: 60})
React:
<Image publicId="sample.jpg" >
  <Transformation quality="60" />
</Image>
Angular:
<cl-image public-id="sample.jpg" >
  <cl-transformation quality="60">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Quality(60)).BuildImageTag("sample.jpg")
Image set at 60% quality

For details, see Adjusting image quality.

Use q_auto - Automatic quality and encoding

When you add the quality = auto (q_auto in URLs) parameter to your delivered image, Cloudinary's intelligent quality and encoding algorithm selects the optimal quality compression level and optimal encoding settings based on the specific image content, format, and the viewing browser, in order to produce an image with good visual quality while minimizing the file size. This setting can significantly reduce the file size without any degradation noticeable to the human eye, and without the need for you to individually analyze every image.

For example, the q_auto parameter below decreases the delivered file size from 569 KB to 45.1 KB, more than a 90% decrease:

Ruby:
cl_image_tag("woman.jpg", :quality=>"auto")
PHP:
cl_image_tag("woman.jpg", array("quality"=>"auto"))
Python:
CloudinaryImage("woman.jpg").image(quality="auto")
Node.js:
cloudinary.image("woman.jpg", {quality: "auto"})
Java:
cloudinary.url().transformation(new Transformation().quality("auto")).imageTag("woman.jpg")
JS:
cl.imageTag('woman.jpg', {quality: "auto"}).toHtml();
jQuery:
$.cloudinary.image("woman.jpg", {quality: "auto"})
React:
<Image publicId="woman.jpg" >
  <Transformation quality="auto" />
</Image>
Angular:
<cl-image public-id="woman.jpg" >
  <cl-transformation quality="auto">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Quality("auto")).BuildImageTag("woman.jpg")
Image using q_auto

You can further influence the aggressiveness of the algorithm, to get even smaller file sizes, or to ensure higher than average quality, with q_auto:best , :good, :eco, or :low.

By using q_auto:low in the example below, the delivered file size decreases from 569 KB to 33.6 KB, and yet the delivered image, while not perfect, is still quite clean:

Ruby:
cl_image_tag("woman.jpg", :quality=>"auto:low")
PHP:
cl_image_tag("woman.jpg", array("quality"=>"auto:low"))
Python:
CloudinaryImage("woman.jpg").image(quality="auto:low")
Node.js:
cloudinary.image("woman.jpg", {quality: "auto:low"})
Java:
cloudinary.url().transformation(new Transformation().quality("auto:low")).imageTag("woman.jpg")
JS:
cl.imageTag('woman.jpg', {quality: "auto:low"}).toHtml();
jQuery:
$.cloudinary.image("woman.jpg", {quality: "auto:low"})
React:
<Image publicId="woman.jpg" >
  <Transformation quality="auto:low" />
</Image>
Angular:
<cl-image public-id="woman.jpg" >
  <cl-transformation quality="auto:low">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Quality("auto:low")).BuildImageTag("woman.jpg")
Image using q_auto:low

You can also use q_auto together with f_auto (described below) to add additional quality considerations to the format selection algorithm.

Tip: You can set an override quality for a specific image in the Media Library. When set, that quality will always override the q_auto setting. This can be useful to control the quality of an important image if you apply a q_auto default setting for your account, or if all images delivered through a particular process are delivered with a transformation that includes q_auto. Cloudinary also uses your overrides as input that can help it improve the q_auto algorithm.

How to optimize image format

Image formats can be lossy or lossless, each with its own compression algorithm. And as mentioned, each type gives better results on some types of image content, and poorer results on other types. Furthermore, some of the newer formats are only supported on some browsers. See Image format support and usage.

Choosing the right format to deliver each image can result in significant file size savings without sacrificing quality.

There are several Cloudinary options you can use to address these issues.

  • Even if your users upload images in a format that isn’t ideal for the content, you can easily deliver in them a different type, just by changing the file type extension in the delivery URL.
  • Use the fetch_format = auto (f_auto) parameter to allow Cloudinary to analyze the image content and select the best format to deliver. For example, it can automatically deliver images as WebP to Chrome browsers or JPEG-XR to Internet Explorer browsers, while delivering in the original format to all other browsers. This option also delivers animated GIFs as WebP on Chrome, Android and Opera.
  • If you use both f_auto and q_auto, then Cloudinary will still generally deliver WebP and JPEG-XR to the relevant browsers, but might deliver selected images as PNG-8 or PNG-24 if the quality algorithm determines that as optimal.
  • For browsers that do not support WebP, you can also deliver animated GIFs as lossy GIFs, for significant file size savings while maintaining acceptable quality.

This lossy animated GIF is only 2.5 MB, compared to the 6.3 MB original:

Ruby:
cl_image_tag("kitten_fighting.gif", :flags=>"lossy")
PHP:
cl_image_tag("kitten_fighting.gif", array("flags"=>"lossy"))
Python:
CloudinaryImage("kitten_fighting.gif").image(flags="lossy")
Node.js:
cloudinary.image("kitten_fighting.gif", {flags: "lossy"})
Java:
cloudinary.url().transformation(new Transformation().flags("lossy")).imageTag("kitten_fighting.gif")
JS:
cl.imageTag('kitten_fighting.gif', {flags: "lossy"}).toHtml();
jQuery:
$.cloudinary.image("kitten_fighting.gif", {flags: "lossy"})
React:
<Image publicId="kitten_fighting.gif" >
  <Transformation flags="lossy" />
</Image>
Angular:
<cl-image public-id="kitten_fighting.gif" >
  <cl-transformation flags="lossy">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Flags("lossy")).BuildImageTag("kitten_fighting.gif")
A lossy animated GIF

Another way to lower the cost of animated graphics is to deliver animated GIFs as videos. You can do this by simply changing the file type extension to .mp4 (or webm for Chrome, Android, and Opera) in the delivery URL.

For example, this mp4 is 95% smaller than the original animated GIF (319 KB instead of 6.3 MB):

Ruby:
cl_video_tag("kitten_fighting", :resource_type=>"image")
PHP:
cl_video_tag("kitten_fighting", array("resource_type"=>"image"))
Python:
CloudinaryImage("kitten_fighting").video()
Node.js:
cloudinary.video("kitten_fighting", {resource_type: "image"})
Java:
cloudinary.url().resourceType("image").videoTag("kitten_fighting")
JS:
cl.imageTag('kitten_fighting').toHtml();
jQuery:
$.cloudinary.video("kitten_fighting", {resource_type: "image"})
React:
<Image publicId="kitten_fighting" resource_type="image">

</Image>
Angular:
<cl-image public-id="kitten_fighting" resource_type="image">

</cl-image>
.Net:
cloudinary.Api.UrlImgUp.BuildVideoTag("kitten_fighting")

For more information on f_auto, see Automatic format selection. For more information on working with animated GIFs, see Manipulating animated GIFs.

How to optimize image sizing

Web site art-design generally requires displaying images at a variety of sizes, often much smaller than the original.

If you deliver full size images and rely on browser-side resizing (using CSS or HTML width and height attributes), users are forced to unnecessarily download large images. Therefore, images should always be delivered from the server at their final size.

When you use any of the Cloudinary resizing transformations, the sizing (scaling/cropping) is performed on the server-side, and the image is always delivered to the browser at the requested size.

For details on resizing transformations, see Resizing and cropping images.

In general, the time for resizing an image on-the-fly (the first time it is delivered via the CDN) is negligible, but if you are resizing a very large image or video, and every millisecond counts even for those first users, consider doing an eager or explicit transformation to pregenerate the transformed image.

Responsive image sizing

The importance of server-side resizing becomes that much more important if your Web site is responsive and needs to select an image size based on the current size of your browser or the resolution of your device.

By taking advantage of Cloudinary’s dpr_auto, w_auto, and other responsive image functionalities, you can ensure that you are delivering large or high-resolution images only to those users whose device resolution or browser size requires it, and you can create the many different sized images required, using simple transformations.

For example, to deliver the sample image cropped to an aspect ratio of 4:3 using the fill crop method, and then automatically scaled to the width available for the image in the responsive layout, and with a DPR value suitable for the user's device, use a statement like this:

Ruby:
cl_image_tag("sample.jpg", :transformation=>[
  {:aspect_ratio=>"4:3", :crop=>"fill"},
  {:width=>"auto", :dpr=>"auto", :crop=>"scale"}
  ])
PHP:
cl_image_tag("sample.jpg", array("transformation"=>array(
  array("aspect_ratio"=>"4:3", "crop"=>"fill"),
  array("width"=>"auto", "dpr"=>"auto", "crop"=>"scale")
  )))
Python:
CloudinaryImage("sample.jpg").image(transformation=[
  {"aspect_ratio": "4:3", "crop": "fill"},
  {"width": "auto", "dpr": "auto", "crop": "scale"}
  ])
Node.js:
cloudinary.image("sample.jpg", {transformation: [
  {aspect_ratio: "4:3", crop: "fill"},
  {width: "auto", dpr: "auto", crop: "scale"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .aspectRatio("4:3").crop("fill").chain()
  .width("auto").dpr("auto").crop("scale")).imageTag("sample.jpg")
JS:
cl.imageTag('sample.jpg', {transformation: [
  {aspect_ratio: "4:3", crop: "fill"},
  {width: "auto", dpr: "auto", crop: "scale"}
  ]}).toHtml();
jQuery:
$.cloudinary.image("sample.jpg", {transformation: [
  {aspect_ratio: "4:3", crop: "fill"},
  {width: "auto", dpr: "auto", crop: "scale"}
  ]})
React:
<Image publicId="sample.jpg" >
  <Transformation aspect_ratio="4:3" crop="fill" />
  <Transformation width="auto" dpr="auto" crop="scale" />
</Image>
Angular:
<cl-image public-id="sample.jpg" >
  <cl-transformation aspect_ratio="4:3" crop="fill">
  </cl-transformation>
  <cl-transformation width="auto" dpr="auto" crop="scale">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .AspectRatio("4:3").Crop("fill").Chain()
  .Width("auto").Dpr("auto").Crop("scale")).BuildImageTag("sample.jpg")
Image using dpr_auto and w_auto

The above example will yield a 318 KB file on a DPR 2.0 device and 115 KB on a DPR 1.0 device.

For more details, on Cloudinary’s responsive design functionality, see Responsive images.

Additional tips for optimizing images

Sprites

A sprite is a single image that is comprised of many smaller images. The web page is modified to download only a single image from the server and the page’s HTML uses alternative CSS class names to point to the small images within the larger image.

This minimizes the number of images to download and thus the number of server communications required, resulting in faster image delivery.

You can quickly create a single sprite image and the corresponding CSS file comprising all images with a particular tag.

After ensuring all relevant images are sized and tagged as needed, reference the URLs: http://res.cloudinary.com/demo/image/sprite/mytag.css http://res.cloudinary.com/demo/image/sprite/mytag.png

For more details, see Sprite Generation.

Analytics

Even after employing as many automated optimization solutions as possible, you may find that specific original or derived images are still especially big bandwidth eaters.

Take a look at the Reports section of the Cloudinary console. There’s always a personalized tip at the top of the page based on your account’s usage. Then check out the Top bandwidth images or resources and the corresponding Top derived images and resources. Consider employing file-specific optimizations on these resources.

Top derived images listing

Scroll down to the Top Browsers to get an idea of how important each browser is to your users. This can give you insights on the relative value of using newer formats that are only supported on some browsers.

Top browsers graph

Appendix: Image format support and usage

Format Browser support Use for:
JPG Universal Photos, images with many gradients. No transparency needed.
PNG-8 Universal Small color pallette with solid colors and stark contrasts or if full transparency is required.
PNG-24 Universal > 256 solid colors and stark contrasts, or if partial (soft alpha) transparency is required.
GIF Universal Animated, with or without transparency.
WebP Chrome, Opera, Android Supports transparency and animation with better compression than standard formats. Good alternative for users of the relevant browsers.
JPEG-XR Internet Explorer Supports transparency and animation with better compression than standard formats. Good alternative for users of the relevant browsers.
FLIF Currently only with Polyfill solution Lossless format, supports full and partial transparency and, according to its creators, outperforms all the above formats in terms of compression ratio. Currently only works in browsers using a polyfill solution, but it’s a format worth following: FLIF Details.

Additional Reading

For additional reading on image optimization and ways that Cloudinary functionality can help you best optimize your images, you can also review these articles: