Economic Times quest for fixing INP

Bringing down TBT by 30 times and migrating to Next.js helped The Ecomonic Times reduce INP nearly four times, leading to a 50% decrease in bounce rate and 43% uplift in pageviews.

Daya Ram Yadav
Daya Ram Yadav
Saurabh Rajpal
Saurabh Rajpal

Interaction to Next Paint (INP) is a metric that assesses a website's responsiveness to user input. Good responsiveness means that a page is quick to respond to user interactions. The lower a page's INP is, the better it is able to respond to user interactions.

Good INP values are 200 milliseconds or less, poor values are greater than 500 milliseconds, and anything in between needs improvement.

The fuzzy beginning

When Google initially introduced INP as an experimental metric with the potential to evolve into one of the Core Web Vitals metrics, the Economic Times team took up the challenge to fix it before it graduates into one, since providing a world class user experience is crucial to our core business values.

INP has been one of the most difficult metrics to solve thus far. In the beginning, it was unclear on how to measure INP effectively. What made it more difficult was the lack of community support—including most Real User Monitoring (RUM) providers not supporting it yet. However, we had Google RUM tools like Chrome User Experience Report (CrUX), the web-vitals JavaScript library, and others supporting it, which gave us a sense of where we stood while we were evaluating the path ahead. Our INP was close to 1,000 milliseconds at the origin level when we started.

One thing that emerged while fixing INP in the field was that one of the lab metrics to target could be Total Blocking Time (TBT). TBT was already well documented and supported by the community. Despite already meeting the thresholds for Core Web Vitals, however, we weren't doing as well on the TBT front, as it was over 3 seconds when we began.

What is TBT, and what steps did we take to improve it?

TBT is a lab metric that measures the responsiveness of a web page to user input during page load. Any task that takes more than 50 milliseconds to execute is considered a long task, and the time after the 50 millisecond threshold is known as the blocking time.

TBT is calculated by taking the sum of the blocking time of all long tasks during page load. For example, if there are two long tasks during load, the blocking time is determined as follows:

  • Task A takes 80 milliseconds (30 milliseconds more than 50 milliseconds).
  • Task B takes 100 milliseconds (50 milliseconds more than 50 milliseconds).

The page's TBT will be: 80 milliseconds (30 + 50). The lower the TBT, the better, and TBT also correlates well with INP.

Here’s a quick lab comparison of our TBT before and after taking steps to improve it:

A composite image of long tasks during startup as shown in the performance panel of Chrome DevTools, and a report of page metrics. The main thread is blocked during page load for 3,260 milliseconds.
The main thread during startup before optimizing TBT. The TBT is 3,260 milliseconds.
A composite image of long tasks during startup as shown in the performance panel of Chrome DevTools, and a report of page metrics. The main thread is blocked during page load for 120 milliseconds.
The main thread during startup after optimizing TBT. The TBT is 120 milliseconds.

Minimize main thread work

The browser’s main thread handles everything from parsing HTML, building the DOM, to parsing CSS and applying styles, as well as evaluating and executing JavaScript. The main thread also handles user interactions—that is, click, tap, and keypresses. If the main thread is occupied with doing other work, it may not respond to user inputs efficiently, and may lead to a janky user experience.

This was the most difficult task for us, since we have our own algorithms to detect user identity for serving ads based on subscription status and third party scripts for A/B testing, analytics, and more.

We took small steps at first, such as de-prioritizing loading of less critical business assets. Second, we used requestIdleCallback for non-critical work, which can help to reduce TBT.

if ('requestIdleCallback' in window) {
  this.requestIdleCallbackId = requestIdleCallback(fetchMarketsData.bind(this), {timeout: 3000});
} else {
  fetchMarketsData(); // Fallback in case requestIdleCallback is not supported
}

Specifying a timeout is recommended when using requestIdleCallback, since it makes sure that if the given time is elapsed and the callback is not already been called, it executes the callback immediately after the timeout.

Minimize script evaluation time

We also lazy loaded third party libraries using Loadable components. We also removed unused JavaScript and CSS by profiling the page with the coverage tool in Chrome DevTools. It helped us to identify areas where tree shaking was needed to ship less code during page load, and therefore reduce the initial bundle size of the application.

A screenshot of the coverage tool in Chrome DevTools. Here, the tool displays unused portions of JavaScript and CSS files during page load.

Reduce DOM size

Per Lighthouse, large DOM sizes increase memory usage, causes longer style recalculations, and produces costly layout reflows.

A screenshot of the DOM size audit in Lighthouse. The number of DOM elements reported is 2,706 elements.

We reduced the number of DOM nodes in two ways:

  • First, we rendered our menu items at the user’s request (on click). It decreased the DOM size by around 1,200 nodes.
  • Second, we lazy loaded less important widgets.

Because of all these efforts, we reduced TBT significantly, and our INP was reduced accordingly by almost 50%:

A screenshot of the INP audit in CrUX. The INP for the page is 539 milliseconds, which exceeds the 'poor' threshold.

At this point, we nearly ran out of easy wins to further reduce TBT (and INP by proxy), but we knew we had a lot of room for improvement. This is when we decided to upgrade our custom-built UI boilerplate to the latest version of React along with Next.js to make better use of hooks to avoid unnecessary re-rendering of components.

Due to more frequent updates and comparatively lesser traffic as compared to the other portions of the website, we began to migrate our topic pages to Next.js. We also used PartyTown for offloading additional heavy main thread work to web workers, along with techniques like requestIdleCallBack for deferring non-critical tasks.

How has improving INP helped The Economic Times?

Current TBT and INP on origin

At the time of publishing this post, the TBT for our origin was 120 milliseconds, down from 3,260 milliseconds when we began our optimization efforts. Similarly, the INP for our origin was 257 milliseconds after our optimization efforts, down from over 1,000 milliseconds.

A screenshot of the INP audit in CrUX. The INP for the page is 257 milliseconds, which is within the 'needs improvement' thresholds.

INP CrUX trend

The traffic received on topic pages represents a significantly smaller portion of overall traffic. Hence, it was an ideal place for experimentation. The CrUX results along with the business outcomes were very encouraging, and led us to expand our efforts across the entire website to reap further benefits.

A screenshot of INP distributions as visualized in CrUX over a period of four months, starting in July 2022 and ending in October 2022. Values within the 'poor' and 'needs improvement' thresholds declined somewhat, while the values within the 'good' threshold increased.

Akamai mPulse TBT Analysis

We use Akamai mPulse as our RUM solution, which measures TBT in the field. We observed a consistent decrease in TBT, clearly mapping to the outcomes of our efforts to reduce INP. As can be seen in the screenshot below, TBT values eventually dropped from approximately 5 seconds in to around 200 milliseconds in the field.

A screenshot of a chart in Akamai mPulse, showing a decline in TBT over the course of roughly a month.

Business outcome

Overall, our efforts to bring down TBT by 30 times, along with migrating to Next.js helped us reduce INP nearly by 4 times, which eventually led to a 50% decrease in bounce rate and 43% uplift in pageviews on topic pages.

A screenshot of Google Analytics comparing pageviews versus bounce rate. Because of the optimizations made to INP on The Economic Times website, a 50% decrease in bounce rate and a 43% increase in pageviews was realized.

Conclusion

To summarize, INP extensively helped to determine runtime performance issues on parts of the Economic Times website. It has proven to be one of the most effective metrics to positively impact business outcomes. Due to the very encouraging numbers we've observed as the result of this effort, we are motivated to scale our optimization efforts to other areas of our website and reap additional benefits.