Learn / Blog / Article
Lazy loading: when to use it and why you should
Lazy loading or loading content on demand is the process of identifying resources that are non-blocking to a website and delaying their loading or initialization until the page needs them.
This article outlines the benefits of loading content on demand, how to do it, and when the technique should be applied. We’ll also share how we use lazy loading at Hotjar.
💡 A quick caveat: in providing these tips, we assume all essential performance-related implementations already exist on your website and that, like us, your goal is to optimize page load time and Largest Contentful Paint (LCP) further.
Let’s dive in.
Hotjar elevates your user experience
Hotjar tools like Heatmaps, Recordings, Surveys, Feedback, and Interviews help you put your customers at the heart of your decisions and create experiences people love.
Why is lazy loading important?
You’ve done everything right: content delivery network (CDN) setup, file compression enablement, static JS and CSS file minification, and resource caching. You’ve been sure to follow good coding standards and promote the reusability of components. Now, you’re monitoring your website’s performance and hoping for the best.
But even after all this work, your page still takes too long to load.
You measure your loading time using a performance monitoring tool. As you suspected, it returns a poor score. But the problem is that none of your website resources can be removed—they're all crucial elements of your site in one way or another.
This is when lazy loading comes in.
4 key benefits of lazy loading
Lazy loading has several benefits, but these are four of the biggest:
Reducing the initial web page load time by reducing the total size of resources downloaded
Conserving the user's bandwidth, especially keeping in mind mobile data plans on mobile devices
Conserving system resources, as requests to the server are made only when needed
Avoiding unnecessary code execution
You might be wondering: don’t I need all the resources included in our website? Is there anything we could load on demand?
Answer: there's almost always something you don't need immediately.
Start by identifying the level of importance of the resources. Some resources might not be ideal to lazy load, such as main JS bundles, main CSS styles, fonts, and analytics packages that need to be available on the initial website load.
When to implement lazy loading
The most common resources to lazy load include:
Bundle JS files
Vendor or third-party JS files
CSS files
Images
As your website grows, so does the final bundle of JS and CSS files. To use this technique effectively, you need to split the JS bundles and CSS files.
The traditionally bulky file holding JS, and another hefty file containing CSS, are no longer an option for the modern front-end tech world we live in. Once you’ve completed this critical step, you’re ready to reap the benefits of lazy loading.
🔥 7 scenarios where lazy loading is beneficial
Loading JS bundles that aren't used on the currently viewed page but are used on other pages of the website
Loading JS components and any library backing them up immediately instead of when that component is viewable on the page
Using a third-party JS library which is only required on a specific page. Such libraries can be for ready-made features, JS utility libraries, animations, analytics, or monitoring purposes.
Loading CSS-style files for the entire website rather than loading only the style files needed for the viewable page
Loading a collection of images that aren't visible to the user until the user scrolls to a particular part of the page
Loading of a resource when a specific DOM event has been triggered, such as resize or click
At a specific state within your website, such as after submitting a form and showing a submission success component that might be animation-heavy
How Hotjar uses lazy loading in a React application
At Hotjar, we constantly strive to keep our website—our most important sales rep—at a solid performance score.
Why do we care so much about performance? Because it results in:
Increased conversion rates
More page views
Higher search engine rankings
Lower server bandwidth costs
Smoother usability on different devices
Our website is a Next.js application. Thus, we rely heavily on the ReactJS library and its available components.
For images, we use the Next.js-provided component, which lazy loads automatically. This means we no longer have to worry about our website suffering from overheads not displaying at that moment in time. Instead, images automatically load and display once the scroll position of a specific image reaches the browser's viewport.
Our discovery
When analyzing our resources on page load, Webpack Bundle Analyzer helped us identify a specific external library used by our website that was adding an overhead of 67.3kB on every page refresh. As you can see below, Webpack Bundle Analyzer’s output reveals lottie.js as one of the large libraries immediately downloaded on our page load.
(We also discovered this library was only used at the bottom of the page, to render a nice animation once a subset of components was in the viewport.)
Lazy loader implementation
Our idea was to create a new component (called LazyLoadOnScroll) to wrap other React components. The logic behind it uses a hook that benefits from the browser’s Observer tools, specifically the IntersectionObserver. Any components wrapped with this won’t render, and any underlying external files, libraries, or JS files won’t download.
Once the user starts to scroll and this component is about to come into view, the IntersectionObserver returns a value of 'true', meaning the component is about to intersect the viewport. At this point in time of scrolling, everything begins downloading, and React renders the component accordingly, making it appear to the user as if items are seamlessly being served on demand.
The new files introduced are the following:
useIntersectionObserver: this is the hook responsible for observing the provided component ref via an IntersectionObserver instance to return 'true' or 'false' as to whether the ref has intersected the viewport. It can also be extended by providing additional config props, but our use case required only the most basic implementation. This includes a check to make sure the browser supports IntersectionObserver; otherwise, it will return 'true' to render the content immediately every time.
LazyLoadOnScroll: this is a React functional component that uses the useIntersectionObserver hook. It contains a statement checking whether the hook is being run on a server. If it is on a server, Next.js ‘Server Side Renderer’ will present the page to the client. The hook always returns 'true' so as not to lazy load anything, and the full page is generated for SEO purposes. When this component is initiated, it sets the children to render once the hook returns 'true'. The process occurs once, and the component does nothing else but keep the children in the rendered document.
Putting it into practice
Implementing it is as simple as wrapping any component you want to lazy load. Plus, there’s no need to worry about extra overheads on page load.
The end result
For our performance measurement, we've used Chrome's devtool, Lighthouse, to generate a report before and after implementation. Results were fascinating, specifically our Desktop scores.
From an overall score of 87 on performance and an LCP of 1.9 seconds…
…we managed to go up to an overall score of 93 on performance and an LCP of 1.5 seconds.
These results gave us the assurance that loading content on demand does impact our overall website experience. Applying it further to other corners of our site ensures that no unnecessary overheads block our pages from loading as fast as possible—helping us give our users an experience they’ll love.
Hotjar elevates your user experience
Hotjar tools like Heatmaps, Recordings, Surveys, Feedback, and Interviews help you put your customers at the heart of your decisions and create experiences people love.
Related articles
Hotjar's tech blog
Modernizing Hotjar’s architecture for a faster flow of value
In this article, we examine how we modernized Hotjar's architecture (note that Hotjar was acquired by Contentsquare in 2021) to deliver value faster to our customers. We start by explaining why we needed to modernize it and which principles guided us throughout the journey. Our aim is to provide insights into how these changes helped us improve and adapt in a rapidly evolving market.
Pavel Krayzel
Hotjar's tech blog
The power and pitfalls of regular expressions
‘Put our customers at the heart of everything’ is Hotjar's foremost core value. In line with this principle, our top priorities are protecting and being consistently available to our users. Regular expressions, or regex, are commonly employed to safeguard web services against harmful inputs. But they can also (somewhat ironically) become a source of vulnerability if not meticulously constructed.
Miloslav Pavelka
Hotjar's tech blog
How we optimized perceived performance to improve our KPIs: a Hotjar case study
No one likes to wait. Even at a nice restaurant, if the food takes too long to arrive, you’ll start wriggling on your chair and looking around for the waiter. Worst case, you might even leave.
This is nothing new: people are impatient by nature, and your users are no different. If you ask them to wait too long for their requested content, they’ll enjoy the experience less and eventually drop off.
Eryk Napierała