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.
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.
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:
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.
Reduce DOM size
Per Lighthouse, large DOM sizes increase memory usage, causes longer style recalculations, and produces costly layout reflows.
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%:
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.
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.
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.
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.
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.