Optimize Image Loading Performance with Intersection Observer
A modern approach to improving web performance without external libraries
Search for a command to run...
A modern approach to improving web performance without external libraries
No comments yet. Be the first to comment.
TL;DR: TanStack Start hit v1.0 in 2025 and is the first React framework to seriously challenge Next.js since Remix. Inngest migrated and saw an 83% drop in dev page load times (10s → 2s). Railway move
TL;DR: Next.js dominates with ~60% usage, but satisfaction has cratered to 55% — a 39-point gap behind Astro. Cloudflare rebuilt 94% of Next.js in one week for $1,100. The framework that's right for y
TL;DR: React Server Components are the default in Next.js 15+ and React 19. They can slash JavaScript bundles by 40–75% and cut LCP by up to 67% — but only if you architect them correctly. 67% of deve
TL;DR: AI coding tools have crossed the threshold from "cool experiment" to "daily infrastructure" for frontend developers. 84% of developers now use or plan to use AI tools — but trust is falling as
TL;DR: continue skips the current loop iteration, break exits the entire loop, and return exits the entire function. Knowing which one to reach for can make your code dramatically cleaner and more int
Arunkumarvelu
11 posts
The majority of software engineers today would love to focus on the latest and greatest framework, technology, or library. However, not many of these engineers would care to look at some basics of the trade that can immediately improve the loading time of web apps. One such technique is ‘image lazy load’ levering lazy loading images, which happens when the images are outside the viewport. You can read more about lazy loading images here.
The Internet is full of ways to improve the performance of your web applications, but the most popular ones are CDN, image compression, and lazy loading.
In this blog, we will talk about tackling lazy load images with Intersection Observer API. By leveraging lazy loading images, we managed to save around 200% data and reduce the app loading time to 68%.

Usually in <img> when we type in the URL, it automatically downloads images even if it is outside the viewport. By using Intersection Observer we can download and render images on demand when the image DOM intersects with the viewport.
The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document’s viewport, which was introduced in 2017.
Intersection Observer is the more popular method for visibility detection over more traditional methods, such as onScroll + getBoundingClientRect() because the actual detection implementation doesn’t run on the main thread. However, the callback for when an intersection has been triggered does run on the main thread so remember to keep it light!
For context, I’m going to share with you the problem we faced with Freshchat and how we fixed it using Intersection Observer. Before delving into the details, I would first like to share the results of our fix. With Optimization Observer, we saved around 67% of data that was not in viewport. As a result of the data reduction, we managed to reduce DOM manipulation, and decrease the loading time of the app to 68%.
When user log in, they land on the Inbox page, which contains a list of conversations with visitor images. Every conversation has agents and visitors with profile images who are involved in this conversation, and also messages containing images. By using Intersection Observer, images are lazy loaded to improve the performance of the app.
It’s simple. Just follow these steps:
In HTML,
Add the image url to data-src instead of src in <img>
Note: If we add it directly to src, the browser automatically starts the download.

In Javascript,
Create a new instance of Intersection Observer with the callback function ‘observe’. Ask an observer to observe that image element.
Notice when an intersection was triggered between the root and target elements. In our case, the elements were the top-level document’s viewport and img.lazy ref respectively.


We downloaded all the images from all 40 conversations, visitor images, and selected conversations with images even those that were not in viewport. The total data we have downloaded is 1.1MB of image resources and also the time taken to render was 3.45s.

The total data we have downloaded was 373KB of image resources and also time taken to render was 2.31s. Around 200% of bandwidth usage was saved, reducing the loading time of the app to 68%.

Using Intersection Observer API, we saved around ~740KB of data, ~1.14s of rendering time. We successfully reduced LCP to ~2.9s and interactive and blocking time. Around 200% of bandwidth usage was saved and the loading time of the app was brought down to 68%.
This is a better approach than the traditional way of dealing with lazy load because—and I reiterate—the actual detection implementation doesn’t run on the main thread.
References: