Skip to main content
whitep4nth3r logo

11 Mar 2024

7 min read

What is INP and why you should care

Your website performance is now trash until you optimize for INP.

On March 12th 2024, Google is launching a new Core Web Vital metric, Interaction to Next Paint (INP). INP will replace First Input Delay (FID) and will change the way your sites are assessed for performance by Google, which ultimately affects how your sites rank in search engine results.

TL;DR: You need to start optimizing for INP today so your sites are not negatively impacted after March 12th.

Why the change?

The FID Core Web Vital was designed to measure how quickly a webpage responds to a user’s first action on that page. A good FID score is achieved at 100ms or less.

However, “Chrome usage data shows that 90% of a user’s time on a page is spent after it loads,” so FID doesn’t capture the full user experience. As a result, INP has been designed to measure a page’s overall perceived responsiveness by observing clicks, taps and key presses across the entire user journey on the page — rather than just the first interaction.

The final INP value is calculated as the longest time observed between the user performing an action and receiving visual feedback. Examples of user interactions include clicking a button to add a product to a cart, clicking an expandable accordion or tapping a collapsed navigation menu, and typing into an input field. INP focuses on the time it takes for visual feedback to be presented after a particular action is performed (i.e. the next paint — where painting is the process in which browsers add pixels to the screen), and it excludes eventual effects of an interaction (such as network requests or UI updates).

Two buttons. Left button is clicked and UI provides no visual feedback for 2 seconds. Right button is clicked and shows a loading state immediately.

Investigating INP in dev tools

Let’s look at how to investigate actions and events that contribute to the INP metric using Chromium-based browsers such as Chrome, Brave, Edge, and Arc.

Choose a web page that accepts one of the following user interactions that INP measures (scrolling and moving the pointer, for example, is not measured):

  • Clicking with a mouse

  • Tapping on a device with a touchscreen

  • Pressing a key on either a physical or onscreen keyboard

I’ve chosen to investigate what happens when I search for “web vitals” on the Sentry Docs home page. Open up the dev tools panel and click on the “Performance” tab.

Chrome dev tools, showing the performance tab, with an arrow pointing to the performance tab title.

Depending on the website’s target audience, it’s often useful to throttle the CPU or network speed to analyze the user experience on older machines and/or slower internet. If you want to simulate a slower CPU or network, configure the options accordingly.

Chrome dev tools performance tab, showing a rectangle to highlight the CPU throttle and network slow down options.

Click the record button, and perform some interactions on the page.

Short animated GIF showing a click on the record button, and typing web vitals into the search bar on the Sentry docs home page.

Stop recording, and wait for the profile to load. You’ll now see a LOT of data in the form of color-coded blocks with labels in named lanes. The most important lanes to zoom in on when analyzing contributing factors to INP are “Interactions” (any user interactions performed on the page) and “Main” (the browser’s main thread).

A performance profile view, with rectangles annotating the interactions and main lanes.

For context, the main thread is “where a browser processes user events and paints.” By default, the browser uses the main thread to run all JavaScript on a page, layout the page, recompute any changes, and allocate and free up memory (garbage collection). This means that long-running JavaScript functions can block the main thread, leading to unresponsive pages and a bad user experience. This is what Google is encouraging developers to solve by introducing the INP metric.

When inspecting your recorded performance profile, you may see blocks on the main thread highlighted in red; this indicates a long running task. Hovering over a task gives you the time it took to run, and under that task block, you’ll find all of the separate events and function calls that made up that task. Zoom in/out by scrolling on your mouse or trackpad, and use the scrollbars to the right of the window to scroll up and down the stack.

A zoomed in view of the performance profile, with the mouse hovering over a long task that took 90.16ms.

The summary tab below the lanes shows how much time in each task was allocated to different processes. This will vary between tasks, but usually you’ll observe that “Scripting” (i.e. JavaScript processes) and “Loading” takes the longest time.

The summary tab expanded, with a rectangle highlighting the aggregated time metrics for a single task.

Now, let’s cross-reference the main thread activity with the interactions lane. In this example, I typed the term “web vitals” into the search input on the Sentry Docs home page. Under the task blocks on the main thread, you’ll see a number of “Event: keypress” blocks that were captured when I typed each letter. In the interactions lane, there are blocks labeled “Keyboard”, indicating when I typed. Hovering over those blocks tells us that “Long interaction is causing poor performance.”

A zoomed in view of the main thread, showing three key press events with arrows pointing to them. The mouse is hovering over one of the keypresses and a popup has appeared showing that a keyboard interaction was long and is indicating poor performance.

Also notice the whiskers on either side of the blocks. These indicate that interactions are currently blocked by activity on the main thread, meaning the page might appear unresponsive. As I was typing (with CPU throttling), this unresponsiveness was obvious.

Clicking on a keyboard interaction block allows us to inspect this interaction further. The summary shows us that this interaction had an input delay of 45ms, processing time of 83.1ms, and a presentation delay of 84.638ms. The total time of the interaction took 212.74 ms.

The keyboard action summary tab, showing again that the long interaction is indicating poor page responsiveness, and some associated metrics.

Google states that a good INP score is equal to or less than 200ms, a poor score is greater than 500ms, and a score that needs improvement is between 200 and 500ms. Based on these benchmarks, our scores need improvement.

To understand which processes are taking the longest inside each task, select a task block, and click on the “Bottom-Up” tab below. This shows which activities directly took up the most time in total. Click the “Total Time” column header to sort by time ascending or descending.

The bottom up tab view for a single task, with a rectangle highlighting the total time column which you can click to sort events.

Expand each event to see the full list of subsequent events and their respective execution times. Comparing this detailed list to what you thought should be happening can help you identify any anomalies.

Improving INP for your websites and apps

Now that you’re familiar with how to investigate blocking processes by cross-referencing interactions with main thread activity in development, how do you fix issues that cause bad INP scores? As usual, it depends. But here are some questions to ask yourself if you discover unexpected long-running tasks on your web pages that could affect your INP score:

  • Are you providing timely visual feedback? Does the next paint happen within 200ms?

  • Is something running when you didn’t expect it to? Can you remove that process?

  • Do you really need to process each user interaction individually, or can you restrict function calls via debouncing?

  • Could you extract the resulting function calls from the main thread and move them to a web worker?

There are also some more experimental ways to improve the perceived responsiveness of your pages, but proceed with caution because they may not be supported on all browsers.

navigator.scheduling.isInputPending()

With support for Chromium browsers only, isInputPending() allows you to check whether there are pending input events in the event queue, indicating that the user is attempting to interact with the page.

This could be useful in situations where you have a queue of tasks to run (such as calls to an API on each keypress), and you want to give control back to the main thread regularly to allow the page to respond to further user interaction. At the time of writing, there are no published plans to make this API available in any other browser engines.

scheduler.yield

Another experimental feature from the Chrome Team is scheduler.yield, which expands the scheduler API to make yielding control back to the main thread “easier and better” than previously used methods such as manually deferring code execution with setTimeout().

Both new APIs offer some good reading opportunities to understand how JavaScript in the browser actually works, but ultimately, without support for all browsers, it’s not something you should rush to adopt just yet.

A cross-browser JavaScript task scheduler

During my research for this post, I discovered main-thread-scheduling, a JavaScript task scheduler developed by Antonio Stoilkov that focuses on helping you improve perceived page performance, and therefore, your INP scores. It uses isInputPending() if available, but provides scheduling functionality for all browsers. Personally, I haven’t had a use case to test this just yet, but at first glance, it’s currently maintained and could be worth a try.

The bottom line

By introducing the new INP Core Web Vital to replace FID, developers are encouraged to prioritize minimizing delays in visual feedback across the entire user journey. This can reassure users that a page is responding to their actions, which, in theory, should reduce friction and bounce rates, improving the overall web experience.

The bottom line? As developers building for the web, even if we don’t always have complete control of how long it takes to fetch data and make calls to API services on the front-end, in order to achieve a good INP score, we need to make our pages feel fast, all the time.

Originally posted on blog.sentry.io

Want weird stuff in your inbox?

Join undefined subscribers in the Weird Wide Web Hole to find no answers to questions you didn't know you had.

Subscribe

Salma sitting cross legged on a sofa, holding a microphone, looking up into the right of the space.

Salma Alam-Naylor

I'm a live streamer, software engineer, and developer educator. I help developers build cool stuff with blog posts, videos, live coding and open source projects.

Related posts

21 Sep 2023

From LCP to CLS: Improve your Core Web Vitals with Image Loading Best Practices

Learn all about image lazy loading and how it can help improve performance, UX and core web vitals.

Web Dev 9 min read →

29 Mar 2022

How I massively improved my website performance by using the right tool for the job

I rebuilt my website AGAIN with the aim of using as little JavaScript as possible to improve performance. Did I succeed? And what did I learn?

Web Dev 10 min read →