<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rahul Nanwani</title>
    <description>The latest articles on DEV Community by Rahul Nanwani (@rnanwani).</description>
    <link>https://dev.to/rnanwani</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F104692%2Ffd641d51-8c60-469e-a370-91a6ad966add.jpg</url>
      <title>DEV Community: Rahul Nanwani</title>
      <link>https://dev.to/rnanwani</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rnanwani"/>
    <language>en</language>
    <item>
      <title>Optimize and resize images in AWS S3 in real-time with ImageKit</title>
      <dc:creator>Rahul Nanwani</dc:creator>
      <pubDate>Thu, 02 Jul 2020 13:11:13 +0000</pubDate>
      <link>https://dev.to/rnanwani/optimize-and-resize-images-in-aws-s3-in-real-time-with-imagekit-dg7</link>
      <guid>https://dev.to/rnanwani/optimize-and-resize-images-in-aws-s3-in-real-time-with-imagekit-dg7</guid>
      <description>&lt;p&gt;&lt;a href="https://aws.amazon.com/s3/"&gt;AWS Simple Storage Service&lt;/a&gt; or S3 is one of the most commonly used cloud-based storage across the globe. It provides infinite storage with high uptime, immediate access, and scales up as per your requirements.&lt;/p&gt;

&lt;p&gt;A common use of AWS S3 storage is to store large files, like images. Images are often huge and have to be stored for really long times. Storing them in S3 takes away the pain of managing the storage on your own or continuously adding space on your server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features missing for image optimization natively on AWS S3
&lt;/h2&gt;

&lt;p&gt;While S3 is excellent for image storage, it does not provide the following features, which are now fundamental for every website that is serious about delivering an exceptional experience to its users -&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The ability to be able to &lt;a href="https://imagekit.io/blog/image-optimization-its-importance/"&gt;compress the images&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The ability to be able to &lt;a href="https://docs.imagekit.io/features/image-optimization/automatic-image-format-conversion"&gt;convert the images to a newer, better formats&lt;/a&gt; like WebP&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The ability to &lt;a href="https://docs.imagekit.io/features/image-transformations/resize-crop-and-other-transformations"&gt;resize and crop the images&lt;/a&gt; for use on different pages of our application&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And maybe a more advanced requirement could be to be able to these and more advanced manipulations like watermarking those images, creating smart thumbnails in real-time without having to write or maintain complex solutions for it. More often than not, managing images is not your core business, and you do not want to be spending a lot of time on it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OF7KdwRs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4008/1%2A84SkBIb2qztpVoo9TGOsQA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OF7KdwRs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4008/1%2A84SkBIb2qztpVoo9TGOsQA.jpeg" alt="A large and unoptimized image in S3" width="800" height="180"&gt;&lt;/a&gt;&lt;em&gt;A large and unoptimized image in S3&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is ImageKit, and how does it optimize images in S3?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://imagekit.io"&gt;ImageKit.io&lt;/a&gt; is a cloud-based &lt;a href="https://imagekit.io/blog/what-is-image-cdn-guide/"&gt;image CDN&lt;/a&gt; with real-time image optimization and transformation features that help you deliver perfectly optimized images across all devices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Eo9C37_E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3596/1%2AzDtTW4-9E_momGYKLEH4EA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Eo9C37_E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/3596/1%2AzDtTW4-9E_momGYKLEH4EA.jpeg" alt="Just by delivering through ImageKit, your images get optimized. You can then start resizing the images as well." width="800" height="158"&gt;&lt;/a&gt;&lt;em&gt;Just by delivering through ImageKit, your images get optimized. You can then start resizing the images as well.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It comes integrated with AWS CloudFront for image delivery (and other non-image files too). Over 15,000 developers and companies already serve billions of optimized images via ImageKit and its CDN every day. So, you do not have to pay for a separate CDN if you are using ImageKit.&lt;/p&gt;

&lt;p&gt;You can attach your AWS S3 bucket to ImageKit and start delivering optimized images in just a few minutes. Without writing a single line of code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tbl0yWz---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A_Zqelp4OzJ-b_piX2n61JQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tbl0yWz---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A_Zqelp4OzJ-b_piX2n61JQ.jpeg" alt="Setup of your AWS S3 storage with ImageKit" width="800" height="274"&gt;&lt;/a&gt;&lt;em&gt;Setup of your AWS S3 storage with ImageKit&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Image Optimization on S3 + ImageKit — How does it work?
&lt;/h2&gt;

&lt;p&gt;Let’s look at how a request gets handled when you optimize your S3 images via ImageKit.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;When a request comes to ImageKit, the image is delivered from the CDN cache.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the image is not there in the CDN cache, ImageKit tries to deliver the image from its internal caches. Usually, images that are transformed once will stay in ImageKit’s caches for some time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the image is not found in this internal cache as well, then ImageKit gets the image from your AWS S3 bucket attached to ImageKit, optimizes it, and transforms it in real-time and sends it back to the user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After this first time processing that takes about 200ms on an average, the image gets cached on the CDN and ImageKit’s internal caches, bringing down the response time for almost 98% of image requests to under 50ms.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2X2d-YBc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2A-mp2uRc_vdaaeKTfhHWhzw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2X2d-YBc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2A-mp2uRc_vdaaeKTfhHWhzw.png" alt="The flow of request with ImageKit’s CDN, Processing Server and your AWS S3 storage" width="800" height="150"&gt;&lt;/a&gt;&lt;em&gt;The flow of request with ImageKit’s CDN, Processing Server and your AWS S3 storage&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up ImageKit and AWS S3 for image optimization and resizing
&lt;/h2&gt;

&lt;p&gt;Let’s set up AWS S3 with &lt;a href="https://imagekit.io"&gt;ImageKit&lt;/a&gt; and start delivering optimized images. It will take a few minutes if you follow the steps here.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Creating a new ImageKit account
&lt;/h2&gt;

&lt;p&gt;The first step is to &lt;a href="https://imagekit.io/registration"&gt;create a new ImageKit account&lt;/a&gt; if you have not done so already. You get 20GB free output bandwidth every month forever without adding any credit card details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SfAcrSAh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5580/1%2AbOZto3LH0P7lsxiA25rPjA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SfAcrSAh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5580/1%2AbOZto3LH0P7lsxiA25rPjA.png" alt="A new ImageKit account that has been setup for this demo" width="800" height="430"&gt;&lt;/a&gt;&lt;em&gt;A new ImageKit account that has been setup for this demo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ImageKit has six regions for processing the images. Please select a region that is the same as your S3 bucket or is close to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Creating a new user in AWS
&lt;/h2&gt;

&lt;p&gt;ImageKit only needs a read-only or, more specifically, the GetObject access to your S3 bucket. It is recommended that you create a separate user in AWS for use in ImageKit.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users_create.html"&gt;create a new user&lt;/a&gt; by going to the AWS IAM console. For this demo, we have created a user called imagekit-s3-demo-integration with Programmatic access, i.e. access using keys, enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wOI1uf_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4024/1%2AWNBXfednqE8LfNg5fCssbA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wOI1uf_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4024/1%2AWNBXfednqE8LfNg5fCssbA.png" alt="Creating a new user in AWS IAM console with Programmatic access enabled" width="800" height="472"&gt;&lt;/a&gt;&lt;em&gt;Creating a new user in AWS IAM console with Programmatic access enabled&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You just need to create a new user as of now. Don’t worry about the access you grant to this user. We will be doing that in the next section.&lt;/p&gt;

&lt;p&gt;Once the user is created, copy its access key and secret key as we will use it later to integrate with ImageKit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5zROTK2e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4216/1%2AuDFk8DbbRKyYWZj-RelanA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5zROTK2e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4216/1%2AuDFk8DbbRKyYWZj-RelanA.jpeg" alt="Once the new user is created copy the access key ID and the Secret access key" width="800" height="453"&gt;&lt;/a&gt;&lt;em&gt;Once the new user is created copy the access key ID and the Secret access key&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Assigning access to the bucket
&lt;/h2&gt;

&lt;p&gt;We have a bucket named imagekit-s3-demo-integration for this demo with a couple of images in it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zvPaUhtD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5596/1%2AOgB6kvWGRzvizR9QM2LpVg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zvPaUhtD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5596/1%2AOgB6kvWGRzvizR9QM2LpVg.png" alt="A demo S3 bucket that has been for this guide" width="800" height="339"&gt;&lt;/a&gt;&lt;em&gt;A demo S3 bucket that has been for this guide&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The above bucket is private, but the steps here will be the same, even for a public bucket. We need to provide GetObject access on this bucket to the newly created user.&lt;/p&gt;

&lt;p&gt;a. To do this, click on the “Add Permissions” button for this user. Select “Attach existing policies directly” and then click on “Create Policy.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6YQdWnr3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4596/1%2A8zYFeGX6z0xSd5iSo-UFbg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6YQdWnr3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4596/1%2A8zYFeGX6z0xSd5iSo-UFbg.png" alt="Click on “Add Permissions” for the newly created user to get started" width="800" height="432"&gt;&lt;/a&gt;&lt;em&gt;Click on “Add Permissions” for the newly created user to get started&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RZNvq7Dq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4824/1%2ANJENPsdKCDnpoc6lNoJ0nw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RZNvq7Dq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4824/1%2ANJENPsdKCDnpoc6lNoJ0nw.png" alt="Create a new policy to be attached to this user" width="800" height="230"&gt;&lt;/a&gt;&lt;em&gt;Create a new policy to be attached to this user&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;b. Select the JSON creator option for the policy and use the following JSON to create the policy that provides the GetObject access to our demo bucket. Note, that you need to change the bucket name to that of your bucket.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::imagekit-s3-demo-integration",
                "arn:aws:s3:::imagekit-s3-demo-integration/*"
            ]
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We named our policy ImageKitS3DemoIntegration. Once you save the policy, it looks like this -&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NuYWXuM2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4000/0%2AbhGegmptrYOZiUDi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NuYWXuM2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4000/0%2AbhGegmptrYOZiUDi.png" alt="" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;c. Attach this newly created policy to the user and confirm that the user in IAM panel has this policy attached.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u5ZE6sOE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5704/1%2AObSkTEu3Oxx_SOOe08ALZA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u5ZE6sOE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5704/1%2AObSkTEu3Oxx_SOOe08ALZA.png" alt="Once the policy is attached, this is how the User in IAM panel looks like" width="800" height="353"&gt;&lt;/a&gt;&lt;em&gt;Once the policy is attached, this is how the User in IAM panel looks like&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Adding access in ImageKit
&lt;/h2&gt;

&lt;p&gt;We will now use the access and secret keys for the new user that we created in AWS to enable &lt;a href="https://docs.imagekit.io/integration/configure-origin/amazon-s3-bucket-origin"&gt;ImageKit to access the S3 bucket&lt;/a&gt;. The documentation for the same can also be found here — &lt;a href="https://docs.imagekit.io/integration/configure-origin/amazon-s3-bucket-origin"&gt;Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In ImageKit, go to the Origins section under External Storage and then click on the “Add Origin” button. Change the “Origin type” to “Amazon S3 Bucket” and add the values in the corresponding fields.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qGH4lHGc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5572/1%2An2Gymtd25iZ75Q6-pcDZNg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qGH4lHGc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5572/1%2An2Gymtd25iZ75Q6-pcDZNg.jpeg" alt="" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we save this, if this is the first origin that you added in your ImageKit account, it will automatically get mapped against a URL endpoint. If this does not happen automatically, you can always go to the URL endpoints section and add this new S3 origin in the origin preference sequence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ciQ0hR93--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5580/1%2AP4CFcK1LGoEwRZFIHkeclQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ciQ0hR93--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/5580/1%2AP4CFcK1LGoEwRZFIHkeclQ.jpeg" alt="AWS S3 Bucket gets mapped to the URL Endpoint" width="800" height="433"&gt;&lt;/a&gt;&lt;em&gt;AWS S3 Bucket gets mapped to the URL Endpoint&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s access the optimized image via ImageKit
&lt;/h2&gt;

&lt;p&gt;Our sample bucket has an image at the path monuments/eiffel-tower.jpeg. The image eiffel-tower.jpeg is 938kb initially in size.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VHHOBCXP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4000/0%2APKEPa9gRKwLPWyVs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VHHOBCXP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4000/0%2APKEPa9gRKwLPWyVs.png" alt="" width="800" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As indicated under the URL Endpoint inside your ImageKit dashboard, to access this image using ImageKit, you need to append the URL endpoint from your ImageKit dashboard with the path of the image in the bucket.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[https://ik.imagekit.io/s3demoik/monuments/eiffel-tower.jpeg](https://ik.imagekit.io/s3demoik/monuments/eiffel-tower.jpeg)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And voila!&lt;/p&gt;

&lt;p&gt;Without adding any other parameter to the URL, the image is now down to 583KB in size and is also automatically converted to WebP image format in supported browsers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Oz95ny8B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4564/1%2AXugwHJriLQw2R6rpvcJJkw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Oz95ny8B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4564/1%2AXugwHJriLQw2R6rpvcJJkw.jpeg" alt="Accessing the image via ImageKit optimizes the image and converts it to the right format too" width="800" height="437"&gt;&lt;/a&gt;&lt;em&gt;Accessing the image via ImageKit optimizes the image and converts it to the right format too&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resizing and other transforms on AWS S3 images with ImageKit
&lt;/h2&gt;

&lt;p&gt;Not just automatic optimization, you can also resize and transform the images in your S3 bucket in real-time. You just need to specify the right transformation in your image URL&lt;/p&gt;

&lt;p&gt;Here is the above image resized to a width of 300px -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://ik.imagekit.io/s3demoik/monuments/eiffel-tower.jpeg?tr=w-300
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UW2zILgN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Anjcld9GJLZcdF4tPf_4mfw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UW2zILgN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2Anjcld9GJLZcdF4tPf_4mfw.jpeg" alt="" width="300" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also specify both height and width to get a square thumbnail of this image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://ik.imagekit.io/s3demoik/monuments/eiffel-tower.jpeg?tr=w-300,h-300
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sjsK0wrV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A-FVxJ9FiaajoHqRZdo8BNg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sjsK0wrV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2000/1%2A-FVxJ9FiaajoHqRZdo8BNg.jpeg" alt="" width="300" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are many &lt;a href="https://docs.imagekit.io/features/image-transformations"&gt;other transformations in ImageKit&lt;/a&gt;. All of them can be used with the images in the AWS S3 bucket. You can use the &lt;a href="https://imagekit.io/blog/smart-crop-deliver-perfect-responsive-images/"&gt;smart crop feature&lt;/a&gt; to center the image’s subject in the output thumbnail automatically. Or you could use &lt;a href="https://imagekit.io/blog/how-to-create-a-photo-collage/"&gt;overlays to create dynamic banners&lt;/a&gt;, control how thee image aspect ratio and cropping are handled, and so on.&lt;/p&gt;

&lt;p&gt;Here is a &lt;a href="https://www.youtube.com/watch?v=BlYfugkBfmc"&gt;video demonstrating the use of some of these transformations&lt;/a&gt; on the image.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/BlYfugkBfmc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-time image optimization for AWS S3 without writing any code
&lt;/h2&gt;

&lt;p&gt;And just like that, optimizing and resizing images in your AWS S3 bucket becomes really simple. Easy integration and you start delivering optimized images in minutes.&lt;/p&gt;

&lt;p&gt;If you use some metrics like &lt;a href="https://developers.google.com/web/tools/lighthouse"&gt;Google Lighthouse&lt;/a&gt; to monitor the images on your website, then you would be able to check off all the image-related points from that list using ImageKit with minimal effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started with ImageKit now!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://imagekit.io"&gt;ImageKit&lt;/a&gt; comes with a forever free account that gives you access to all the image optimization and transformation related features for use with your S3 bucket. And you get 20GB free delivery bandwidth every month.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imagekit.io/registration"&gt;Sign up now&lt;/a&gt; and start delivering perfectly optimized images on your websites and apps.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://imagekit.io/blog/image-optimization-resize-aws-s3-imagekit/"&gt;https://imagekit.io&lt;/a&gt; on June 30, 2020.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What is a Content Delivery Network (CDN) — A Beginner’s Guide</title>
      <dc:creator>Rahul Nanwani</dc:creator>
      <pubDate>Thu, 18 Jun 2020 07:25:13 +0000</pubDate>
      <link>https://dev.to/rnanwani/what-is-a-content-delivery-network-cdn-a-beginner-s-guide-24hc</link>
      <guid>https://dev.to/rnanwani/what-is-a-content-delivery-network-cdn-a-beginner-s-guide-24hc</guid>
      <description>&lt;p&gt;A Content Delivery Network, or a CDN as it is commonly called, is an essential part of any modern website and application. The content that you view on your phones today, on any website or app, videos or images, or any other kind of content, is very likely to be delivered using a content delivery network.&lt;/p&gt;

&lt;p&gt;A CDN is also an essential part of our &lt;a href="https://imagekit.io/blog/what-is-image-cdn-guide/"&gt;image CDN&lt;/a&gt; offering at ImageKit. And given the lack of example-led resources for beginners about CDNs on the internet, we decided to write this short guide to help understand what a CDN is and how does it work, using some common scenarios that you would relate with.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a CDN — the theoretical definition
&lt;/h2&gt;

&lt;p&gt;A Content Delivery Network or a CDN is a globally-distributed network of servers that helps provide high-availability, faster performance, and security to websites distributing their content via it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding CDN with an example
&lt;/h2&gt;

&lt;p&gt;One of the most common use case of a &lt;a href="https://en.wikipedia.org/wiki/Content_delivery_network"&gt;CDN&lt;/a&gt; is to improve page load time. Let’s use an e-commerce store as an example to understand how a CDN helps improve page load time.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CiphZWq3ST4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Consider that you run an e-commerce store in the US. You have developed a fantastic website and host it on a server located in a city on the US east coast, let’s say, North Virginia. All the files needed on your website are stored in this server. So, when a user accesses your website, everything that loads on that website comes from this server in North Virginia.&lt;/p&gt;

&lt;p&gt;Now, a user in California, on the west coast, is trying to access the website. For every resource that loads on the website — the textual content, javascript files, stylesheets, and images — a request goes from the user’s device to your servers, where the files are stored. These two locations, the user in California and the server in North Virginia are over 2000 miles apart.&lt;/p&gt;

&lt;p&gt;Negating all the other factors, this distance between the customer and the server is responsible for adding a few hundred milliseconds in load time of a resource. Imagine those extra milliseconds getting added up over hundreds of resources that load on your website, and you end up with a slow page load time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KvxZN4cp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2A-H1qLR9JkD8lTLVVQ-IF4Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KvxZN4cp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2A-H1qLR9JkD8lTLVVQ-IF4Q.png" alt="Greater the geographical distance, higher the latency" width="800" height="286"&gt;&lt;/a&gt;&lt;em&gt;Greater the geographical distance, higher the latency&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And no one likes a slow website. It frustrates your users, hits your sales, and even impacts how you rank on search engines.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does a CDN improve page load time?
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, it is a globally distributed network of servers that store (commonly referred to as “cache”) and deliver some or all of your website’s content. Each of these servers in the CDN’s network is called a Point of Presence (PoP) or an edge server.&lt;/p&gt;

&lt;p&gt;Instead of delivering your website resources directly from your website server, you deliver them via a CDN’s PoPs or edges.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V8w8KKXz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2ArsK1Z3fW_UuJyl70cDCitA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V8w8KKXz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2ArsK1Z3fW_UuJyl70cDCitA.png" alt="CDNs cut down the geographical distance between the user and the content, thereby reducing load time" width="800" height="286"&gt;&lt;/a&gt;&lt;em&gt;CDNs cut down the geographical distance between the user and the content, thereby reducing load time&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the above image, we are using a CDN along with our server in North Virginia. This CDN has PoPs present in multiple locations across the US, including the west coast as well.&lt;/p&gt;

&lt;p&gt;Now, when the user accesses your website, instead of getting the resources from your website server on the east coast, the user gets them from the CDN server that is closer to him on the west coast. Geographically, the user and the CDN server that responds to the user’s request are now just a few miles apart, which reduces the time taken to load the resource significantly.&lt;/p&gt;

&lt;p&gt;The page loads faster, your users are happy, and your sales start looking up.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the other functions of a CDN?
&lt;/h2&gt;

&lt;p&gt;As mentioned earlier, improving load time by delivering your content via a content delivery network is the most common use case for any CDN.&lt;/p&gt;

&lt;p&gt;But there are other use cases as well, some that are implicit to using a CDN and some that are used by slightly larger and technologically advanced organizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Increasing Availability
&lt;/h2&gt;

&lt;p&gt;This is an automatic result of using any CDN.&lt;/p&gt;

&lt;p&gt;For simplicity, availability can be considered a simple measure of how long your website and its functions remain accessible in a given period.&lt;/p&gt;

&lt;p&gt;Usually, when you are serving content from your servers, you need to add more servers as your traffic goes up. If there is an unexpected issue with your server or a database, it could take the application down.&lt;/p&gt;

&lt;p&gt;With a CDN coming into the picture, it does two things. One, a lot of traffic doesn’t even come to your servers. The edge server of the CDN serves a lot of content from its cache. So, you need a slightly fewer number of servers.&lt;/p&gt;

&lt;p&gt;Second, as long as the content is available in the CDNs cache, even if your actual servers are not working, the CDN will keep serving the content. This gives you some buffer time to fix issues on your servers while the CDN serves whatever content it can from its cache.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xXLYpIP9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2A10TmY4ilqb1ssOlVN0b7ug.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xXLYpIP9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2A10TmY4ilqb1ssOlVN0b7ug.jpeg" alt="The CDN delivers content from its own cache while the origin server is down." width="800" height="324"&gt;&lt;/a&gt;&lt;em&gt;The CDN delivers content from its own cache while the origin server is down.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Website Security
&lt;/h2&gt;

&lt;p&gt;This is a more advanced use of CDNs that is generally used by larger companies.&lt;/p&gt;

&lt;p&gt;Since the CDN PoP or edge server is now the first layer in the system which accepts incoming traffic, it also becomes the first line of &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Website_security"&gt;defence against attacks on your website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, if a CDN can isolate bad traffic from good traffic, it can stop all the bad traffic from coming to your servers. Your servers only respond to the “good” requests coming from actual users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H7HJtthJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2AsltVcnLdgyY9s5xjUJRC7w.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H7HJtthJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2AsltVcnLdgyY9s5xjUJRC7w.jpeg" alt="CDN blocks the request from a malicious user while serving good requests as usual" width="800" height="84"&gt;&lt;/a&gt;&lt;em&gt;CDN blocks the request from a malicious user while serving good requests as usual&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Website security is a very vast topic in itself and beyond the scope of this blog. But, there are certain features like blocking access on non-HTTP ports, which are a standard feature in all CDNs, and help provide basic security. Such features are accessible to everyone.&lt;/p&gt;

&lt;p&gt;Then there are more advanced features like Bot Protection, Web Application Firewall (WAF), DDoS protection, etc. that are available as add-ons in certain CDNs. Such add-ons are usually expensive, and configuring them takes time and effort too. Therefore, they are used by a select few companies who face such challenges and can afford to deploy more expensive customized solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What kind of content can be delivered through a CDN?
&lt;/h2&gt;

&lt;p&gt;Theoretically, you can use a CDN to cache and deliver your entire website. How long can you cache it on the CDN, or can you or should you cache it at all, depends on the type of content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s look at an example.
&lt;/h2&gt;

&lt;p&gt;If you are selling Nike shoes on your website, and two users are looking at that product page — the first is a male from California, and the second is a female from New York.&lt;/p&gt;

&lt;p&gt;It’s a black running shoe, and both see the same image for the product.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--toWhAg_r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2APMP1RfvkTjBjpSTy3NbbNA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--toWhAg_r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2918/1%2APMP1RfvkTjBjpSTy3NbbNA.png" alt="All users see the same product image on the website" width="800" height="287"&gt;&lt;/a&gt;&lt;em&gt;All users see the same product image on the website&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Such content that does not change on a per-user basis is a great candidate for serving from the CDN cache. Had you been using your server directly, that server would have also sent out the same image. Content like this image, that does not change or remains “static” for users is called static content. Javascript, which affects the interactions on your website, and the CSS, which affects how your website looks, also remains the same for all users and are also classified as static content.&lt;/p&gt;

&lt;p&gt;But your website can have different discounts or shipping rates for different regions within the country. You might want to tune product recommendations differently for your male and female audience. Or you may have an offer that is valid for only the next hour in New York. So, the actual website content, the text, the offers, and the APIs that get the product recommendations can vary for the two users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6PfPrSSm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2800/1%2A10XNjU3SQ9WHrvjbsEtt0g.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6PfPrSSm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2800/1%2A10XNjU3SQ9WHrvjbsEtt0g.jpeg" alt="The image remains the same but different offers are presented to each user" width="800" height="299"&gt;&lt;/a&gt;&lt;em&gt;The image remains the same but different offers are presented to each user&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Such content is called dynamic content. It can change on a per-user basis (like recommendations), location-basis (discounts and shipping), or on a time-basis (like a discount that is available till midnight). It becomes difficult, if not impossible, to have such content stored in a CDN’s cache for a long time. Imagine an offer that was supposed to expire at 1 pm, continues to be stored and delivered from the CDN server till 3 pm. This would only result in confusion for your users and a drop in sales.&lt;/p&gt;

&lt;p&gt;Maybe you can keep shipping rates cached for some hours on the CDN because they don’t change very often. However, content like recommendations for a user is likely to change frequently as the user navigates through other products, making it non-cacheable. And if you cannot store it on the CDN, then should you be using a CDN for such content at all.&lt;/p&gt;

&lt;p&gt;Note: This is a simple example. There are certain cases, as a breaking news item on a high-traffic news website, where even a short cache time of 1 or 2 minutes can be useful for reducing the stress on servers while accelerating content delivery. A lot of websites do that in practice. Plus, CDNs can still act as the first layer of security, and therefore it makes sense to use it even if you are not caching any content on them.&lt;/p&gt;

&lt;p&gt;The most common use case of a CDN is to cache content and deliver it to the end-user, reducing the page load time. This means that the content should be cached on the CDN edge as long as possible. The longer it stays, the longer you get the benefit of the fast load time. &lt;a href="https://developers.google.com/speed/pagespeed"&gt;Google PageSpeed&lt;/a&gt;, for example, penalizes you for not using a long cache time for your static content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j-zSqjwB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4000/1%2AzMDxxhWb5NyDCll6FCQZwg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j-zSqjwB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/4000/1%2AzMDxxhWb5NyDCll6FCQZwg.png" alt="PageSpeed giving a warning related to Cache Policy" width="800" height="399"&gt;&lt;/a&gt;&lt;em&gt;PageSpeed giving a warning related to Cache Policy&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;However, you should be able to control how long the content stays on the CDN and how do you force it to refresh if the content on your server has changed.&lt;/p&gt;

&lt;p&gt;For example, your CDN has stored, on its edge servers, a copy of the black Nike running shoe that we talked about earlier. Even if you change the image on your origin server, the file cached on the CDN won’t change automatically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L_C4KWKr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2754/1%2APKdBF91madf8k7gjCn6DcA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L_C4KWKr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://cdn-images-1.medium.com/max/2754/1%2APKdBF91madf8k7gjCn6DcA.jpeg" alt="For the same product image, the CDN cache has a different version than the origin server. The user keeps getting the image from the CDN cache." width="800" height="335"&gt;&lt;/a&gt;&lt;em&gt;For the same product image, the CDN cache has a different version than the origin server. The user keeps getting the image from the CDN cache.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are some standard cache control headers and best practices for updating your resources (and their URLs), which, when combined, ensure that the content on the CDN remains up-to-date and in sync with the updates on your servers. These techniques have been discussed in detail in this guide — &lt;a href="https://imagekit.io/blog/ultimate-guide-to-http-caching-for-static-assets/"&gt;The Ultimate Guide To Caching Static Assets&lt;/a&gt; and would require some technical know-how about HTTP requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;This guide was intended to give you a gentle introduction of what a CDN is and how does it work. It was intentionally built as a light read, avoiding the technical jargon associated with Content Delivery Networks as much as possible.&lt;/p&gt;

&lt;p&gt;We would ourselves follow this up with a more detailed, technical guide on how CDNs work. You are now equipped to go out on the internet and dive deeper into the functioning of a CDN.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://imagekit.io/blog/what-is-content-delivery-network-cdn-guide"&gt;https://imagekit.io&lt;/a&gt; on June 9, 2020.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What is an Image CDN - The Complete Guide</title>
      <dc:creator>Rahul Nanwani</dc:creator>
      <pubDate>Wed, 10 Jun 2020 04:27:22 +0000</pubDate>
      <link>https://dev.to/rnanwani/what-is-an-image-cdn-the-complete-guide-1be7</link>
      <guid>https://dev.to/rnanwani/what-is-an-image-cdn-the-complete-guide-1be7</guid>
      <description>&lt;p&gt;If you are reading this guide, you are probably trying to learn more about an image CDN, and how does it work. Or you are a bit further down the line ‚ trying to evaluate what an image CDN should do or understanding the essential features of an image CDN that can help you with faster page load time, better image delivery, improved SEO, and simpler integration.&lt;/p&gt;

&lt;p&gt;You have come to the right place!&lt;/p&gt;

&lt;p&gt;This guide not only covers the basics but also includes why a particular feature is essential for an image CDN. Having this understanding would enable you to map your requirements to what an image CDN offers.&lt;/p&gt;

&lt;p&gt;Let's quickly get started. We take a quick look at a regular content delivery network (CDN) and then gradually move on to the specifics of an image CDN.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Content Delivery Network (CDN), in general
&lt;/h2&gt;

&lt;p&gt;A Content Delivery Network forms the basis of what we will cover in the rest of this guide. Let's understand how it works with an example.&lt;/p&gt;

&lt;p&gt;Consider that you run an e-commerce store in the US hosted on a server located in a city on the US east coast, let's say, North Virginia. So, when a user accesses your website, everything that loads on that website comes from this server in North Virginia.&lt;/p&gt;

&lt;p&gt;But, your users access it from across all of the United States. And maybe even in other countries, which means that they could be a few thousand miles away from your server. And, the farther they are, the longer it would take for the content to get transferred from your server to their devices. Your users get frustrated because of the slow website and drop off without converting to a paid customer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2A-H1qLR9JkD8lTLVVQ-IF4Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2A-H1qLR9JkD8lTLVVQ-IF4Q.png" alt="Users geographically far away from the origin server experience slow load time"&gt;&lt;/a&gt;&lt;em&gt;Users geographically far away from the origin server experience slow load time&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is where a &lt;a href="https://en.wikipedia.org/wiki/Content_delivery_network" rel="noopener noreferrer"&gt;Content Delivery Network&lt;/a&gt; comes into the picture. While your server sits in one location, a CDN consists of globally distributed servers that can store your website's content (or commonly referred to as "cache" your website's content) and deliver it to your users. So now, if users sitting in California access your website, instead of downloading the content from North Virginia, they can get it from one of the servers of the CDN, a few miles from their location. Shorter distance, super-fast load time, happier users, and more sales for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2ArsK1Z3fW_UuJyl70cDCitA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2ArsK1Z3fW_UuJyl70cDCitA.png" alt="With a CDN the geographical distance, and hence the load time, decreases"&gt;&lt;/a&gt;&lt;em&gt;With a CDN the geographical distance, and hence the load time, decreases&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you want to read more about how a general CDN works, we have written a separate guide that gives you a gentle introduction to the same. You can access it from here - &lt;a href="https://imagekit.io/blog/what-is-content-delivery-network-cdn-guide/" rel="noopener noreferrer"&gt;Content Delivery Network - A Beginner's Guide&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is an image CDN?
&lt;/h2&gt;

&lt;p&gt;Images present a slightly complicated case when it comes to delivering the perfect variation on each device using a CDN. You need to consider the image format, image dimensions, image compression, aspect ratio, and a lot more, while balancing the image's visual quality. Therefore, we need to have a CDN tuned for image delivery.&lt;/p&gt;

&lt;p&gt;An image CDN is a regular content delivery network topped with a set of software enhancements to enhance the underlying CDNs functionality for optimizing and transforming images in real-time, thereby making it more suitable for image delivery.&lt;/p&gt;

&lt;p&gt;This is the most important thing to understand about all the image CDNs out there. They are not an entirely different content delivery network; they are built on top of existing ones with software enhancements required for image optimization.&lt;/p&gt;

&lt;p&gt;Let's look at different parts of the process to understand how are image CDNs built. There are three of them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Delivery
&lt;/h3&gt;

&lt;p&gt;Delivery means how does an image actually gets to the user's device and how quickly we can get it there. This is done using the Content Delivery Networks we talked about earlier.&lt;/p&gt;

&lt;p&gt;There are already massive, well-performing general content delivery networks out there. They have their network spread across hundreds of countries, already tuned for fast load times. Some of the leading ones are AWS &lt;a href="https://aws.amazon.com/cloudfront/features/" rel="noopener noreferrer"&gt;CloudFront&lt;/a&gt;, Akamai, and Fastly.&lt;/p&gt;

&lt;p&gt;Almost all good image CDNs would offer one of these leading CDN providers as a part of their service. Eventually, it is this underlying Content Delivery Network that is responsible for delivering the images to the users.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Processing
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, we need to add to the content delivery network the unique functionality required for &lt;a href="https://imagekit.io/blog/how-to-manage-image-heavy-website/" rel="noopener noreferrer"&gt;modifying and optimizing the images&lt;/a&gt;. This processing functionality would allow you to resize images, crop them, watermark them, and apply visual effects to them.&lt;/p&gt;

&lt;p&gt;This functionality is performed via dedicated "processing servers," which are separate from the servers in the content delivery network. The processing servers are the ones doing the heavy lifting in the image CDN setup. These would always be far fewer in number than the servers in a content delivery network and localized in a few regions.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Storage
&lt;/h3&gt;

&lt;p&gt;Now, this is a part that may vary across different image CDNs.&lt;/p&gt;

&lt;p&gt;A good image CDN should be able to deliver all the image optimizations and transformations on any image, even the ones that are outside of the image CDN's system.&lt;/p&gt;

&lt;p&gt;But, the leading ones take it a step further. They come with a storage or a media library for users to upload and manage their images. These uploaded images can be accessed via the CDN, and can be processed by the processing part of the image CDN. This media library makes it simple to get started with using the service apart from simplifying image upload and management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4000%2F1%2AomsjQ1haDfc1sqIUsglTjQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4000%2F1%2AomsjQ1haDfc1sqIUsglTjQ.jpeg" alt="Media Library in ImageKit.io"&gt;&lt;/a&gt;&lt;em&gt;Media Library in ImageKit.io&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The overall structure
&lt;/h3&gt;

&lt;p&gt;Let's look at ImageKit.io, which is an &lt;a href="https://imagekit.io" rel="noopener noreferrer"&gt;image CDN&lt;/a&gt;, as an example. It comes with an image storage called the &lt;a href="https://imagekit.io/features/imagekit-media-library-storage" rel="noopener noreferrer"&gt;Media Library&lt;/a&gt; (the "Storage" part). The bundled CDN is AWS CloudFront (the "Delivery" part), an extensive, general content delivery network with over 200 delivery nodes worldwide. The image &lt;a href="https://imagekit.io/blog/imagekit-io-distributed-core-processing-regions-advantages/" rel="noopener noreferrer"&gt;processing servers are present in 6 regions&lt;/a&gt; across the globe (the "Processing" part).&lt;/p&gt;

&lt;p&gt;Here is how the structure looks like when we combine the three components mentioned above&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2A2hWBNyanNXtqeiB3YWbdvQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2A2hWBNyanNXtqeiB3YWbdvQ.png" alt="The three components of an Image CDN, taking ImageKit.io as an example"&gt;&lt;/a&gt;&lt;em&gt;The three components of an Image CDN, taking ImageKit.io as an example&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The combination of these three different components collectively makes an image CDN.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does an image CDN work?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2A-mp2uRc_vdaaeKTfhHWhzw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2A-mp2uRc_vdaaeKTfhHWhzw.png" alt="The flow of a user request and response in an Image CDN (CDN + Processing Server + Storage = Image CDN)"&gt;&lt;/a&gt;&lt;em&gt;The flow of a user request and response in an Image CDN (CDN + Processing Server + Storage = Image CDN)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now that we know that an image CDN is a combination of three distinct elements, let's see how do these come together to deliver the intended functionality.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;When a user requests an image, it first goes to the delivery part of the image CDN, i.e., the underlying general CDN.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the CDN does not have the image cached on its servers, it goes to the processing servers requesting the same.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The processing server then has two ways of fulfilling the request. Usually, it first attempts to send back an existing copy of the image that is requested.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If that is not possible for any reason, the processing server gets the original image from the storage. It can come integrated with the image CDN as shown above (like the Media Library in ImageKit), or it may be some external image storage. The server then does all the optimizations and transformations requested on the image in real-time and sends it back to the CDN. It also stores a copy of this processed image for subsequent requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The CDN delivers the image to the user and also caches it on its servers for subsequent requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next time a request comes for the same image, the CDN would deliver it from its cache.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There might be some variations in the above steps that would vary across different image CDN services, but on a high-level, all image CDNs work in the same way.&lt;/p&gt;

&lt;p&gt;**Note: **Regardless of the setup, an image CDN should be able to modify images in real-time. There are a few other services that let you do a one-time image processing and store them in some storage for you to use later, but, for the context of this article, and even otherwise, those are not image CDNs. They are great for a simple, one-time use case, but lag significantly in terms of functionality compared to real-time image CDNs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important infrastructure-level features of an image CDN
&lt;/h2&gt;

&lt;p&gt;We have now covered how an image CDN is set up, and how does it work.&lt;/p&gt;

&lt;p&gt;We now need to look at the features of an image CDN that will be help you deliver perfect images on your websites and apps with minimum effort.&lt;/p&gt;

&lt;p&gt;Let's first look at some of the essential infrastructure-level features of an image CDN.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Integration with existing storages and servers
&lt;/h3&gt;

&lt;p&gt;This is by far the most crucial feature that you should be looking for in an image CDN - more than any other infrastructure-level feature.&lt;/p&gt;

&lt;p&gt;If you have been running a website for some time, you would already have quite a lot of images being used and stored in a particular location on your server or a storage service like AWS S3. Your processes to upload images to your storage, your content management systems, and your teams using it are also set and mature by that time.&lt;/p&gt;

&lt;p&gt;Very often, in this scenario, all that you are looking for is a service that can just &lt;a href="https://docs.imagekit.io/integration/integration-overview" rel="noopener noreferrer"&gt;integrate with your existing systems&lt;/a&gt; and help you deliver optimized and resized images across devices. You do not want to opt for an image CDN where you have to move all your images to a designated storage to use its features. Or make tons of changes to your content management systems just to integrate it with your process.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Choice of the CDN (Bonus: Third-party CDN integrations)
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, building your delivery network is a non-trivial task. Most image CDNs would rely on an established Content Delivery Network for the final image delivery.&lt;/p&gt;

&lt;p&gt;Therefore, the first thing one should look for when evaluating an image CDN is the content delivery network used to serve the images. Good image CDNs are built on the best general CDNs available out there - Amazon CloudFront, Akamai, Fastly, &lt;a href="https://cloud.google.com/cdn/" rel="noopener noreferrer"&gt;Google CDN&lt;/a&gt;, among others. These CDNs would ensure that you get the fastest possible content delivery across the globe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus:&lt;/strong&gt; Heavy users, those running a website with several million page views every month, might have their preferred CDN. This preference could be because of contractual obligations, use cases, or the strength of a particular CDN in the region they operate. In either case, the image CDN should allow integration with other CDNs apart from the one that comes bundled with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Location of the image processing regions
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, the processing part of the image CDN is different from its delivery part. The &lt;a href="https://imagekit.io/blog/imagekit-io-distributed-core-processing-regions-advantages/" rel="noopener noreferrer"&gt;processing servers&lt;/a&gt; are far fewer in number as compared to the delivery nodes of the underlying CDN and are present in a few geographical regions.&lt;/p&gt;

&lt;p&gt;If you are using the image CDN with your storage or server, there is some time (a few milliseconds) that is needed to get the image from your storage to the image CDNs processing server. The shorter this distance geographically, the shorter this time to retrieve the original image and hence faster the image load. Similarly, any image request that is not delivered from the CDN cache goes the processing server for retrieval or fresh processing. The higher the distance between the CDN cache and the processing server, the higher the time for fulfilling this request.&lt;/p&gt;

&lt;p&gt;Therefore, you should opt for image CDNs that can provide processing regions close to either your end-users or your existing infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. HTTPS and HTTP/2 (Bonus - With Custom Domain Names)
&lt;/h3&gt;

&lt;p&gt;HTTPS is a protocol for securely transmitting data from a user's browser and the website's server. Google, the biggest search engine in the world, has always maintained that HTTPS-enabled websites get a &lt;a href="https://webmasters.googleblog.com/2014/08/https-as-ranking-signal.html" rel="noopener noreferrer"&gt;ranking boost in search results&lt;/a&gt;. Modern browsers like Chrome, also give subtle preferences to secure websites.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2AG1BiOMP--tsstBMxNxWsdg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2AG1BiOMP--tsstBMxNxWsdg.png" alt="Google uses a padlock in the address bar to indicate secure websites"&gt;&lt;/a&gt;&lt;em&gt;Google uses a padlock in the address bar to indicate secure websites&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imagekit.io/blog/http2-vs-http1-performance/" rel="noopener noreferrer"&gt;HTTP/2&lt;/a&gt;, on the other hand, is an upgrade to HTTP/1.1 protocol, that allows for faster data transfer and page load. A faster page load time not just improves the user experience but is of great importance for SEO as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2ACfdkGCKoG4axFMahvBCccQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2ACfdkGCKoG4axFMahvBCccQ.png" alt="HTTP/2 on the left with all requests getting fired in parallel. HTTP/1.1 limiting the requests in parallel. Source: [https://imagekit.io/blog/http2-vs-http1-performance/](https://imagekit.io/blog/http2-vs-http1-performance/)"&gt;&lt;/a&gt;&lt;em&gt;HTTP/2 on the left with all requests getting fired in parallel. HTTP/1.1 limiting the requests in parallel. Source: &lt;a href="https://imagekit.io/blog/http2-vs-http1-performance/" rel="noopener noreferrer"&gt;https://imagekit.io/blog/http2-vs-http1-performance/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Given the importance of HTTPS and HTTP/2 for securing websites, SEO, and faster page loads, your image CDN should support them, without fail.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom Domain Names:&lt;/strong&gt; While most third-party image CDNs do support these out of the box, providing them over custom domain names like images.yourwebsite.com, is often not supported or is an expensive add-on. While the importance of custom domain names for SEO is debatable, they do help to white-label the image CDN and present the image URLs as if they are coming from your service, instead of a third-party. You should look for an image CDN provider with inexpensive &lt;a href="https://imagekit.io/features/imagekit-custom-cdn-integrations" rel="noopener noreferrer"&gt;custom domain name integrations&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Availability of an integrated media library
&lt;/h3&gt;

&lt;p&gt;Unlike the first three points, this might be non-essential in most cases. But, used correctly, it can prove to be a great add-on or help you completely overhaul your image management systems and make them more efficient.&lt;/p&gt;

&lt;p&gt;In companies with large fragmented teams and multiple stakeholders working on the images that go on a website or an app, having a central media library for storing, searching, and managing images can prove to be useful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4000%2F1%2ABVnHZBrdf1PBS0UZ9UHrIw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4000%2F1%2ABVnHZBrdf1PBS0UZ9UHrIw.jpeg" alt="Media Library with Search and image uploads"&gt;&lt;/a&gt;&lt;em&gt;Media Library with Search and image uploads&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the previous section, we looked at the essential features of an image CDN from an infrastructure perspective.&lt;/p&gt;

&lt;h2&gt;
  
  
  Image-related features of an image CDN
&lt;/h2&gt;

&lt;p&gt;We now get to the actual optimization and transformation capabilities that you should look for in an image CDN - the processing part. While the infrastructure helps you accelerate delivery, the processing features help you adapt the image to your requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Automatic format optimization including WebP support
&lt;/h3&gt;

&lt;p&gt;We have already talked about this earlier - different image formats are suitable for different kinds of use cases. For example, while JPG is excellent for photograph-like images, PNGs are suitable for graphics and logos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ADSHAiLudWXqZ-8LM" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ADSHAiLudWXqZ-8LM" alt="Always JPG image"&gt;&lt;/a&gt;&lt;em&gt;Always JPG image&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AOW6bTkMAhpqYlstV" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AOW6bTkMAhpqYlstV" alt="WebP or JPG image (depending on browser support). Image by [Fabian](https://www.pexels.com/photo/seaside-994605/)"&gt;&lt;/a&gt;&lt;em&gt;WebP or JPG image (depending on browser support). Image by &lt;a href="https://www.pexels.com/photo/seaside-994605/" rel="noopener noreferrer"&gt;Fabian&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Good image CDNs should be able to convert your images to the &lt;a href="https://imagekit.io/blog/automatic-best-image-format-selection/" rel="noopener noreferrer"&gt;correct image format&lt;/a&gt;, automatically taking into account factors like browser support and original image content.&lt;/p&gt;

&lt;p&gt;Do note that, most image CDNs would just default to converting every image to WebP, whenever possible. However, there are a few cases, like the one illustrated below, where a lossy-compressed PNG is smaller than the WebP variant and looks the same. Therefore, image format optimization should not be just about converting the image to WebP but about converting it to the "right" format for that particular image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2Ay27ny1kwmcWa2bP4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2Ay27ny1kwmcWa2bP4.png" alt="This logo image is always in PNG even in WebP-supported browsers (1.6KB), as it is smaller than WebP (2.1KB)"&gt;&lt;/a&gt;&lt;em&gt;This logo image is always in PNG even in WebP-supported browsers (1.6KB), as it is smaller than WebP (2.1KB)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Controllable image compression (Bonus: Network-based image compression)
&lt;/h3&gt;

&lt;p&gt;The next step in image optimization is compression. And while lossy compression does lead to visual degradation, if done correctly and up to a certain level, the human eye is not able to perceive those visual differences.&lt;/p&gt;

&lt;p&gt;For example, the two images below at different quality levels look nearly identical, though the one that is compressed is almost one-fifth in terms of byte size.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AS2J16FlJIFuht52V" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AS2J16FlJIFuht52V" alt="At Quality 100, JPG image 107KB"&gt;&lt;/a&gt;&lt;em&gt;At Quality 100, JPG image 107KB&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AYSeeeo29UYFVDtov" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2AYSeeeo29UYFVDtov" alt="At Quality 90, JPG image 20.3KB. Image by [Fabian](https://www.pexels.com/photo/seaside-994605/)"&gt;&lt;/a&gt;&lt;em&gt;At Quality 90, JPG image 20.3KB. Image by &lt;a href="https://www.pexels.com/photo/seaside-994605/" rel="noopener noreferrer"&gt;Fabian&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Different kinds of businesses have different quality requirements. For example, an e-commerce business selling clothes with a fine texture would prefer to deliver images at a higher quality because the visual quality of those details is what would help sell the product. On the other hand, news and content websites can get away with slightly lower quality for photographs. Or there might be individual sections of the website, like the part where you present a zoomed-in image, where you need a higher quality image. Therefore, the quality level or the compression should be controllable on a per-URL basis.&lt;/p&gt;

&lt;p&gt;**Bonus: **Mobile network connections are still flaky. The download speed on a user's device can vary. To provide a seamless experience to users on different network speeds, a right image CDN should &lt;a href="https://imagekit.io/blog/network-based-image-optimization-and-role-of-service-workers/" rel="noopener noreferrer"&gt;adapt the image compression to different network levels&lt;/a&gt;. A more compressed, lighter image can download faster on a slow user's device resulting in improved user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Real-time transformations for responsive images
&lt;/h3&gt;

&lt;p&gt;Any image CDN should come with fundamental image transformations like resizing, cropping (with different crop modes), DPR variation, and aspect ratio modification. These transformations, combined with specifications like responsive image tags, &lt;a href="https://imagekit.io/blog/lighter-automatic-responsive-images-client-hints/" rel="noopener noreferrer"&gt;Client Hints&lt;/a&gt; (though an outgoing spec), or client-side javascript, help adapt the images for that particular device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2AoVDxH2IloRKSBATLxkFDoQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2918%2F1%2AoVDxH2IloRKSBATLxkFDoQ.png" alt="Varying layout across devices requires different image sizes"&gt;&lt;/a&gt;&lt;em&gt;Varying layout across devices requires different image sizes&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus: Smart cropping of images&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When transforming images for smaller sizes, cropping usually becomes unavoidable. If the subject of the image is not in the center, it can get cropped out of the thumbnail. An image CDN that provides &lt;a href="https://imagekit.io/blog/smart-crop-deliver-perfect-responsive-images/" rel="noopener noreferrer"&gt;smart crop&lt;/a&gt; (not just face crop, but identifies other important elements of the image), helps you overcome this problem.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4664%2F1%2AVGaNwz2CGKpjyQy7Yo2JeQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4664%2F1%2AVGaNwz2CGKpjyQy7Yo2JeQ.jpeg" alt="From left to right - the original image, center cropped, and smart cropped image. Smart cropping gives a much better result."&gt;&lt;/a&gt;&lt;em&gt;From left to right - the original image, center cropped, and smart cropped image. Smart cropping gives a much better result.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Support for complex transformations and compressions
&lt;/h3&gt;

&lt;p&gt;Just simple resize and crop transformations may not be enough for adapting your images for web and mobile. For example, you might want to overlay an image with your brand's logo in the top-right corner. With hundreds of thousands of images in your product catalog, it can be quite a task if you were to do it manually. Thus, it is a feature that you should look for in an image CDN.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2Atm5MX5MjWGksTCw6" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2Atm5MX5MjWGksTCw6" alt="Image with watermark added on the top dynamically using the image URL. [URL here](https://ik.imagekit.io/demo/img/beach_photo_wuC6hiv0Uy.jpeg?tr=w-600:oi-logo-dark.png,ox-N10,oy-10,f-png)."&gt;&lt;/a&gt;&lt;em&gt;Image with watermark added on the top dynamically using the image URL. &lt;a href="https://ik.imagekit.io/demo/img/beach_photo_wuC6hiv0Uy.jpeg?tr=w-600:oi-logo-dark.png,ox-N10,oy-10,f-png" rel="noopener noreferrer"&gt;URL here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Overlays should not be just for watermarking, but good image CDNs would even provide you with &lt;a href="https://docs.imagekit.io/features/image-transformations/overlay#text-overlay" rel="noopener noreferrer"&gt;text overlays&lt;/a&gt;. One can combine them with other &lt;a href="https://docs.imagekit.io/features/image-transformations" rel="noopener noreferrer"&gt;image transformations&lt;/a&gt; like background modification to convert your images into personalized banners for your users. You can use these personalized banners for sending targeted emails, or on the website to help boost your conversion rates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ANONelO144WOBo2RW" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F0%2ANONelO144WOBo2RW" alt="Image with text added and styled dynamically directly from the image URL. [URL here](https://ik.imagekit.io/demo/img/beach_photo_wuC6hiv0Uy.jpeg?tr=w-600,f-png:ot-This%20is%20a%20beautiful%20beach,otp-10-20,otbg-00000080,otc-FFFFFF,ots-24,oy-N10)."&gt;&lt;/a&gt;&lt;em&gt;Image with text added and styled dynamically directly from the image URL. &lt;a href="https://ik.imagekit.io/demo/img/beach_photo_wuC6hiv0Uy.jpeg?tr=w-600,f-png:ot-This%20is%20a%20beautiful%20beach,otp-10-20,otbg-00000080,otc-FFFFFF,ots-24,oy-N10" rel="noopener noreferrer"&gt;URL here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In addition to the above examples, features like progressive images, &lt;a href="https://imagekit.io/blog/what-and-why-brotli-compression/" rel="noopener noreferrer"&gt;Brotli compression&lt;/a&gt; for text-based image formats like SVG, support for conversion to animated WebP, are some of the other advanced features that can be useful in an image CDN.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. URL usability and security
&lt;/h3&gt;

&lt;p&gt;Real-time image transformations are fantastic. Just change a parameter, and you get a new image that fits your requirement perfectly. But this capability is like a double-edged sword.&lt;/p&gt;

&lt;p&gt;While it makes it easier for someone to create a new image variant, it can pose problems for your technology team and make the URLs prone to plagiarism.&lt;/p&gt;

&lt;p&gt;For example,&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;a. Usability *&lt;/em&gt;- It becomes difficult for your technology team to remember the transformations that need to be applied to an image to adapt it to different parts of the website. For transforming an image to 400x300 size with a watermark, what is the exact transformation string? There should be a more &lt;a href="https://imagekit.io/blog/how-to-use-named-transformations-for-better-code-readability-and-maintenance/" rel="noopener noreferrer"&gt;natural way to refer to these transformations&lt;/a&gt; so that your development team can speak a common language.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;b. Security *&lt;/em&gt;- The transformation parameters can be removed or changed. Any unauthorized entity would then be able to access your original images, or download a modified variant and use it themselves. The image CDN should, therefore, come with features like URL-modification prevention, allowing access to only specific transformations, URLs with time-based expiry, and others to &lt;a href="https://imagekit.io/blog/reduce-unauthorised-use-image-urls/" rel="noopener noreferrer"&gt;reduce the unauthorized use of your image URLs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. SDKs and Support
&lt;/h3&gt;

&lt;p&gt;While this may not seem to be directly related to images, but excellent technical support and SDKs for use with different frameworks and platforms can provide a significant boost to your image optimization efforts.&lt;/p&gt;

&lt;p&gt;The reason for this is that image optimization is essential, yet using an image CDN to its full potential and adopting the best practices related to image-loading is non-trivial.&lt;/p&gt;

&lt;p&gt;You need your image CDN to be able to provide you with reliable technical advice, guides, and solid SDKs to make it simpler to implement the best practices in your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identifying improvement areas for images on your website
&lt;/h2&gt;

&lt;p&gt;We have now covered most of the image CDN and the different features that come along with it that can be useful for you. But do you need one? How is the current state of images on your website? And if it is terrible, then what are the areas that you should be looking to improve first?&lt;/p&gt;

&lt;p&gt;The following tools can help you answer this question.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Google PageSpeed Insights
&lt;/h3&gt;

&lt;p&gt;Built on top of &lt;a href="https://developers.google.com/web/tools/lighthouse" rel="noopener noreferrer"&gt;Lighthouse&lt;/a&gt;, the new industry-standard performance measurement tool, PageSpeed insights, gives you a complete report of your desktop and mobile web page performance.&lt;/p&gt;

&lt;p&gt;Within that detailed report, five parameters are related to image delivery and optimization - &lt;a href="https://developers.google.com/web/tools/lighthouse/audits/offscreen-images" rel="noopener noreferrer"&gt;offscreen images&lt;/a&gt;, &lt;a href="https://developers.google.com/web/tools/lighthouse/audits/optimize-images" rel="noopener noreferrer"&gt;optimize images&lt;/a&gt;, &lt;a href="https://developers.google.com/web/tools/lighthouse/audits/oversized-images" rel="noopener noreferrer"&gt;properly size images&lt;/a&gt;, &lt;a href="https://developers.google.com/web/tools/lighthouse/audits/webp" rel="noopener noreferrer"&gt;images in next-gen formats&lt;/a&gt;, and &lt;a href="https://developers.google.com/web/tools/lighthouse/audits/cache-policy" rel="noopener noreferrer"&gt;efficient cache-control&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4308%2F1%2APdgd_JmoiBcc3p8bqO02Mw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4308%2F1%2APdgd_JmoiBcc3p8bqO02Mw.png" alt="PageSpeed Insights report of ImageKit.io"&gt;&lt;/a&gt;&lt;em&gt;PageSpeed Insights report of ImageKit.io&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. ImageKit's Website Analyzer and Performance Center
&lt;/h3&gt;

&lt;p&gt;ImageKit is a complete image CDN that comes with two tools to help you understand and solve image optimization related problems. The &lt;a href="https://imagekit.io/website-analyzer" rel="noopener noreferrer"&gt;website analyzer&lt;/a&gt; provides you with a complete report for a single image URL on both desktop and mobile, providing you with an image-by-image detailed report of how that particular image can be optimized.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4972%2F1%2Ami_xXZ7u5gLbN7DhkTRAzg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4972%2F1%2Ami_xXZ7u5gLbN7DhkTRAzg.png" alt="ImageKit Website Analyzer with an image-by-image report for optimizing your images"&gt;&lt;/a&gt;&lt;em&gt;ImageKit Website Analyzer with an image-by-image report for optimizing your images&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.imagekit.io/features/performance-monitoring" rel="noopener noreferrer"&gt;Performance Center&lt;/a&gt;, though available only to the paid users of ImageKit.io, takes the website analyzer report a step further. It automatically analyzes the critical pages on your website for image optimization every day. It then presents a visual trend specifically for the size and scope of optimization for the images on your website. This trend helps your team to stay on top of image optimization and delivery as you release new pages and layout variations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4000%2F1%2A2iZIH9EWYt-w9FD2XXGjyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F4000%2F1%2A2iZIH9EWYt-w9FD2XXGjyw.png" alt="The Performance Center shows that the image payload has gone up around Dec 25."&gt;&lt;/a&gt;&lt;em&gt;The Performance Center shows that the image payload has gone up around Dec 25.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping it Up
&lt;/h2&gt;

&lt;p&gt;Images are an essential part of all websites and apps - not just in terms of visual presentation but also in terms of the size that good quality images take on a website. Optimizing them, therefore, should be the number one priority for any website or app owner, who wants to deliver a great experience to the users.&lt;/p&gt;

&lt;p&gt;And selecting the right &lt;a href="https://imagekit.io" rel="noopener noreferrer"&gt;image CDN&lt;/a&gt; that integrates well with your existing setup and provides the essential transformation capabilities, makes it simple to deliver perfect images across devices.&lt;/p&gt;

&lt;p&gt;One such image CDN is &lt;a href="https://imagekit.io" rel="noopener noreferrer"&gt;ImageKit.io&lt;/a&gt;. It automatically optimizes your images to the right format and compression level and comes with tons of transformations to deliver the perfect image. It comes with AWS CloudFront and a media library built-in. Plus, you are in good company as over 15,000 companies and developers use it in 40+ countries. There is a generous &lt;a href="https://imagekit.io/plans" rel="noopener noreferrer"&gt;free plan&lt;/a&gt; that gives you up to 20GB of bandwidth, absolutely FREE, every month!&lt;/p&gt;

&lt;p&gt;Don't compromise on the images on your website. Start &lt;a href="https://imagekit.io/" rel="noopener noreferrer"&gt;optimizing them today&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://imagekit.io/blog/what-is-image-cdn-guide/" rel="noopener noreferrer"&gt;https://imagekit.io&lt;/a&gt; on June 9, 2020.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Ultimate Guide To HTTP Caching For Static Assets</title>
      <dc:creator>Rahul Nanwani</dc:creator>
      <pubDate>Sat, 16 May 2020 12:00:46 +0000</pubDate>
      <link>https://dev.to/rnanwani/the-ultimate-guide-to-http-caching-for-static-assets-2iib</link>
      <guid>https://dev.to/rnanwani/the-ultimate-guide-to-http-caching-for-static-assets-2iib</guid>
      <description>&lt;p&gt;According to HTTP Archive, among the top 300,000 sites, the browser can cache &lt;a href="http://httparchive.org/trends.php#maxage0"&gt;nearly half of all the downloaded responses&lt;/a&gt;. Undoubtedly this is a massive saving for repeat page views and visits. It reduces the time it takes the visitor to interact with the page (e.g., see the images or start using filters) and, at the same time, reduces the load on your server. Not to mention it reduces the cost of data transfer from your server (or CDN) to the end-user.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Caching Works?
&lt;/h2&gt;

&lt;p&gt;Suppose you open a webpage &lt;a href="https://www.example.com"&gt;https://www.example.com&lt;/a&gt; and the server returns below HTML:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
&amp;lt;link type="text/css" href="https://www.example.com/app.css" rel="stylesheet"&amp;gt;
...
&amp;lt;!-- Rest of the HTML --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When the browser parses this HTML, it identifies that a CSS resource needs to be loaded from &lt;a href="https://www.example.com/app.css"&gt;https://www.example.com/app.css&lt;/a&gt;. The browser issues a request to the server, the server returns the image and tells the browser to cache it for 30 days.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imagekit.io/blog/content/images/2020/01/get-app-no-cache.png"&gt;&lt;br&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K11l0SQx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagekit.io/blog/content/images/2020/01/get-app-no-cache.png" alt="" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;
GET app.css, no object found in local cache



&lt;p&gt;Now, let's say you open the same page again after a few hours. The browser again parses the HTML and come across the resource at &lt;a href="https://www.example.com/app.css"&gt;https://www.example.com/app.css&lt;/a&gt;. Since the browser has this particular resource available in its local cache, it won't even go to the server. The network request is avoided in this case, and the styles are applied very quickly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imagekit.io/blog/content/images/2020/01/get-app-from-cache.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ytHl2qGE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagekit.io/blog/content/images/2020/01/get-app-from-cache.png" alt="" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;
GET app.css, object found in the local cache



&lt;h2&gt;
  
  
  Caching Static Assets On CDN
&lt;/h2&gt;

&lt;p&gt;Now you understand how browser caches the resource, let's talk about taking it a step further. Let's say users across different physical locations access your website millions of times in a month. And every page load would load the same image logo-white.png (and many other static assets like JS and CSS). All these requests are coming to your server for the first time for each user. This unnecessarily strains your web server. To avoid this, you can use a Content Delivery Network (CDN) and cache the static resources on CDN nodes itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource loading without CDN&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imagekit.io/blog/content/images/2020/01/no-cdn.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2vVICrTa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagekit.io/blog/content/images/2020/01/no-cdn.png" alt="" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;
Resources are downloaded from the origin server



&lt;p&gt;&lt;strong&gt;Resource loading with CDN&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imagekit.io/blog/content/images/2020/01/with-cdn.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5_d_NNK7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagekit.io/blog/content/images/2020/01/with-cdn.png" alt="" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;
Resources are downloaded from the nearest CDN edge



&lt;h2&gt;
  
  
  Best Practices For Caching
&lt;/h2&gt;

&lt;p&gt;Leveraging the cache is crucial, and there are few things to keep in mind while you set up your server, CDN, and application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choose The Right Cache Header Directive
&lt;/h3&gt;

&lt;p&gt;Values of following HTTP headers in the response controls who can cache the response, under which conditions, and for how long.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;Expires&lt;/code&gt; header&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Last-modified&lt;/code&gt; header&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Cache-control&lt;/code&gt; header (&lt;strong&gt;recommended)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9"&gt;Cache-Control&lt;/a&gt; header is defined as part of the HTTP/1.1 specification, and it supersedes the other caching headers. All modern browsers support Cache-Control, and you can forget about the other two headers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Set Optimal Cache Lifetime
&lt;/h3&gt;

&lt;p&gt;The cache lifetime depends on what kind of resource you are trying to cache. For example, frequently updating content like avatars or script loaders can have a shorter cache lifetime. However, in almost all cases, static assets like JS, CSS, and images can be cached for a much longer duration.&lt;/p&gt;

&lt;p&gt;You can use the table below to set the appropriate cache lifetime based on the type of resource:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;Resource type&lt;/th&gt;

&lt;th&gt;Optimial cache-control value&lt;/th&gt;

&lt;th&gt;Description&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;JS, images, CSS&lt;/td&gt;

&lt;td&gt;public, max-age=15552000&lt;/td&gt;

&lt;td&gt;This tells that the resource can be cached by the browser and any intermediary caches  
for up to 6 months.  

**Note:** Static assets can be safely cached for a longer duration, like six months or even one year.&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;HTML&lt;/td&gt;

&lt;td&gt;no-cache, no-store&lt;/td&gt;

&lt;td&gt;Don’t cache HTML on the browser so that you can quickly push updates to the client-side.  

**Note:** You might want to cache HTML content on  
CDN but never cache HTML content on intermediate proxies and browsers.  
Different CDN has a different way of setting this cache privately without setting browser cache.&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can &lt;a href="https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching"&gt;learn more about HTTP caching&lt;/a&gt; and different values for the &lt;code&gt;cache-control&lt;/code&gt; header.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ensure That The Server Adds A Validation Token (ETag)
&lt;/h3&gt;

&lt;p&gt;Let's say you have specified a cache lifetime of 300 seconds, and now a page issues a new request for the same resource. Assuming 300 seconds have passed since the first request, the browser can't use the cached response. Now browser can issue a new request to the server. But, it would be inefficient because if the resource on the server hasn't changed, then it doesn't make sense to download the same resource we have in the local cache.&lt;/p&gt;

&lt;p&gt;The validation token like ETag is here to solve this problem. The server generates this token, and it is typically a hash (or some other fingerprint) of the content, which means if the content changes, then this token change.&lt;/p&gt;

&lt;p&gt;So the browser sends the value of this ETag in &lt;code&gt;If-None-Match&lt;/code&gt; request header. The server checks this token against the latest resource. If the token hasn't changed, then a &lt;code&gt;304 - Not modified&lt;/code&gt; response is generated. &lt;code&gt;304 - Not modified&lt;/code&gt; response tells the browser that the resource in its local cache hasn't changed on the server, and its cache lifetime can be renewed for another 300 seconds. This saves time and bandwidth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First download of the resource&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imagekit.io/blog/content/images/2020/01/first-download.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f79ercb9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagekit.io/blog/content/images/2020/01/first-download.png" alt="" width="800" height="275"&gt;&lt;/a&gt;&lt;/p&gt;
First download of the resource



&lt;p&gt;&lt;strong&gt;Subsequent If-None-Match request when object in local cache is expired&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://imagekit.io/blog/content/images/2020/01/if-not-modifed.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AyxlFwvv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imagekit.io/blog/content/images/2020/01/if-not-modifed.png" alt="" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;
Subsequent If-None-Match request when object in local cache is expired



&lt;blockquote&gt;
&lt;p&gt;You need to ensure that the server is providing the ETag tokens by making sure the necessary flags are set. Use these &lt;a href="https://github.com/h5bp/server-configs"&gt;sample server configuration&lt;/a&gt; to confirm if your server is configured correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Embed fingerprints in the URLs of images, JS, CSS, and other static assets
&lt;/h3&gt;

&lt;p&gt;The browser looks up the resources in its local cache based on the URL. You can force the client side to download the newer file by changing the URL of that resource. Even changing the query parameters is considered as changing the resource URL. Ever noticed file names like below?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script src="/bundles/app.bundle.d587bbd6e38337f5accd.js" type="text/javascript"&amp;gt;&amp;lt;/script&amp;gt;
...
&amp;lt;div class="website-logo"&amp;gt;
  &amp;lt;img src="https://www.example.com/logo-white_B43Kdsf1.png"&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class="product-list"&amp;gt;
  &amp;lt;img src="https://www.example.com/product1.jpg?v=93jdje93"&amp;gt;
  &amp;lt;img src="https://www.example.com/product1.jpg?v=kdj39djd"&amp;gt;
  ...
&amp;lt;/div&amp;gt;
&amp;lt;!-- Rest of the HTML --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the above code, snippet &lt;strong&gt;B43Kdsf1, d587bbd6e38337f5accd&lt;/strong&gt;, &lt;strong&gt;93jdje93&lt;/strong&gt;, and &lt;strong&gt;kdj39djd&lt;/strong&gt; are essentially the fingerprint (or hash) of the content of the file. If you change the content, the fingerprint changes, hence the whole URL changes and browser's local cache for that resource is ignored.&lt;/p&gt;

&lt;p&gt;You don't have to manually embed fingerprints in all references to static resources in your codebase. Based on your application and build tools, this can be automated.&lt;/p&gt;

&lt;p&gt;One very popular tool &lt;a href="https://webpack.js.org/"&gt;WebPack&lt;/a&gt; can do this and much more for us. You can use long-term caching by embedding content hash in the file name using &lt;a href="https://github.com/jantimon/html-webpack-plugin#long-term-caching"&gt;html-webpack-plugin&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.[contenthash].html'
  })
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Avoid embedding current timestamps in the file names because this forces the client-side to download a new file even if the content is the same. Fingerprint should be calculated based on the content of the file and should only change when the content changes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can also use &lt;a href="https://gulpjs.com/"&gt;gulp&lt;/a&gt; to automatic this using &lt;a href="https://www.npmjs.com/package/gulp-cache-bust"&gt;gulp-cache-bust&lt;/a&gt; module. Example setup:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var cachebust = require('gulp-cache-bust');

gulp.src('./dist/*/*.html')
    .pipe(cachebust({
        type: 'MD5'
    }))
    .pipe(gulp.dest('./dist'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Aim for a higher hit ratio on CDN
&lt;/h3&gt;

&lt;p&gt;A "cache hit" occurs when a file is requested from a CDN, and the CDN can fulfill that request from its cache. A cache miss is when the CDN cache does not contain the requested content.&lt;/p&gt;

&lt;p&gt;Cache hit ratio is a measurement of how many requests a cache can fulfill successfully, compared to how many requests it received.&lt;/p&gt;

&lt;p&gt;The formula for a cache hit ratio is (Number of Cache Hits) divided by the (Number of Cache Hits + Number of Cache Misses)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When using a CDN, we should aim for a high cache hit ratio. When serving static assets using CDN, it is easy to get a cache hit ratio between 95-99% range. Anything below 80% for static assets delivery is considered bad.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Factors that can reduce cache hit ratio&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use of inconsistent URLs -&lt;/strong&gt; If you serve the same content on different URLs, then that content is fetched and stored multiple times. Also, note that URLs are case sensitive.  &lt;/p&gt;

&lt;p&gt;For example, the following two URL point to the same resource.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/demo/medium_cafe_B1iTdD0C.jpg?tr=w-100,h-100"&gt;https://ik.imagekit.io/demo/medium_cafe_B1iTdD0C.jpg?tr=w-100,h-100&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://ik.imagekit.io/demo/medium_cafe_B1iTdD0C.jpg?tr=h-100,w-100"&gt;https://ik.imagekit.io/demo/medium_cafe_B1iTdD0C.jpg?tr=h-100,w-100&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;But the URLs are different, and hence, two different requests are issued to the server. And two different copies are maintained on the CDN cache.  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use of timestamps in URLs&lt;/strong&gt; - If you are embedding current timestamps in URLs, then this changes the URL and response won't be returned from the cache. For example - &lt;a href="https://www.example.com/static/dist/js/app.bundle.dn238dj2.js?v=1578556395255"&gt;https://www.example.com/static/dist/js/app.bundle.dn238dj2.js?v=1578556395255&lt;/a&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A high number of image variations&lt;/strong&gt; - If you have implemented &lt;a href="https://scotch.io/tutorials/deliver-responsive-and-art-directed-images-for-your-website-with-imagekit908237"&gt;responsive images&lt;/a&gt; and have too many variations for every possible DPR value and screen size. It could lead to a low cache hit ratio. If a user gets a tailored image dimension from your servers based on their screen width and DPR, then they might be the first user to request this specific image from your CDN layer.  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;A rule of thumb is to check popular viewport sizes and device types from your Google Analytics and optimize your application for them.&lt;/em&gt;  &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Using shorter cache lifetime&lt;/strong&gt; - Static assets can be cached for a longer duration as long as you have a mechanism to push updates like embedding fingerprints in the URL. Setting a short cache duration increases the chances of a cache miss.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Use Vary Header Responsibly
&lt;/h3&gt;

&lt;p&gt;By default, every CDN looks up objects in its cache based on the path and host header value. The Vary header tells any HTTP cache (intermediate proxies and CDN), which request header to take into account when trying to find the right object. This mechanism is called &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation"&gt;content negotiation&lt;/a&gt; and is widely used to serve WebP images in supported browsers and leveraging Brotli compression.&lt;/p&gt;

&lt;p&gt;For example, if the client supports &lt;a href="https://imagekit.io/blog/what-and-why-brotli-compression/"&gt;Brotli compression&lt;/a&gt;, then it adds &lt;code&gt;br&lt;/code&gt; in the value of the &lt;code&gt;Accept-Encoding&lt;/code&gt; request header, and the server can use Brotli compression. If the client-side doesn't support Brotli, then br won't be present in this header. In this case, the server can use gzip compression.&lt;/p&gt;

&lt;p&gt;Since the response varies on the value of the &lt;code&gt;Accept-Encoding&lt;/code&gt; header received from the client while sending the response, the server should add the following header to indicate the same.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Vary: Accept-Encoding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Or you can serve WebP images if the value of Accept header has a string &lt;code&gt;webp&lt;/code&gt;. The server should add the following header in the image response:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Vary: Accept
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This allows us to serve &amp;amp; cache different content on the same URL. However, you should use the &lt;code&gt;Vary&lt;/code&gt; header responsibly as this can unnecessarily create multiple versions of the same resource in caches.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You should never vary responses based on User-Agent. For every unique value of User-Agent, a separate object is cached. This reduces the cache hit ratio.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Normalize&lt;/strong&gt; request header, if possible. Most CDNs normalizes the &lt;code&gt;Accept-Encoding&lt;/code&gt; header before sending it to the origin. For example, if we are only interested in the value of the &lt;code&gt;Accept-Encoding&lt;/code&gt; header has the string br or not, then we don't need to cache separate copy of the resource for each unique value of &lt;code&gt;Accept-Encoding&lt;/code&gt; header.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache Invalidation - Different Methods And Caveats
&lt;/h2&gt;

&lt;p&gt;If you need to update the content, then there are a couple of ways to go about it. However, you should keep in the mind that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Browser cache can't be purged unless you change the URL, which means you changed the resource. You will have to wait till the resource expires in the local cache.&lt;/li&gt;
&lt;li&gt;  Purging the resource on CDN doesn't guarantee that your visitor will see updated content because intermediate proxies (and browser) could still serve a cached response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above limitation leaves us with the following options:&lt;/p&gt;

&lt;h3&gt;
  
  
  Change the fingerprint in the resource URL
&lt;/h3&gt;

&lt;p&gt;Always embed fingerprints in the URL of static assets and do not cache HTML on the browser. This will allow you to push changes quickly and, at the same time, leverage long term cache. By changing the fingerprint in URL, we are essentially changing the URL of resource and forcing the client-side to download a new file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wait till resource expires in the local cache
&lt;/h3&gt;

&lt;p&gt;If you have chosen your cache policy wisely based on how often you change the content, then you don't need to invalidate the resource from caches at all. Just wait till the resources expire in caches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Service Workers To Manage Cache
&lt;/h3&gt;

&lt;p&gt;You can &lt;a href="http://Caching%20Files%20with%20Service%20Worker"&gt;cache files using service workers&lt;/a&gt; to manage local cache using the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Cache"&gt;Cache interface&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is useful when caching content, which often changes such as avatars or marketing banner images. However, you are responsible for implementing how your script (service worker) handles updates to the cache. All updates to items in the cache must be explicitly requested; items will not expire and must be deleted.&lt;/p&gt;

&lt;p&gt;You can put items in the cache on network request:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.open('mysite-cache').then(function(cache) {
      return cache.match(event.request).then(function (response) {
        return response || fetch(event.request).then(function(response) {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    })
  );
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And then later serve it from the cache:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;self.addEventListener('fetch', function(event) {&lt;br&gt;
  event.respondWith(caches.match(event.request));&lt;br&gt;
});&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Purge From CDN&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;If you need to purge the cache from CDN and don't have any other option, most CDN providers have this option. You can integrate their cache purge API in your CMS so that if a resource is changed on the same URL, a cache purge request is submitted on the CDN.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Here is what you need to remember while caching static resources on CDN or local cache server:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Use &lt;code&gt;Cache-control&lt;/code&gt; HTTP directive to control who can cache the response, under which conditions, and for how long.&lt;/li&gt;
&lt;li&gt; Configure your server or application to send validation token Etag.&lt;/li&gt;
&lt;li&gt; Do not cache HTML in the browser. Always set &lt;code&gt;cache-control: no-store, no-cache&lt;/code&gt; before sending HTML response to the client-side.&lt;/li&gt;
&lt;li&gt; Embed fingerprints in the URL of static resources like image, JS, CSS, and font files.&lt;/li&gt;
&lt;li&gt; Safely cache static resources, i.e., images, JS, CSS, font files for a longer duration like six months.&lt;/li&gt;
&lt;li&gt; Avoid embedding timestamps in URLs as this could quickly increase the variations of the same content on a local cache (and CDN), which will ultimately result in a lower cache hit ratio.&lt;/li&gt;
&lt;li&gt; Use Vary header responsibly. Avoid using &lt;code&gt;Vary: User-agent&lt;/code&gt; in the response header.&lt;/li&gt;
&lt;li&gt; Consider implementing CDN purge API in your CMS if you need to purge content from the cache in an automated way.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>webperf</category>
    </item>
    <item>
      <title>Network-Based Image Optimization And Role Of Service Workers</title>
      <dc:creator>Rahul Nanwani</dc:creator>
      <pubDate>Thu, 16 Apr 2020 08:34:57 +0000</pubDate>
      <link>https://dev.to/rnanwani/network-based-image-optimization-and-role-of-service-workers-3hig</link>
      <guid>https://dev.to/rnanwani/network-based-image-optimization-and-role-of-service-workers-3hig</guid>
      <description>&lt;h2&gt;
  
  
  Importance of Page Load Speed
&lt;/h2&gt;

&lt;p&gt;47% of consumers expect a web page to load in 2 seconds or less, and a 1-second delay in page response can result in a 7% reduction in conversions!&lt;/p&gt;

&lt;p&gt;Are we still debating about the importance of page load speed?&lt;/p&gt;

&lt;p&gt;The many, many images added to your website to increase its visual, as well as contextual appeal, are assets weighing down your webpages.&lt;/p&gt;

&lt;p&gt;Amongst all the resources that load on a webpage, images make up for most of the payload!&lt;/p&gt;

&lt;p&gt;And when data travels from point A to Point B, it takes time, in turn, slowing down the page load speed, and therefore, affecting website performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Role Of Network Speed in Website Performance
&lt;/h2&gt;

&lt;p&gt;While time is spent optimizing images for various viewports, and compressing and optimizing them to reduce their bandwidth consumption, the importance of optimizing their delivery is often discounted, or sometimes even entirely ignored.&lt;/p&gt;

&lt;p&gt;Yes, using a CDN helps cut latency, but what about the latency at the user’s end?&lt;/p&gt;

&lt;p&gt;The various bandwidth connections have a direct impact on your website’s load speed. With each asset consuming bandwidth, the weight of that asset becomes a critical factor, and more so if the network speed fluctuates during the session.&lt;/p&gt;

&lt;p&gt;So, assuming a user is visiting a webpage at the network speed of 4G, there would hardly be a hiccup the website faces as the bandwidth is fast enough for the resources to consume, and load quickly.&lt;/p&gt;

&lt;p&gt;But if the user is on a 2G network, the available bandwidth would be much less, and with heavy website assets, the webpages would take far too long to load.&lt;/p&gt;

&lt;p&gt;The bounce rate multiplies for each passing second the website takes to load. Those are potential conversions you’ve lost due to resources on your websites that haven’t been optimized for slower bandwidth connections.&lt;/p&gt;

&lt;p&gt;Additionally, network speeds aren’t always stable. A user may have started their session on your website at a 4G connection, but it can drop down to a 2G one during their time on your webpages. You need to prepare your websites for such instances as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Network-Based Image Optimization?
&lt;/h3&gt;

&lt;p&gt;As high-quality images consume more bandwidth further slowing the page load speed, and with more and more users shifting to mobiles for internet browsing, network speeds at which your websites are visited are now consequential factors to consider in your image optimization strategy.&lt;/p&gt;

&lt;p&gt;Poor data download speeds is not a concept limited to certain countries or data providers, it is an issue everyone faces. When one is camping in the woods or in the basement of their building parking their car, are some instances where mobile data download speed takes a hit.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hqhNdyeJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/h7qu0njwijhe3vofywp3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hqhNdyeJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/h7qu0njwijhe3vofywp3.png" alt="different network users" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image optimization based on network speeds is a relatively new concept, but now a critical yet effective one.&lt;/p&gt;

&lt;p&gt;Essentially, the image is compressed and served based on the user’s network speed. So, slower the bandwidth speed, more the compression that needs to be applied to the images for a faster website.&lt;/p&gt;

&lt;p&gt;Even if you do take care of optimizing the images in general, optimizing them further for slower networks can reduce the overall page weight by almost 30%. This reduces their weight, making them easier and faster to load even on slow networks.&lt;/p&gt;

&lt;p&gt;Though you can optimize other assets apart from images on the basis of network speed, and while doing that will actually have a bigger impact on website performance than optimizing images for network speeds.&lt;br&gt;
However, optimizing images is just simpler to do and, additional compression of images doesn’t break the critical functionality of any application.&lt;/p&gt;

&lt;p&gt;Yes, the image quality drops a bit to provide for a better user experience. But unlike stripping away Javascript, which would require much thought, compressing images is relatively straightforward.&lt;/p&gt;

&lt;p&gt;And all this can be done with minimum effort using &lt;a href="//www.ImageKit.io"&gt;ImageKit.io&lt;/a&gt; and our service worker.&lt;/p&gt;

&lt;p&gt;It can help select the right image quality to be delivered to the user, without affecting the perceived website performance, for their bandwidth connection. All this without any changes in your code or image URLs, and no additional requests made to the server origins. Hence, saving bandwidth costs as well.&lt;/p&gt;

&lt;h4&gt;
  
  
  So how does it work?
&lt;/h4&gt;

&lt;p&gt;Amongst the many challenges faced by developers is rendering the appropriate quality of any image based on the bandwidth or network speed of their users. But it does not need to be a complicated process. It should be as simple as passing an additional parameter in the image URL when the browser triggers a load for it.&lt;/p&gt;

&lt;p&gt;ImageKit.io service worker can help optimize and deliver your images based on the network speed of your users, that too, in a simple, straightforward manner.&lt;/p&gt;

&lt;p&gt;Network speeds are broadly divided into four categories - 4G, 3G, 2G, and slow 2G. ImageKit.io allows you to set different image quality levels based on each respective network speed based on application, within their dashboard.&lt;/p&gt;

&lt;p&gt;All that needs doing is enabling the setting for network-based image optimization in the ImageKit dashboard. You get a code snippet right there which needs to be added to an existing service worker on your website or to a new service worker.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AKLjM816--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/rya6u039r9ardx6hfwl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AKLjM816--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/rya6u039r9ardx6hfwl4.png" alt="network based image optimization dashboard" width="800" height="422"&gt;&lt;/a&gt;&lt;br&gt;
The ImageKit.io code snippet is like a plugin meant for use in service workers. It intercepts the image requests originating from the user’s browser, detects the user’s network speed, and adds the necessary parameters to the image URL. These parameters can be understood by the ImageKit server to compress the image to the desired level and maintain efficient client-side caching.&lt;/p&gt;

&lt;p&gt;With ImageKit.io you can get the image with the desired compression level for a particular network speed in a simple manner.&lt;/p&gt;

&lt;p&gt;The compression and quality levels can be customized and are entirely upon your discretion within ImageKit.io.&lt;/p&gt;

&lt;p&gt;All you have to do is pass the network type in the image URL, and with the network type to image quality settings already stated within the dashboard, ImageKit.io service worker understands the parameter, and optimizes and renders the image in the required quality.&lt;/p&gt;

&lt;p&gt;Quality is directly proportional to image size, thus, higher the quality number, larger will be the resulting image.&lt;/p&gt;

&lt;p&gt;Additionally, in the ImageKit.io dashboard, you can specify the image URLs (or patterns in URLs) that should not be optimized based on the network type. For example, you would want to present the same crisp logo of your brand to your users regardless of their network speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network-Based Image Caching With Service Worker
&lt;/h3&gt;

&lt;p&gt;ImageKit.io service worker manages the caching (and expiration) of images.&lt;/p&gt;

&lt;p&gt;So as an added advantage of using ImageKit.io service worker, the plugin bypasses the browser cache in favor of network-based image cache in the browser. Bypassing the browser cache means that the service worker can maintain different caches for different network types and chooses the correct image from the cache or request a new one based on the user’s current network condition.&lt;/p&gt;

&lt;p&gt;The service worker plugin automatically uses the cache-first technique to load the images and also implements a waterfall method to pick the right one from the cache. With this waterfall method, images at higher quality get preference over images at a lower quality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NvyO0a-L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/79jzed00c50o5tw4mzvi.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NvyO0a-L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/79jzed00c50o5tw4mzvi.jpeg" alt="network based image optimization cache" width="800" height="483"&gt;&lt;/a&gt;&lt;br&gt;
What this means is if the user’s speed drops to 2G and he has a particular image cached from the time when he was experiencing good download speed on a 4G network, the service worker will use that cached 4G-level image for delivery instead of downloading the image over the 2G network.&lt;/p&gt;

&lt;p&gt;But the reverse is not valid.&lt;/p&gt;

&lt;p&gt;If the user is experiencing 4G network speeds, the service worker won’t pick up the 2G image from the cache, because it is possible to fetch a better quality image and the resources allow for it.&lt;/p&gt;

&lt;p&gt;Basically, it intercepts all image requests to check for the right cache of images to be served based on the requesting bandwidth connection, or check whether a simple image URL modification would suffice.&lt;/p&gt;

&lt;p&gt;&lt;a href="//www.ImageKit.io"&gt;ImageKit.io&lt;/a&gt; has made it quite easy for you to optimize your images based on bandwidth speeds. It requires almost zero configuration on your part while offering network-based optimizations in a simple format within the tool.&lt;/p&gt;

&lt;p&gt;With the feature incorporated in the dashboard as a convenient and effortless toggle, you can just turn it off or on by a simple click of a button!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b9IXgGlW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xl3rx4jvekls1y3rclxo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b9IXgGlW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/xl3rx4jvekls1y3rclxo.png" alt="enable service worker image optimization" width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Analytics
&lt;/h4&gt;

&lt;p&gt;Another advantage of network-based optimizations with &lt;a href="//www.ImageKit.io"&gt;ImageKit.io&lt;/a&gt; is that the tool provides analytics on your user’s observed network type within its dashboard!&lt;/p&gt;

&lt;p&gt;It gives you an insight into the number of times network-based optimization gets triggered and what does the user distribution look like across different network types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LzSEwTNa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/mxtksfg0xfhdy6u3vpnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LzSEwTNa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/mxtksfg0xfhdy6u3vpnn.png" alt="network based image optimization analytics" width="800" height="360"&gt;&lt;/a&gt;&lt;br&gt;
This distribution analysis can be helpful even for optimizing other resources on your website.&lt;/p&gt;

&lt;h4&gt;
  
  
  Things To Keep In Mind When Employing A Service Worker For Your Websites:
&lt;/h4&gt;

&lt;p&gt;While using service workers for optimizing your images based on varying network speeds has its merits, there are some things that need to be put in order and kept in mind before you get started with them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For security reasons, service workers are available to secure origins only. Hence, your web pages, and subsequently, your service worker script needs to be served via HTTPS for it to be functional.&lt;/li&gt;
&lt;li&gt;The service worker should be placed in the root folder so it can access all the requests. This is imperative as the scope of the service worker is limited to the folder it is present in.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Final Thoughts
&lt;/h4&gt;

&lt;p&gt;Any website should aim for an optimum user experience, and network-based image optimizations serve that very purpose.&lt;/p&gt;

&lt;p&gt;With your images being cached and served at sizes most appropriate for your users' network speeds, ImageKit.io service worker aids more than just a faster website, it also saves on your users‘ bandwidths. And a good user experience is about more than just the website, isn't it?&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>image</category>
      <category>optimization</category>
      <category>performance</category>
    </item>
    <item>
      <title>Website speed testing – Are you doing it right?</title>
      <dc:creator>Rahul Nanwani</dc:creator>
      <pubDate>Wed, 20 Feb 2019 13:31:18 +0000</pubDate>
      <link>https://dev.to/rnanwani/website-speed-testing--are-you-doing-it-right-3pa5</link>
      <guid>https://dev.to/rnanwani/website-speed-testing--are-you-doing-it-right-3pa5</guid>
      <description>&lt;p&gt;If you can’t measure it, you can’t improve it. That is why website speed testing is of great interest to every webmaster. While there are many tools available to measure different metrics related to web page performance, relying on a particular metric alone often leads to inaccurate conclusions.&lt;/p&gt;

&lt;p&gt;The aim of this guide is to highlight the bigger picture around website speed testing. It includes what to measure, how to measure it accurately and various pitfalls in the whole process. Let’s cover them one by one:&lt;/p&gt;

&lt;h2&gt;
  
  
  What to measure during website speed testing?
&lt;/h2&gt;

&lt;p&gt;When it comes to website speed testing, we immediately start thinking about the total page load time. And no doubt about the importance of this metric but if you dig deeper you will know that caring too much about this particular metric, as reported by several tools, will often mislead you. The page load time alone is a poor indicator of the user experience of your visitors.&lt;/p&gt;

&lt;p&gt;Let me show you why. For example, take a look at this image&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uLW6EdPA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/24tsj4dhts8qq34x6is8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uLW6EdPA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/24tsj4dhts8qq34x6is8.png" alt="various third party calls increasing the total page load time" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how third party calls starting with &lt;code&gt;ipt&lt;/code&gt; are taking quite a lot of time to load and increasing the reported page load time. Even though these calls happen asynchronously in the background after all the important content have been loaded, they are still reported in the total page load time. If you are in a similar situation, then ask yourself this question&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do any of these third party tracking API calls or ad scripts actually affect the way your user interacts with the page?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the answer to the above question is no then you need to stop taking decisions based on this metric alone.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In other words, you need to start measuring metrics that matter to your application and are specific to your use case &amp;amp; business.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, on an e-commerce website, the users should be able to use filters and see the products. So all the JS files, HTML templates and product images should load as quickly as possible. And this is exactly what you should be measuring. We will soon discuss how you can measure the loading time of different assets individually.&lt;/p&gt;

&lt;p&gt;On the other hand, for a news website, your visitors should be able to see the text and the associated images before losing interest and bouncing off. Only after you quickly feed them the content by quickly loading your page, do the chances of getting more engagement, more ad impressions and more clicks increase.&lt;/p&gt;

&lt;p&gt;Now we know that one size doesn’t fit all, as not all metrics carry same importance. Let’s discuss how we can measure these page performance metrics separately and accurately.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to measure different performance metrics of a web page?
&lt;/h2&gt;

&lt;p&gt;There are broadly two measurement techniques:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Synthetic testing with no actual user. This could be done using tools like &lt;a href="http://www.catchpoint.com/synthetic-monitoring/"&gt;CatchPoint&lt;/a&gt; or &lt;a href="https://www.pingdom.com/"&gt;Pingdom&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Real user monitoring in an actual user’s browser by injecting javascript to collect timing metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you care about how your users are actually experiencing your applications, then Real User Monitoring(RUM) will provide the most accurate insights.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are a few companies and open-source projects for RUM but you can build your own scripts too!&lt;/p&gt;

&lt;p&gt;Skip the next section if you are already familiar with Resource Timing API and the related properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  About Resource Timing API
&lt;/h3&gt;

&lt;p&gt;The Resource Timing API is exposed through the performance property of the window object.&lt;code&gt;window.performance.getEntries()&lt;/code&gt; provides an array of PerformanceResourceTiming object for every asset on the page. Each PerformanceResourceTiming object in this array contains following crucial timing information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;initiatorType&lt;/code&gt; represents the type of resource that initiated the performance event. It could be element’s localname, css or xmlhttprequest etc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redirectStart&lt;/code&gt; is recorded when the first HTTP redirect starts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;redirectEnd&lt;/code&gt; is recorded when the last HTTP redirect is completed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fetchStart&lt;/code&gt; is recorded when the browser is ready to fetch the document using an HTTP request. This moment is before the check to any application cache.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;domainLookupStart&lt;/code&gt; is recorded immediately before the domain name lookup.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;domainLookupEnd&lt;/code&gt; is recorded immediately after the domain name lookup is successfully done.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connectStart&lt;/code&gt; is recorded immediately before initiating the connection to the server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;connectEnd&lt;/code&gt; is recorded immediately after the connection to the server or the proxy is established.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;secureConnectionStart&lt;/code&gt; is recorded when the handshake begins for securing the connection. It is used only if TLS or SSL is in use.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;requestStart&lt;/code&gt; is recorded immediately before the device starts sending the request for the resource.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;responseStart&lt;/code&gt; is recorded immediately after the device receives the first byte of the response.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;responseEnd&lt;/code&gt; is recorded immediately after receiving the last byte of the response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical request lifecycle in the browser starts by a DNS lookup, then a TCP connection and finally actual downloading.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9tOoRFXe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/f8tps31qq3j9wysb7mde.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9tOoRFXe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/f8tps31qq3j9wysb7mde.png" alt="graphical representation of a request lifecycle in the browser" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TTFB = &lt;code&gt;responseStart - requestStart&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Download time = &lt;code&gt;responseEnd - responseStart&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Total download time = &lt;code&gt;responseEnd - requestStart&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here are a few scripts that you can use to see how your website is performing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo script to calculate the download time of a specific JS file on a page
&lt;/h3&gt;

&lt;p&gt;Suppose we want to measure the download time for a compiled JS file called vendor.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function measureTimings() {
  var timingInfo = window.performance.getEntriesByName("https://imagekit.io/static/build/js/vendor.js");
  if(timingInfo.length) {
    var duration = timingInfo[0].duration;
    var beacon = new Image();
    beacon.src = "//example.com/rum/result/log-timings?script=vendor&amp;amp;amp;duration=" + duration;
  }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Call &lt;code&gt;measureTimings()&lt;/code&gt; after vendor.js is loaded.&lt;/p&gt;

&lt;p&gt;Simply implement an end point on your backend, like the &lt;code&gt;log-timings&lt;/code&gt; end point in the above example, to receive this duration data. You can then calculate data like average, median and percentile load times to learn how long does it take before your web page is useful for your visitors.&lt;/p&gt;

&lt;p&gt;This data reflects what your real users are experiencing on your website. You might have more than one JS file or some other assets that are more important for your use case, go measure timings for those.&lt;/p&gt;

&lt;p&gt;Instead of implementing your own backend for recording these timings, you can also leverage &lt;a href="https://developers.google.com/analytics/devguides/collection/analyticsjs/user-timings"&gt;Google Analytics’s User Timings&lt;/a&gt; tracking. You can use send command like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ga('send', {
  hitType: 'timing',
  timingCategory: 'JS Dependency',
  timingVar: 'load',
  timingValue: 1249

});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I will write a detailed post about how we can collect more information like visitor’s IP and location to be able to generate much better insights about our page performance. Let me know if you want a heads up&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo scripts to calculate the 90% percentile download time for all images on a page
&lt;/h3&gt;

&lt;p&gt;To calculate how much time it takes before 90% of the images on a web page have been loaded, you can use something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function measureImageTimings() {
  var timings = window.performance.getEntries();
  var sum = 0;
  for(var i=0, l=entries.length; i &amp;amp;lt; l;i++) {
    // check on name property to check only for images or any other custom check you want
    if(entries[i].name.indexOf("images.example.com") != -1) {
      timings.push(entries[i].duration);
    }
  }
  timings.sort(function(a,b){ return a-b; });
  var len = timings.length, ninetieth, beacon;
  if(len) {
      ninetieth = timings[parseInt(len *.9)] || 0;
      beacon = new Image();
      beacon.src = "//example.com/rum/result/log-nineteenth-percentile?ninetieth="+ninetieth;
  }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trigger &lt;code&gt;measureImageTimings()&lt;/code&gt; a few seconds after the user has been on the page. Ideally, you would want to wait till most of the images have been loaded. You can also send &lt;code&gt;timings.length&lt;/code&gt; to note how many images have been loaded at the time of this recording. Experiment with different wait times before triggering &lt;code&gt;measureImageTimings()&lt;/code&gt; to increase this count. If you have a better idea for this, do share in the comments section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Various pitfalls during website speed testing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Timing metrics not available&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Not all timing metrics are exposed on every origin. &lt;code&gt;Timing-Allow-Origin&lt;/code&gt; response header should contain the whitelisted origin on which you want to allow access to above timing information. In case this check fails, &lt;code&gt;responseStart&lt;/code&gt; and many other metrics will simply report 0 and your whole analysis can go wrong. You can whitelist all origins like this to be safe side&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Timing-Allow-Origin : *&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;While relying on RUM, you should &lt;strong&gt;always collect a lot of data&lt;/strong&gt; to make up for any variance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Median and percentiles&lt;/strong&gt; should be given more importance than average.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Remove the outlier values&lt;/strong&gt; when analysing the data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don’t get overwhelmed with the sheer amount of data and always &lt;strong&gt;remember what to measure&lt;/strong&gt;. Remember, the page load time example above. Don’t get locked into a single metric.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Know the difference between duration field and actual download time&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;During a page load, there are many resources being downloaded in parallel and they all compete for a limited bandwidth. On top of it if your server is using HTTP/1 instead of HTTP/2 then browser puts a further restriction of only 6 TCP connections per origin at any point in time. This can result in queueing your requests for a much longer time than compared to the actual download time for that asset. The browser can postpone your request for other reasons as well like a lower priority request than critical resources (such as scripts/styles). This often happens with images. For example-&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kxNhDZs9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ik.imagekit.io/demo/imagekitwebsite/wp-content/uploads/Screen-Shot-2017-07-31-at-6.07.18-PM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kxNhDZs9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://ik.imagekit.io/demo/imagekitwebsite/wp-content/uploads/Screen-Shot-2017-07-31-at-6.07.18-PM.png" alt="PerformanceResourceTiming object properties" width="539" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now notice that the overall download time (TTFB + download time) is only around 95ms but since the request was queued for 1.4 seconds, the total download duration is reported as 1.5 seconds.&lt;/p&gt;

&lt;p&gt;You need to make sure you are using a right field from the PerformanceResourceTiming object for your measurements.&lt;/p&gt;

&lt;p&gt;For example, If you are comparing the performance of various CDNs, then you should care about TTFB and total download time. On the other hand, if you want to measure how much time it takes before your images are actually visible to the visitors or how much time it takes before your JS is downloaded (i.e. filters start working), then you should take into consideration the duration field. It will account for all the queuing, stalling, TCP handshakes, SSL handshake &amp;amp; DNS lookup times.&lt;/p&gt;

&lt;p&gt;I hope you are all set to use these techniques for measuring the performance of your own website. Website speed testing is a continuous process and besides RUM, you should also use other tools available to monitor the overall performance of your websites like Google PageSpeed Inshgits, WebPageTest and Pingdom.&lt;/p&gt;

&lt;p&gt;To gain deeper insights about your images health, try ImageKit &lt;a href="https://imagekit.io/website-analyzer"&gt;website analyzer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you see too many unoptimized images in the analyzer report, &lt;a href="https://imagekit.io/registration?planType=free&amp;amp;utm_source=dev.to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=Dev.to_Speedtest_Free&amp;amp;utm_content=Dev.to_Speedtest_Free"&gt;sign up on ImageKit now&lt;/a&gt; and give it a try. It is an intelligent global &lt;a href="https://imagekit.io?utm_source=dev.to&amp;amp;utm_medium=blog&amp;amp;utm_campaign=Dev.to_Speedtest_Free"&gt;image CDN&lt;/a&gt; free to begin with and only takes a &lt;a href="https://imagekit.io/blog/image-optimization-10-minutes-imagekit?utm_campaign=blog&amp;amp;utm_source=website-speed-testing&amp;amp;utm_medium=web"&gt;couple of minutes&lt;/a&gt; to get up and running.&lt;/p&gt;

&lt;p&gt;Not sure why &lt;a href="https://imagekit.io/blog/image-optimization-goes-well-beyond-performance-improvement?utm_campaign=blog&amp;amp;utm_source=website-speed-testing&amp;amp;utm_medium=web"&gt;image optimization is important, read this&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;Please share this guide with your team and leave your feedback &amp;amp; views in the comments section below.&lt;/p&gt;

</description>
      <category>webperf</category>
      <category>imageoptimization</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Speed up your website with image optimization, Absolutely Free!</title>
      <dc:creator>Rahul Nanwani</dc:creator>
      <pubDate>Tue, 29 Jan 2019 13:18:29 +0000</pubDate>
      <link>https://dev.to/rnanwani/image-optimization-is-essential-for-your-website-now-you-can-do-it-for-free-5ecd</link>
      <guid>https://dev.to/rnanwani/image-optimization-is-essential-for-your-website-now-you-can-do-it-for-free-5ecd</guid>
      <description>&lt;p&gt;A picture can paint a thousand words is an adage that is true for all things online. Whether it is the image of a product or a place, having them on the website is an excellent way to communicate with your audience. Also, with many sites having similar products, ideas and services an image can leave a lasting impact, enhance user experience and driving traffic to the webpage. &lt;/p&gt;

&lt;p&gt;To stay ahead of the competition, companies need to understand not just the value of visuals, but also how and why it should be optimized. &lt;a href="https://imagekit.io/?utm_source=Dev.to&amp;amp;utm_campaign=FreePlan_Dev.to"&gt;Optimized images can be a great differentiator&lt;/a&gt; between the haves and the have-nots. &lt;/p&gt;

&lt;p&gt;If you are already aware of the importance of image optimization, you can skip the next section and jump straight to how ImageKit can help you achieve it for free. &lt;/p&gt;

&lt;p&gt;If you are not convinced, let us look at how image optimization can help you stay ahead of the curve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do you need image optimization?
&lt;/h3&gt;

&lt;p&gt;Simply put, image optimization is a process of quickly delivering images in the correct format, dimensions and compression level to each device while ensuring good visual quality. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;For example&lt;/em&gt;, you cannot use a product photograph clicked using a DSLR camera directly on your website. That image would run into quite a few Megabytes and take forever to download for your user. You need to resize the image down to the exact dimensions required on your website, convert it to, let’s say, JPG format and compress it a bit to get the size down to a few Kilobytes which is more in line with what is acceptable on a website. And then you need to ensure that this image is delivered quickly to your user’s device regardless of their geographical location.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Faster page load for better conversions -
&lt;/h4&gt;

&lt;p&gt;With optimized images, your page size goes down, and the images load quicker which reduces the total load time of your page. This reduction in load time results in an improved user experience helping improve retention and decreasing the bounce rate. Thus the chances of a user converting, either purchasing a product or signing up on your website, improve significantly with image optimization. &lt;/p&gt;

&lt;h4&gt;
  
  
  2. Better SEO for organic traffic -
&lt;/h4&gt;

&lt;p&gt;Plus, search engines like Google also factor in the page load speed when ranking any webpage. Lower the page load time higher is the organic traffic you can get to your website. &lt;/p&gt;

&lt;h4&gt;
  
  
  3. Perfect image experience across devices -
&lt;/h4&gt;

&lt;p&gt;The definition doesn’t stop here. Most of the users use their smartphones and other hand-held devices to access websites. Therefore, for a perfect visual experience, you need to ensure that the images are resized correctly irrespective of the user's device.&lt;/p&gt;

&lt;p&gt;The stepping stone of any successful online business is using correctly optimized and resized images.&lt;/p&gt;

&lt;p&gt;So why do these seemingly clear and straightforward tasks are in reality difficult to achieve? The lack of a simple, yet complete tool for image optimization? Something that is easy to set up for any website and doesn’t cost a bomb? Well, all of that now changes with ImageKit!&lt;/p&gt;

&lt;h3&gt;
  
  
  What is ImageKit and how can it help with image optimization?
&lt;/h3&gt;

&lt;p&gt;ImageKit is an intelligent global &lt;a href="https://imagekit.io"&gt;image CDN&lt;/a&gt; which is a one-stop solution for all your image-related needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Real-time URL-based image transformations like resizing and cropping&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- Automatic best format selection including WebP support&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- Automatic image compression&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- Intelligent cropping with Smart Crop&lt;/strong&gt; &lt;br&gt;
&lt;strong&gt;- Image overlays (watermarks)&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;- A ready-to-use media storage and many more features...&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All the optimizations and transformations are done in real-time and can be changed directly from the URL. &lt;/p&gt;

&lt;p&gt;Combine this with AWS CloudFront Content Delivery Network, that comes by default with ImageKit and has 150+ delivery nodes across the globe, your images will not only be smaller in size but will load in a few milliseconds for all your users.&lt;/p&gt;

&lt;h3&gt;
  
  
  And it is now available for absolutely free!
&lt;/h3&gt;

&lt;p&gt;At ImageKit, we understand that you don’t work with bottomless budgets and have to be sure about the investments you make. And something as basic as image optimization should be accessible to everyone regardless of the size of their online presence. &lt;/p&gt;

&lt;p&gt;That is why we have launched our &lt;a href="https://imagekit.io/plans?utm_source=Dev.to&amp;amp;utm_campaign=FreePlan_Dev.to"&gt;Forever Free plan&lt;/a&gt; that gives you access to all the image-related features mentioned above and up to 20GB bandwidth for delivering optimized images every month, which translates to close to a million files that you can load with ImageKit! And yes it is free, no credit card needed. Forever! &lt;/p&gt;

&lt;p&gt;Whether it is a WordPress blog or a Magento or Shopify e-commerce store or any other website for that matter, ImageKit can work for you with just a few minutes of setup and a small URL change. And if you are migrating from a complex third-party image management system, our team can help you with that as well. &lt;/p&gt;

&lt;p&gt;ImageKit’s Forever Free plan gets you to access a single world-class tool to address multiple image-related requirements and turn your users into a custodian of your brand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Just don’t believe in what we say! &lt;a href="https://imagekit.io/plans?utm_source=Dev.to&amp;amp;utm_campaign=FreePlan_Dev.to"&gt;Sign up for the free plan&lt;/a&gt; now and see how ImageKit can help you deliver a perfect visual experience on your website
&lt;/h3&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>optimization</category>
      <category>performance</category>
    </item>
    <item>
      <title>How Smart Crop can help you deliver perfect responsive images on each device</title>
      <dc:creator>Rahul Nanwani</dc:creator>
      <pubDate>Thu, 17 Jan 2019 08:40:07 +0000</pubDate>
      <link>https://dev.to/rnanwani/how-smart-crop-can-help-you-deliver-perfect-responsive-images-on-each-device-25p4</link>
      <guid>https://dev.to/rnanwani/how-smart-crop-can-help-you-deliver-perfect-responsive-images-on-each-device-25p4</guid>
      <description>&lt;p&gt;Images are a critical piece of all websites and apps. Whether it is an e-commerce store, a travel website or a content website, a typical website would have hundreds of thousands of images. The number can be significantly higher if you have user-generated content on the website. With such a large number of images on a website, for a &lt;a href="http://imagekit.io/blog/how-to-deliver-responsive-images-across-multiple-devices/" rel="noopener noreferrer"&gt;perfect responsive image experience&lt;/a&gt; on each user’s device, the images should also change according to the device that is requesting them. Which means that instead of resizing the image using CSS, the image that loads on a mobile device should be actually smaller in dimensions than the one that loads on a desktop device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does regular cropping fail?
&lt;/h2&gt;

&lt;p&gt;In such a scenario, where a variety of images have to be resized for different devices and different placeholders, cropping in an image is inevitable. And the default cropping strategy adopted for images is centre cropping – preserve the centre of the image and crop out from the edges. While this strategy works fine for a lot of cases, it can fail when the subject is not at the centre of the image. Here are some examples of poor thumbnails as a result of centre cropping –&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Original Images (scaled down)&lt;/th&gt;
&lt;th&gt;Image thumbnails 150px x 200px&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_1_BJ6GYWWbN.jpeg%3Ftr%3Dw-400"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_1_BJ6GYWWbN.jpeg%3Ftr%3Dw-150%2Ch-200"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_2_r1QOFZ-bE.jpeg%3Ftr%3Dw-400"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_2_r1QOFZ-bE.jpeg%3Ftr%3Dw-150%2Ch-200"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_3_H1LQ5Wb-E.jpeg%3Ftr%3Dw-400"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_3_H1LQ5Wb-E.jpeg%3Ftr%3Dw-150%2Ch-200"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_4_ryB8GMWbE.jpeg%3Ftr%3Dw-400"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_4_ryB8GMWbE.jpeg%3Ftr%3Dw-150%2Ch-200"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;You may get away with such thumbnails on your website, not all of your users may care about it. But if you are one of those companies, that want to deliver a perfect experience to your users, even if it is a thumbnail of a product, you would not want such improperly cropped thumbnails to be shown to your users.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What’s the solution then? How do we ensure that we are cropping the images correctly while creating thumbnails?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter ImageKit’s Smart Crop
&lt;/h2&gt;

&lt;p&gt;Smart Crop is a content-aware cropping method available to all ImageKit users that analyses the image content and tries to ensure that the most important part of the image is always at the centre of the final thumbnail.&lt;/p&gt;

&lt;p&gt;Let’s see how it works for the images where the centre crop failed.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Original Images (scaled down)&lt;/th&gt;
&lt;th&gt;Centre-cropped image thumbnails 150px x 200px&lt;/th&gt;
&lt;th&gt;Smart-cropped image thumbnails 150px x 200px&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_1_BJ6GYWWbN.jpeg%3Ftr%3Dw-400"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_1_BJ6GYWWbN.jpeg%3Ftr%3Dw-150%2Ch-200"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_1_BJ6GYWWbN.jpeg%3Ftr%3Dw-150%2Ch-200%2Cfo-auto"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_2_r1QOFZ-bE.jpeg%3Ftr%3Dw-400"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_2_r1QOFZ-bE.jpeg%3Ftr%3Dw-150%2Ch-200"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_2_r1QOFZ-bE.jpeg%3Ftr%3Dw-150%2Ch-200%2Cfo-auto"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_3_H1LQ5Wb-E.jpeg%3Ftr%3Dw-400"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_3_H1LQ5Wb-E.jpeg%3Ftr%3Dw-150%2Ch-200"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_3_H1LQ5Wb-E.jpeg%3Ftr%3Dw-150%2Ch-200%2Cfo-auto"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_4_ryB8GMWbE.jpeg%3Ftr%3Dw-400"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_4_ryB8GMWbE.jpeg%3Ftr%3Dw-150%2Ch-200"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_4_ryB8GMWbE.jpeg%3Ftr%3Dw-150%2Ch-200%2Cfo-auto"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;In each case, the smart crop was able to get the most important part of the image in the centre.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to enable smart crop in the image URL?
&lt;/h2&gt;

&lt;p&gt;Well, it’s really simple. Along with the height and width, you need to specify the &lt;code&gt;focus&lt;/code&gt; mode for cropping and set it to &lt;code&gt;auto&lt;/code&gt;. This is done using the &lt;code&gt;fo-auto&lt;/code&gt; parameter in the transformation string in the URL. For example,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://ik.imagekit.io/demo/img/tr:w-150,h-200,fo-auto/test_image.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can &lt;a href="https://help.imagekit.io/start-delivering-resized-and-optimized-images/resize-crop-and-responsive-images/crop-crop-modes-and-focus" rel="noopener noreferrer"&gt;read more about this focus parameter in ImageKit here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical applications of smart crop
&lt;/h2&gt;

&lt;p&gt;Now that we have seen how ImageKit works, let’s take a look at how you can use it on your website.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. For e-commerce websites&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Creating perfect product thumbnails&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A product needs to be displayed on multiple pages on your website or app – the listing page, the product detail page, as a small thumbnail in an image carousel etc. With smart crop, you can ensure that each product thumbnail is perfect and showcases your product the way it should be done.&lt;/p&gt;

&lt;p&gt;Here is how it smart crop can help your e-commerce store. We are using scaled-down versions of images here for display, but it does give an idea about the power of smart crop.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Original Image&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_5_ByBvwmbWV.jpeg%3Ftr%3Dw-500"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Without Smart Crop&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;strong&gt;Mobile Thumbnail&lt;/strong&gt;  200px x 200px&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;Desktop Listing Page&lt;/strong&gt;  350px x 300px&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;Desktop Product Carousel&lt;/strong&gt;  400px x 600px (scaled to 60%)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_5_ByBvwmbWV.jpeg%3Ftr%3Dw-200%2Ch-200"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_5_ByBvwmbWV.jpeg%3Ftr%3Dw-350%2Ch-300"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_5_ByBvwmbWV.jpeg%3Ftr%3Dw-400%2Ch-600"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;With Smart Crop&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;strong&gt;Mobile Thumbnail&lt;/strong&gt; 200px x 200px&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;Desktop Listing Page&lt;/strong&gt; 350px x 300px&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;Desktop Product Carousel&lt;/strong&gt; 400px x 600px (scaled to 60%)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_5_ByBvwmbWV.jpeg%3Ftr%3Dw-200%2Ch-200%2Cfo-auto"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_5_ByBvwmbWV.jpeg%3Ftr%3Dw-350%2Ch-300%2Cfo-auto"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_5_ByBvwmbWV.jpeg%3Ftr%3Dw-400%2Ch-600%2Cfo-auto"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. Travel &amp;amp; content websites and user-generated images&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Get the most important region in your thumbnails&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ImageKit’s smart crop can automatically determine the most important part in an image, whether it’s a monument or a landscape or a car, and preserve it in the final thumbnail.&lt;/p&gt;

&lt;p&gt;Here are a few examples of the smart crop in action for different kinds of images –&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Original Image&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fikri6hrz7q0a7toxc5p0.png"&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgkkgycnf6k3bmaa80vzj.png"&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Without Smart Crop&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;strong&gt;Mobile Thumbnail&lt;/strong&gt;  200px x 200px&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;Desktop Cover Image&lt;/strong&gt;  800px x 300px (scaled to 60%)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fc7580hxkv4mokzfy0yic.png"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fyn31s5rtn8zwome6f8kw.png"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;With Smart Crop&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;
&lt;strong&gt;Mobile Thumbnail&lt;/strong&gt;  200px x 200px&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;Desktop Cover Image&lt;/strong&gt;  800px x 300px (scaled to 60%)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Frq4vuly2cjdzx5uezfk3.png"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fercirw09amlszctjbl5b.png"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Face thumbnails with smart crop
&lt;/h2&gt;

&lt;p&gt;Till now, we have seen how smart crop works great for bringing the subject to the centre of the image. But there is more to it.&lt;/p&gt;

&lt;p&gt;The smart crop has another &lt;strong&gt;face-cropping mode&lt;/strong&gt; that finds out the face from an image and extracts it to create a thumbnail. This would help in cases where you need to create profile pictures from a user’s photo.&lt;/p&gt;

&lt;p&gt;Here are a few examples of the face-cropping mode in action&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Original Image&lt;/th&gt;
&lt;th&gt;Regular Smart Cropped Image&lt;/th&gt;
&lt;th&gt;Face-cropped Image&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_8_rkOgXV-W4.jpeg%3Ftr%3Dw-500"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_8_rkOgXV-W4.jpeg%3Ftr%3Dw-200%2Ch-200%2Cfo-auto"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_8_rkOgXV-W4.jpeg%3Ftr%3Dw-200%2Ch-200%2Cfo-face"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_9_By_lQN-WE.jpeg%3Ftr%3Dw-500"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_9_By_lQN-WE.jpeg%3Ftr%3Dw-200%2Ch-200%2Cfo-auto"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_9_By_lQN-WE.jpeg%3Ftr%3Dw-200%2Ch-200%2Cfo-face"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_10_ryQQVNZWV.jpeg%3Ftr%3Dw-500"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_10_ryQQVNZWV.jpeg%3Ftr%3Dw-200%2Ch-200%2Cfo-auto"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_10_ryQQVNZWV.jpeg%3Ftr%3Dw-200%2Ch-200%2Cfo-face"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  How to get the face cropping mode for your images?
&lt;/h2&gt;

&lt;p&gt;Again, like every other transformation in ImageKit, this one is really simple as well. You need to set the value of the &lt;code&gt;focus&lt;/code&gt; parameter to &lt;code&gt;face&lt;/code&gt; in your image URL. This is done using the &lt;code&gt;fo-face&lt;/code&gt; parameter in the transformation string in the URL. For example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://ik.imagekit.io/demo/img/tr:w-200,h-200,fo-face/test_image.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Putting it all together with other transforms
&lt;/h2&gt;

&lt;p&gt;Apart from the examples demonstrated above, you can combine smart cropping with other transforms in ImageKit to create really cool user interfaces.&lt;/p&gt;

&lt;p&gt;Let’s say, just like Facebook, you want to create a user’s profile page with a user profile picture and a cover photo. Let’s take these two images for the same.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_9_By_lQN-WE.jpeg%3Ftr%3Dw-500"&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_7_Hyi1-V-b4.jpeg%3Ftr%3Dw-500"&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With the smart crop set to face-crop mode and the radius transformation, we can get a rounded profile picture of the user.&lt;br&gt;&lt;br&gt;
 &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_9_By_lQN-WE.jpeg%3Ftr%3Dw-200%2Ch-200%2Cfo-face%3Ar-max" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_9_By_lQN-WE.jpeg%3Ftr%3Dw-200%2Ch-200%2Cfo-face%3Ar-max"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can then use the regular smart crop and blur transformation to resize the cover photo as per the required size for desktop and mobile devices.&lt;br&gt;&lt;br&gt;
 &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_7_Hyi1-V-b4.jpeg%3Ftr%3Dw-400%2Ch-150%2Cfo-auto%2Cbl-5" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Ftest_image_7_Hyi1-V-b4.jpeg%3Ftr%3Dw-400%2Ch-150%2Cfo-auto%2Cbl-5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Combining these two pictures using HTML and CSS (or in an app), this is how the end result can look like on different devices&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Fsample2_B1vhuVZ-4.png%3Ftr%3Dw-500%2Cf-png"&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2Fsmart_crop_blog%2Fsample1_HJDhu4bWN.png%3Ftr%3Dw-500%2Cf-png"&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using smart crop for your images requires a very small change in your image URLs but it can help you inch closer towards a perfect image experience across devices. Just add fo-auto for general smart crop and fo-face for the face-crop mode of smart crop. It is especially useful if you get a lot of user-generated content or the main subject in the photos is off-centre.&lt;/p&gt;

&lt;p&gt;So, what are you waiting for? Give it a try for your images and start delivering a better experience to your users.&lt;/p&gt;

</description>
      <category>imageoptimization</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>webperf</category>
    </item>
    <item>
      <title>Lazy Loading Images - The Complete Guide</title>
      <dc:creator>Rahul Nanwani</dc:creator>
      <pubDate>Fri, 23 Nov 2018 13:50:37 +0000</pubDate>
      <link>https://dev.to/rnanwani/lazy-loading-images---the-complete-guide-2665</link>
      <guid>https://dev.to/rnanwani/lazy-loading-images---the-complete-guide-2665</guid>
      <description>&lt;p&gt;Images are critical for every website and application today. Whether it is marketing banners, product images or logos, it is impossible to imagine a website without images. Sadly though, images are large in size making them the single biggest contributor to the page size. As per the latest &lt;a href="https://httparchive.org/reports/state-of-images" rel="noopener noreferrer"&gt;HTTP Archive data&lt;/a&gt;, the median page size on desktops is 1511 KB. Images make up for almost 650 KB of that size, roughly 45% of the total page size. Now, since we cannot do away with images, we need to make our web pages load really fast with them. In this guide, we will talk about lazy loading images, a technique that helps improve the page load time and reduce page size while still retaining all the images on the page.&lt;/p&gt;

&lt;h4&gt;
  
  
  A quick glance at what lazy loading achieves
&lt;/h4&gt;

&lt;p&gt;Before moving further, here is a sample video demonstrating the working of lazy loading. Notice how when the page is scrolled, the grey placeholder is replaced with the actual image.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CPmNHj9a0JI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Lazy Loading Images?
&lt;/h3&gt;

&lt;p&gt;Lazy Loading Images refers to a set of techniques in web and application development that defer the loading of images on a page to a later point in time – when those images are actually needed instead of loading them up front. These techniques help in improving performance, better utilization of the device’s resources and reducing associated costs.&lt;/p&gt;

&lt;p&gt;The word “lazy” in the English language is often attributed to the act of avoiding work as long as possible.&lt;/p&gt;

&lt;p&gt;Similarly, lazy loading defers the loading of resources on the page as long as they are not needed. Instead of loading these resources as soon as the page loads, which is what normally happens, we defer the load of these resources to a later time when they are actually needed.&lt;/p&gt;

&lt;p&gt;The technique of lazy loading can be applied to almost all the resources on a page. For example, in a single page application, if a JS file is not needed until later, it is best &lt;a href="https://medium.com/front-end-hacking/lazy-loading-with-react-and-webpack-2-8e9e586cf442" rel="noopener noreferrer"&gt;not to load it initially&lt;/a&gt;. If an image is not needed up front, load it later when it is actually needed.&lt;/p&gt;

&lt;p&gt;Here, we will stick to lazy loading images and how to do it well on your website.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why go for lazy loading images at all?
&lt;/h3&gt;

&lt;p&gt;Lazy Loading defers the loading of an image that is not needed on the page immediately. An image that is not visible to the user when the page loads, is loaded later when the user scrolls and the image actually become visible. If the user never scrolls, an image that is not visible to the user never gets loaded.&lt;/p&gt;

&lt;p&gt;This has two main advantages.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Performance Improvement
&lt;/h4&gt;

&lt;p&gt;The is the most important one for you as a website administrator – better performance and load time. With lazy loading, you are reducing the number of images that need to be loaded on the page initially. Lesser resource requests mean lesser bytes to download and lesser competition for the limited network bandwidth available to the user. This ensures that the device is able to download and process the remaining resources much faster. Hence, the page becomes usable much earlier compared to the case without lazy loading.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Cost reduction
&lt;/h4&gt;

&lt;p&gt;The second benefit for you is in terms of delivery costs. Image delivery, or delivery of any other asset, is usually charged on the basis of the number of bytes transferred. As mentioned earlier, with lazy loading, if the image is not visible, it never gets loaded. Thus, you reduce the total bytes delivered on the page. Especially for users that bounce off the page or interact only with the top portion of the page. This reduction in bytes transferred from your delivery network reduces delivery costs. This will become more apparent as we explore lazy loading in the coming sections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which images can be lazy loaded?
&lt;/h3&gt;

&lt;p&gt;The basic idea of lazy loading is simple – defer loading anything that is not needed right now. For images, it usually translates to, any image that is not visible to the user up front, can be lazy loaded. As the user scrolls down the page, the image placeholders start coming into viewport (visible part of the webpage). We trigger the load for these images when they become visible.&lt;/p&gt;

&lt;p&gt;You can find out which images are a candidate for lazy loading and how many bytes you can save on the initial page load by using the &lt;a href="https://developers.google.com/web/tools/lighthouse/" rel="noopener noreferrer"&gt;Google Lighthouse audit tool&lt;/a&gt;. The audit performed by this tool has a section dedicated for &lt;a href="https://developers.google.com/web/tools/lighthouse/audits/offscreen-images" rel="noopener noreferrer"&gt;offscreen images&lt;/a&gt;. You can also use &lt;a href="https://imagekit.io/website-analyzer" rel="noopener noreferrer"&gt;ImageKit’s website analyzer&lt;/a&gt; to identify if your website uses lazy loading or not apart from other critical image related optimizations on your page.&lt;/p&gt;

&lt;p&gt;Lazy loading is critical not only to good performance but also to deliver a good user experience to your users. Since combining performance and user experience with lazy loading is important and challenging, we will continue to address this topic in more detail throughout this guide after we have looked at different ways to lazy load images.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lazy Loading Techniques for images
&lt;/h3&gt;

&lt;p&gt;Images on a webpage can be loaded in two ways – using the &lt;a href="" class="article-body-image-wrapper"&gt;&lt;img&gt;&lt;/a&gt; tag or using the CSS &lt;code&gt;background&lt;/code&gt; property. We will first look at the more common of the two, the &lt;a href="" class="article-body-image-wrapper"&gt;&lt;img&gt;&lt;/a&gt; tag and then move to CSS background images.&lt;/p&gt;

&lt;h3&gt;
  
  
  The general concept of lazy loading images in &lt;img&gt; tag
&lt;/h3&gt;

&lt;p&gt;Lazy loading images can be broken down into two steps&lt;/p&gt;

&lt;p&gt;Step one is to prevent the image load up front. For images loaded using the &lt;code&gt;&amp;lt;img /&amp;gt;&lt;/code&gt; tag, the browser uses the &lt;code&gt;src&lt;/code&gt; attribute of the tag to trigger the image load. Doesn’t matter if it is the 1st or the 1000th image in your HTML and well off-screen. If the browser gets the &lt;code&gt;src&lt;/code&gt; attribute, it would trigger the image load.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faahq0zm2164ydjg0h5cc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faahq0zm2164ydjg0h5cc.png" width="800" height="60"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thus, to lazyload such images, put the image URL in an attribute other than &lt;code&gt;src&lt;/code&gt;. Let’s say we specify the image URL in the &lt;code&gt;data-src&lt;/code&gt; attribute of the image tag. Now that &lt;code&gt;src&lt;/code&gt; is empty, the browser doesn’t trigger the image load&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvanztf2x8qdkcrz7apmr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvanztf2x8qdkcrz7apmr.png" width="800" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we stopped the upfront load, we need to tell the browser when to load the image. For this, we check that as soon as the image (i.e. its placeholder) enters the viewport, we trigger the load. To check when an image enters the viewport, there are two ways. Let’s look at both of them with working code samples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trigger image load using Javascript events
&lt;/h3&gt;

&lt;p&gt;In this technique, we use event listeners on the scroll, &lt;code&gt;resize&lt;/code&gt; and &lt;code&gt;orientationChange&lt;/code&gt; events in the browser. The scroll event is an obvious one to check when the user scrolls the page. The resize and orientationChange events are equally important for lazy loading. The resize event occurs when the browser window size changes. The orientationChange event gets triggered when the device is rotated from landscape to portrait mode or vice versa. In such cases, the number of images that become visible on the screen will change. Thus, we would need to trigger a load for these images.&lt;/p&gt;

&lt;p&gt;When either of these events occurs, we find all the images on the page that are to be lazy loaded and have not yet been loaded. From these images, we check which ones are now in the viewport. This is done using the image’s top offset, the current document scroll top and window height. If it has entered the viewport, we pick the URL from &lt;code&gt;data-src&lt;/code&gt; attribute and put it in the src attribute. This triggers the image load. We also remove the class lazy that identifies the images to be lazily loaded for events that trigger later. Once all the images are loaded, we remove the event listeners.&lt;/p&gt;

&lt;p&gt;When we scroll, the scroll event triggers multiple times rapidly. Thus, for performance, we add a small timeout that throttles the lazy loading function execution.&lt;/p&gt;

&lt;p&gt;Here is a working example of this approach.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/imagekitio/embed/MBNwKB?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you would have noticed, the first 3 images in the example are loaded up front. The URL is present directly in the src attribute instead of the &lt;code&gt;data-src&lt;/code&gt; attribute. This is essential for a good user experience. Since these images are at the top of the page, they should be made visible as soon as possible. We must not wait for an event or JS execution to load them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Intersection Observer API to trigger image loads
&lt;/h3&gt;

&lt;p&gt;Intersection Observer API is a relatively new API in browsers. It makes it really simple to detect when an element enters the viewport and take an action when it does. In the previous method, we had to bind events, keep performance in mind and implement a way to calculate if the element was in the viewport or not. The Intersection Observer API makes this really simple, helps avoid the math and delivers great performance.&lt;/p&gt;

&lt;p&gt;Below is an example of using the Intersection Observer API to lazy load images. We attach the observer on all the images to be lazy loaded. Once the API detects that the element has entered the viewport, using the &lt;code&gt;isIntersecting&lt;/code&gt; property, we pick the URL from the data-src attribute and move it to the src attribute for the browser to trigger the image load. Once this is done, we remove the lazy class from the image and also remove the observer from that image.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/imagekitio/embed/BPXQZZ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you compare the image loading times for the two methods, event listeners vs Intersection Observer, you would find that using the Intersection Observer API, the image load is triggered much quicker and yet the site doesn’t appear sluggish on scrolling. In the method involving event listeners, we had to add a timeout to make it performant, which has a slightly negative impact on the user experience as the image load is triggered with a slight delay.&lt;/p&gt;

&lt;p&gt;However, like everything new in browsers, the &lt;a href="https://caniuse.com/#feat=intersectionobserver" rel="noopener noreferrer"&gt;support for Intersection Observer API&lt;/a&gt; is not available across all browsers. So, we need to fallback to the event listener method in browsers where the Intersection Observer API is not supported. We have taken this into account in the example above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lazy Loading CSS Background Images
&lt;/h2&gt;

&lt;p&gt;After &lt;code&gt;&amp;lt;img /&amp;gt;&lt;/code&gt; tags, background images are the most common way to load images on a webpage. For &lt;code&gt;&amp;lt;img /&amp;gt;&lt;/code&gt; tags, the browser has a very simple approach – if the image URL is available, let’s load the image.&lt;/p&gt;

&lt;p&gt;With CSS background images it is not that straightforward. To load CSS background images, the browser needs to build the DOM (Document Object Model) tree as well as the CSSOM (CSS Object Model) tree to decide if the CSS style applies to a DOM node in the current document. If the CSS rule specifying the background image does not apply to an element in the document, then the browser does not load the background image. If the CSS rule is applicable to an element in the current document, then the browser loads the image.&lt;/p&gt;

&lt;p&gt;This may seem complex at first, but, this same behavior forms the basis of the technique for lazy loading background images. Simply put, we trick the browser into not applying the &lt;code&gt;background-image&lt;/code&gt; CSS property to an element, till that element comes into the viewport.&lt;/p&gt;

&lt;p&gt;Here is a working example that lazy loads a CSS background image.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/imagekitio/embed/RBXVrW?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;One thing to note here is that the Javascript code for lazy loading is still the same. We are using the Intersection Observer API method with a fallback to the event listeners. The trick lies in the CSS.&lt;/p&gt;

&lt;p&gt;The element with ID bg-image has a &lt;code&gt;background-image&lt;/code&gt; specified in the CSS. However, when the class lazy is added to this element, in the CSS we override the &lt;code&gt;background-image&lt;/code&gt; property and set it to none. Since the rule, combining &lt;code&gt;#bg-image&lt;/code&gt; with &lt;code&gt;.lazy&lt;/code&gt; class has a higher preference in CSS than just &lt;code&gt;#bg-image&lt;/code&gt;, the browser applies the property &lt;code&gt;background-image: none&lt;/code&gt; to the element initially. When we scroll down, the Intersection Observer (or event listeners) detects that the image is in the viewport, it removes the class &lt;code&gt;lazy&lt;/code&gt;. This changes the applicable CSS and applies the actual background-image property to the element triggering the load of the background image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ik.imagekit.io/demo/img/Lazy_Loading_Images_Infographic_S1h5Jc-HE.png?tr=f-png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fik.imagekit.io%2Fdemo%2Fimg%2FLazy_Loading_Images_Infographic_S1h5Jc-HE.png%3Ftr%3Dw-1200%3Acm-extract%2Cw-1200%2Ch-355%2Cfo-top%2Cf-png%3Aobg-000000%2Cofo-bottom%2Cow-1200%2Coh-50%3Aot-Download%2520the%2520Full%2520Infographic%2Cox-490%2Coy-N15%2Cotc-FFFFFF%2Cots-16" alt="Download the full infographic" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Better user experience with lazy loading images
&lt;/h3&gt;

&lt;p&gt;Lazy loading presents a great performance benefit. For an e-commerce company that loads hundreds of product images on a page, lazy loading can provide a significant improvement in initial page load time while decreasing the bandwidth consumption. However, a lot of companies do not opt for lazy loading, because they believe it goes against delivering a great user experience – the initial placeholder is ugly, the load times are slow etc. In this section, we will try to solve some concerns around user experience with lazy loading of images.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Using the right image placeholders
&lt;/h4&gt;

&lt;p&gt;A placeholder is what appears in the container until the actual image is loaded. Normally, we see developers using a solid color placeholder for images or a single image as a placeholder for all images.&lt;/p&gt;

&lt;p&gt;We used the same in our example code as well. A solid light grey color is used for all our image backgrounds. However, we can do better to provide a more pleasing user experience. Below are some examples of using better placeholders for our images.&lt;/p&gt;

&lt;h4&gt;
  
  
  a. Dominant color placeholder
&lt;/h4&gt;

&lt;p&gt;Instead of using a fixed color for the image placeholder, we find the dominant color from the original image and use that as a placeholder. This technique has been used for quite some time in Google image search results and Pinterest.&lt;/p&gt;

&lt;p&gt;Sample image picked from &lt;strong&gt;&lt;a href="https://manu.ninja/dominant-colors-for-lazy-loading-images/" rel="noopener noreferrer"&gt;Manu.ninja&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxp1z14kn7nbhm4bkz3v.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsxp1z14kn7nbhm4bkz3v.gif" width="720" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This might look complex to achieve. But, a very simple way of accomplishing this is to first scale down the image to a 1×1 pixel and then scale it up to the size of the placeholder – a very rough approximation but a simple, no-fuss way to get a single dominant color. Using ImageKit, the dominant color placeholder can be obtained using a chained transform in ImageKit as shown below.&lt;/p&gt;

&lt;h4&gt;
  
  
  Dominant color placeholder image URL example using ImageKit
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwv3nn8nu8664qdubg1ci.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwv3nn8nu8664qdubg1ci.png" width="800" height="163"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The placeholder image is just 661 bytes in size compared to the original image that is 12700 bytes – &lt;strong&gt;19x&lt;/strong&gt; smaller. And it provides a nicer transition experience from placeholder to the actual image.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here is a video demonstrating how this effect works for the user.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/wJEoRz3P3EU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You can view the &lt;a href="https://codepen.io/imagekit_io/embed/WgvmZj" rel="noopener noreferrer"&gt;working example and code for using dominant color placeholder here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  b. Low quality image placeholder (LQIP)
&lt;/h4&gt;

&lt;p&gt;We can extend the above idea of using a dominant color placeholder further. Instead of using a single color, we use a very low-quality, blurred version of the original image as the placeholder. Not only does it look better, it also gives the user some idea about what to expect in the actual image and gives the perception that the image load is in progress. This is great for improving the perceived loading experience. This technique has been utilized by the likes of Facebook and Medium.com for images on their websites and apps.&lt;/p&gt;

&lt;h4&gt;
  
  
  LQIP image URL example using ImageKit
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57eguufivwlv7uzrwx2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57eguufivwlv7uzrwx2h.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The LQIP is 1300 bytes in size, still almost 10x smaller than the original image and a significant improvement in terms of visual experience over any other placeholder technique.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here is a video demonstrating how this effect works for the user.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/BXoNamwkqi0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You can view the &lt;a href="https://codepen.io/imagekit_io/embed/WgvmZj" rel="noopener noreferrer"&gt;working example and code for using LQIP technique here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is clearly evident from the video samples of the two techniques above, that using dominant-color placeholders or using low-quality image placeholders provides a smoother transition from the placeholder to the actual image, gives the user an idea of what is to come in place of that placeholder and improves loading perception.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Adding some buffer time for image load
&lt;/h4&gt;

&lt;p&gt;When we discussed different methods to trigger image load above, we checked for the point of time where the image enters the viewport i.e. image load is triggered when the top edge of the image placeholder, coincides with the bottom edge of the viewport.&lt;/p&gt;

&lt;h4&gt;
  
  
  The problem
&lt;/h4&gt;

&lt;p&gt;Often, users scroll really fast through the page and the image will need some time to load and appear on the screen. In this scenario, combined with the fact that the load image event might be triggered with a delay because of throttling, you would often face the scenario where the placeholders come into the viewport, the user waits for a few milliseconds and then the image shows up. This delay makes for a poor user experience.&lt;/p&gt;

&lt;p&gt;While using Intersection Observers to load the image or using low-quality image placeholders provides better loading performance and user experience, there is another simple trick that you can use to ensure that the images are always loaded completely when they enter the viewport – introduce a margin to the trigger point for images.&lt;/p&gt;

&lt;h4&gt;
  
  
  The solution
&lt;/h4&gt;

&lt;p&gt;Instead of loading the image just when they exactly enter the viewport, load the images when they are, let’s say, 500px away from entering the viewport. This provides additional time, between the load trigger and the actual entry in the viewport, for the images to load.&lt;/p&gt;

&lt;p&gt;With the Intersection Observer API, you can use the &lt;code&gt;root&lt;/code&gt; parameter along with the &lt;code&gt;rootMargin&lt;/code&gt; parameter (works as standard CSS margin rule), to increase the effective bounding box that is considered to find the “intersection”. With the event listener method, instead of checking for the difference between the image edge and the viewport edge to be 0, we can use a positive number to add some threshold.&lt;/p&gt;

&lt;p&gt;The example &lt;a href="https://codepen.io/imagekit_io/embed/gdbYwV/" rel="noopener noreferrer"&gt;here&lt;/a&gt; uses a 500px threshold to load images.&lt;/p&gt;

&lt;p&gt;As evident from the video below (monitor the network requests closely appearing at the bottom), while scrolling, when the third image is in view, the 5th image gets loaded. When the 4th image comes into the view, the 6th image gets loaded. This way we are giving sufficient time for the images to load completely and in most cases, the user won’t see the placeholder at all.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Zb65sdby7NI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;And if you didn’t notice earlier, in all our examples, the third image (image3.jpg) is always loaded up front, even though it is outside the viewport. This was also done following the same principal – load slightly in advance instead of loading exactly at the threshold for better user experience.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Avoiding content shifting with lazy loading
&lt;/h4&gt;

&lt;p&gt;This is another trivial point, which if solved, can help maintain a good user experience.&lt;/p&gt;

&lt;h4&gt;
  
  
  The problem
&lt;/h4&gt;

&lt;p&gt;When there is no image, the browser doesn’t know the dimensions of the content that is to be displayed in the enclosing container. And if we do not specify it using CSS, the enclosing container would have no dimensions i.e. 0 x 0 pixels. Then, when the image gets loaded, the browser would resize the enclosing container to fit the image. This sudden change in the layout causes other elements to move around and it is called content shifting. As demonstrated in this &lt;a href="https://www.smashingmagazine.com/2016/08/ways-to-reduce-content-shifting-on-page-load/" rel="noopener noreferrer"&gt;content shifting article&lt;/a&gt; &amp;amp; video from Smashing Magazine, it is a rather unpleasant experience for a user, as the content moves suddenly when the image loads.&lt;/p&gt;

&lt;h4&gt;
  
  
  The solution
&lt;/h4&gt;

&lt;p&gt;This can be avoided by specifying a height and/or width for your enclosing container so that the browser can paint the image container with a known height and width. Later, when the image loads, since the container size is already specified and the image fits into that perfectly, the rest of the content around that container does not move.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Do not lazy load all the images
&lt;/h3&gt;

&lt;p&gt;This is another mistake that developers often commit – lazy load all the images on the page. This might reduce the initial page load, but would also result in bad user experience as a lot of images even at the top of the webpage won’t show up till the Javascript gets executed.&lt;/p&gt;

&lt;p&gt;We can follow some general principles to identify which images should be lazy loaded.&lt;/p&gt;

&lt;p&gt;a. Any image that is present in the viewport, or at the beginning of the webpage, should not be lazy loaded. This applies to any header image, marketing banner, logos etc. as the user should see them as soon as the page loads. Also, remember that mobile and desktop devices will have different screen sizes and hence a different number of images that will be visible on the screen initially. So you need to take into account the device type to decide which resources to load up front and which to lazy load.&lt;/p&gt;

&lt;p&gt;b. Any image that is just slightly off the viewport should not be lazy loaded. This is going by the principle discussed above – load slightly in advance. So let’s say any image that is 500px or a single scroll from the bottom of the viewport can be loaded up front as well.&lt;/p&gt;

&lt;p&gt;c. If the page isn’t lengthy, may be just a single scroll or a couple of scrolls, or if there are less than 5 images outside the viewport, then lazy loading can be avoided altogether. It would not provide any significant benefit to the end user in terms of performance. The additional JS that you load on the page to enable lazy loading will offset the gain from lazy loading such a small number of images.&lt;/p&gt;

&lt;h3&gt;
  
  
  Javascript dependency of Lazy Loading
&lt;/h3&gt;

&lt;p&gt;The entire idea of lazy loading is dependent on the availability of Javascript execution capabilities in the user’s browser. While most of your users would have Javascript execution enabled in their browser, as it is essential for almost all websites these days, you may want to plan for users that do not allow javascript execution in the browser or use a browser that doesn’t support javascript at all.&lt;/p&gt;

&lt;p&gt;You could either show them a message telling them why the images won’t load and that they need to switch to a modern browser or enable Javascript. Or you can use the noscript tag to create a usable experience for these users as well. Using the  tag approach for such users has some gotchas. This &lt;a href="https://stackoverflow.com/questions/29145354/dry-lazy-loaded-images-with-noscript-fallback" rel="noopener noreferrer"&gt;question thread on Stack Overflow&lt;/a&gt; does a great job addressing these concerns and is a recommended read for anyone looking to address this set of users.&lt;/p&gt;

&lt;p&gt;Popular Javascript libraries for lazy loading on your website&lt;br&gt;
Since browser environments and implementation details can vary across browsers and devices, it is best to use a tried and tested library for lazy loading. Here is a list of popular libraries and platform specific plugins that will allow you to implement lazy loading with minimal effort&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/malchata/yall.js" rel="noopener noreferrer"&gt;yall.js (Yet Another Lazy Loader)&lt;/a&gt; – Uses Intersection Observer and falls back to event-based lazy loading. Supports all major HTML element types but not background-images. Works on IE11+ as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aFarkas/lazysizes" rel="noopener noreferrer"&gt;lazysizes&lt;/a&gt; – Very popular and extensive functionality. Supports responsive images srcset and sizes attribute as well. High performance even without Intersection Observer.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://jquery.eisbehr.de/lazy/" rel="noopener noreferrer"&gt;jQuery Lazy&lt;/a&gt; – A simple, jquery based lazy loading library.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.weltpixel.com/magento-2-lazy-loading-enhanced.html" rel="noopener noreferrer"&gt;WeltPixel Lazy Loading Enhanced&lt;/a&gt; – A Magento 2 extension for lazy loading images&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.mgt-commerce.com/magento-lazy-load-images.html" rel="noopener noreferrer"&gt;Magento Lazy Image Loader&lt;/a&gt; – A Magento 1.x extension for lazy loading images&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.shopify.com/lazy-image" rel="noopener noreferrer"&gt;Shopify Lazy Image Plugin&lt;/a&gt; – A Shopify extension for lazy loading images. It is paid though.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://wordpress.org/plugins/a3-lazy-load/" rel="noopener noreferrer"&gt;WordPress A3 Lazy Load&lt;/a&gt; – Image lazy loading plugin for WordPress&lt;/p&gt;

&lt;p&gt;How to test if lazy loading is working?&lt;br&gt;
Once you have implemented lazy loading, you would want to check if the behaviour of images on your website is as intended. The simplest way would be to open up developer tools in Chrome browser.&lt;/p&gt;

&lt;p&gt;Go to Network Tab &amp;gt; Images. Here, when you refresh the page for the first time only the images that are to be loaded up front should get loaded. Then as you start scrolling down the page, other image load requests would get triggered and loaded. You can also notice the timings for image load in the waterfall column in this view. It would help you identify image loading issues if any or issues in triggering the image load.&lt;/p&gt;

&lt;p&gt;Another way would be to run the Google Chrome Lighthouse audit report on your page after you have implemented the changes and look for suggestions under the &lt;a href="https://developers.google.com/web/tools/lighthouse/audits/offscreen-images" rel="noopener noreferrer"&gt;“Offscreen images” section&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;We have covered almost everything related to lazy loading images in this guide. Lazy loading if implemented correctly will significantly improve the loading performance of your web pages, reduce page size and delivery costs by cutting down on unnecessary resources loaded up front, while keeping the necessary content intact on the page. Your users would love it too when they get a great experience with the faster loading pages.&lt;/p&gt;

&lt;p&gt;So, what are you waiting for? Get started with lazy loading images now!&lt;/p&gt;

</description>
      <category>lazyloadingimages</category>
      <category>imageoptimization</category>
      <category>webperf</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
