INP Metric: 7 Tips for Optimization

The interactivity metric Interaction to Next Paint (INP) is a crucial part of Core Web Vitals. For some clients, we also see its connection to business indicators.

However, INP isn’t exactly the simplest metric to optimize. Drawing from our practice, we’ve identified the most common problems and ways to solve them.

1) Optimize the Number of DOM Elements on the Page

The number of DOM elements on a page often directly affects the performance of functions that manipulate the DOM in JavaScript. The more DOM elements, the larger the dataset JavaScript must traverse, increasing the time it takes.

A large DOM can elevate the INP metric, especially during hydration if your pages are powered by JavaScript frameworks like React.js. Third-party analytics scripts, such as the TikTok pixel, that scan pages and their information can also cause issues.

According to our experience (and Google’s recommendations), an ideal DOM size is up to 1,500 elements. If your site exceeds this, consider optimization. Components like megamenus or extensive filtering options in categories often inflate the DOM element count.

INP Optimization by Simplifying the Megamenu On this website, we improved the INP metric by simplifying the DOM complexity in the megamenu while maintaining SEO links, resulting in a significant performance boost.

Optimizing the INP metric can be achieved by reducing the complexity of elements (preserving content for SEO but lazy-loading surrounding elements) or loading elements outside the initial view only after a scroll using the Intersection Observer.

2) Minimize the Number of Resource-Intensive Scripts like Hotjar, Smartlook, TikTok Pixel, etc.

Indiscriminate deployment of third-party code can quickly put your site’s INP metric in jeopardy. We often encounter situations where analytic tools collect data that no one monitors.

Sometimes data is only needed for a limited period, but the code remains on the site even after measurement ends. Collaborate with your marketing team to assess whether some analytic tools are unnecessarily running on your sites. If they are, remove the code entirely.

We recommend performing such maintenance at regular intervals, especially if the site is under long-term development with multiple departments independently involved.

With our PLUS monitoring, you can measure the impact of third-party components using the 3PBT metric.

3) Update Components to Newer Versions

In our analyses, we encounter situations where outdated JavaScript component versions cause high INP after interactions.

For instance, an older version of the Fancybox modal can create long tasks on click, elongating interaction time.

Long Task from Fancybox A long task in JS created by an older version of Fancybox.

It’s wise to review the components used in your project and update them to newer versions as part of routine maintenance.

Replacing certain components altogether can also help, especially with resource-intensive carousels like Owl or Slick. Look for carousels that don’t use absolute positioning and recalculating the left property in CSS but instead use the transform property. An example is Embla.

4) Intersection Observer: Defer Initialization of Heavy Components Not in the First Viewport

Another optimization strategy is deferring the initialization of heavy components, such as carousels mentioned earlier. If components are outside the first viewport, there’s no need to initialize them on the first load. Instead, wait and initialize them as the user approaches while scrolling using the Intersection Observer API.

let observer = new IntersectionObserver(callback, options);
let target = document.querySelector('#lazy-component');

observer.observe(target);

Another option is to await browser idle time using Idle Request Callback.

5) Break Down Long Tasks in JavaScript

The best JavaScript is the one that isn’t there. JavaScript code can create, and often does create, long tasks (measurable with the JS Long Tasks (JSLT) metric). These tasks need breaking down into smaller ones that execute sequentially without blocking the browser’s main thread.

An effective way to break down Long Tasks is by wrapping the code in a setTimeout function. This technique is useful for distributing interactions with lots of analytic code that hinders crucial operations.

setTimeout(() => {
	code_deferred_to_next_render();
}, 0);

In the future, keep an eye on scheduler.yield() or the Long Animation Frames API.

6) Don’t Keep Users Waiting

If you anticipate a long request processing time (such as AJAX/fetch) after user interaction (click, tap, keyboard input, etc.), ensure a change in the display on the user’s screen. The visual change should occur as soon as possible, ideally within Google’s 200 ms limit, and display a loading indicator to users post-interaction.

INP Optimization Through Interactions

7) Optimize React, Not Just Hydration

Let’s pause on React optimization and similar frameworks for a moment. Many problems arise during hydration, the moment the site comes to life.

During hydration, the browser processes all available resources and assembles a page that can now respond to user inputs. This process puts a significant load on the browser and results in many long tasks (measurable with the JS Long Tasks (JSLT) metric).

Hydration in React The Performance panel within Chrome DevTools shows the impact of hydration.

The good news is that you can optimize hydration. From the methods we employ, we’ve selected the following:

  • Reduce DOM size
  • Create two versions of components: simple and full-featured
  • Use <Suspense>
  • Beware of hydration errors
  • Be cautious with useEffect()
  • Utilize Server Components

Read our comprehensive guide on React optimization.

We cover the optimization of Core Web Vitals metrics comprehensively, so be sure to check out our other articles: