How to Improve Web Vitals INP Score and Identify issues

Transfon Team

6 min read

Learn about Web Vitals' Interaction to Next Paint (INP), the factors contributing to low INP scores, and strategies for enhancing INP scores.

Unpacking Web Vitals' Interaction to Next Paint (INP)

Slated to replace First Input Delay (FID) by March 2024, INP stands as a pivotal Core Web Vital metric, gauging a webpage's responsiveness by measuring delays in user interactions throughout their visit. The INP score provides crucial insights into how swiftly a page can respond to user inputs. Further information is available at [Web Vitals INP Score: Monitoring and Optimizing User Experience with Pubperf](/blog/Web Vitals-inp).

According to Google, an Interaction to Next Paint (INP) score below 200 milliseconds indicates excellent responsiveness. Scores ranging above 200 milliseconds but below 500 milliseconds highlight areas for responsiveness improvement.

Deciphering Low INP Scores: The Role of LongTask

Long Tasks, defined as operations exceeding 50 milliseconds, significantly impact Interaction to Next Paint (INP) scores by monopolizing the main thread. This monopolization hampers the browser's ability to swiftly respond to user inputs. Long Tasks can arise from various sources, including extensive JavaScript execution, large-scale image processing, or comprehensive style recalculations. Mitigating these Long Tasks is vital for boosting INP scores, thereby ensuring smoother, more responsive user interactions and enriching the overall webpage experience.

Long Tasks can originate from:

  1. Website Itself: The core makeup of the website, encompassing HTML, CSS, and JavaScript, can induce Long Tasks. Inefficiencies in code, excessive DOM manipulation, or heavy reliance on animations and transitions can obstruct the main thread, delaying user interaction processing.

  2. First-Party JavaScript (JS) Tags: Scripts crafted or directly implemented by the website's team for functionalities such as analytics, customer support interfaces, or dynamic content fetching, if not optimized, can lead to Long Tasks. These scripts, served from the same domain or under the website owner's control, are essential yet potential sources of performance bottlenecks.

  3. Third-Party Tags: Often websites rely on external services for features like advertising, social media integration, analytics, or video hosting. These services are integrated through third-party JavaScript tags. While they add valuable functionalities, they also introduce a risk of causing Long Tasks if they are not well-optimized, due to factors like network latency in loading the external scripts, bloated code, or synchronous execution blocking the main thread.

How to Simulate LongTask and Interaction Delays

Simulating Long Tasks and interaction delays offers developers insights into potential responsiveness and user experience impacts, aiding in the evaluation and enhancement of performance optimization strategies.

Simulating Long Tasks

Developers can simulate Long Tasks by crafting JavaScript code that deliberately runs for more than 50 milliseconds. This could involve complex calculations or loops designed to consume time intentionally. For example:

function simulateLongTask(duration) {
    const startTime = performance.now();
    while (performance.now() - startTime < duration) {
        // Loop for the specified duration (milliseconds) to simulate a long task
    }
}

// Simulate a long task of 200 milliseconds
simulateLongTask(200);

Simulating random Long Tasks

function simulateCPULoad(duration, load) {
    const startTime = Date.now();
    const loadDuration = duration * load;
    const idleDuration = duration - loadDuration;

    function step() {
        const currentTime = Date.now();
        const elapsedTime = currentTime - startTime;

        while (Date.now() - currentTime < loadDuration) { /* Busy wait */ }

        if (elapsedTime < duration * 1000) {
            setTimeout(step, idleDuration);
        }
    }

    step();
}

// Simulate a CPU load of 50% for 10 seconds
simulateCPULoad(10, 0.5);

Simulating Interaction Delays

To simulate interaction delays, you can use the Long Task simulation in conjunction with user interactions. For example, you can attach a long-running task to a button click event to simulate how a real user interaction gets delayed due to a Long Task. Here’s an example:

<button id="testButton">Click Me</button>
<script>
document.getElementById('testButton').addEventListener('click', () => {
    simulateLongTask(200); // Using the simulateLongTask function defined earlier
    alert('Button Clicked!');
});
</script>

Network Throttling

In the Network tab, you can simulate various network conditions to see how loading times and script execution delays impact user interactions.

Identifying Webpage Long Tasks with longtask API

Employ the following script to detect Long Tasks that may adversely affect INP scores:

const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    console.log("longtask", entry.duration);
  });
});

observer.observe({ type: "longtask", buffered: true });

Pinpointing the Source of LongTask and Low INP Scores: Long Animation Frames (LoAFs)

The long-animation-frame API offers a promising avenue for diagnosing Long Tasks and INP issues, providing detailed insights into operations exceeding specific execution thresholds. This API facilitates a detailed analysis of performance bottlenecks by identifying the precise scripts or operations causing delays.

const observer = new PerformanceObserver(list => {
  const allScripts = list.getEntries().flatMap(entry => entry.scripts);
  const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
  const scriptsBySource= scriptSource.map(sourceURL => ([sourceURL,
      allScripts.filter(script => script.sourceURL === sourceURL)
  ]));
  const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
    sourceURL,
    count: scripts.length,
    totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
  }));
  processedScripts.sort((a, b) => b.totalDuration - a.totalDuration);
  // Example here logs to console, but could also report back to analytics
  console.table(processedScripts);
  console.log('long-animation-frame', processedScripts);
});

observer.observe({type: 'long-animation-frame', buffered: true});

Note: As of the latest update, the long-animation-frame API is not yet supported in Google Chrome, presenting a challenge for developers who rely on Chrome for performance testing. Alternative methods must be sought to identify and address Long Tasks and INP concerns.

Pubperf is set to incorporate long-animation-frame support for attributing INP sources upon its widespread availability in Chrome.

Tips to Enhance INP Scores

  1. Utilize Pubperf for continuous Long Task monitoring.
LongTask Duration TrackingLongTask Duration TrackingLongTask Distribution TrackingLongTask Distribution Tracking
  1. Conduct manual checks for Long Tasks using the LongTask API.

  2. Isolate and test each JavaScript tag on a blank page with the LongTask API to identify and address potential issues, streamlining the process of enhancing INP scores.

  3. Identify LongTasks Using the Chrome Performance Tab

Idenitfy LongTask with Chrome PerformanceIdenitfy LongTask with Chrome Performance
  1. Mitigating LongTasks: Utilizing the Following Code to Yield to the Main Thread
function yieldToMain () {
  return new Promise(resolve => {
    setTimeout(resolve, 0);
  });
}

How to identify slow scripts causing INP issues

Identify slow scripts block the page for more than 50ms:

const loafEntries = performance.getEntriesByName('long-animation-frame')
  .filter(e => e.duration > 50)
for(const loafEntry of loafEntries) {
  for(const s of loafEntry.scripts) {
      if(s.duration > 50) {
          console.log(s.sourceURL, s.duration);
      }
  }
}

Note: The 'long-animation-frame' API is only avaiable in Chrome Dev version or version >= Chrome 123.