What is INP and why you should care
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.
Event
Behind the Code
On Tuesday, July 16th, we convened a talented group of experts to discuss what’s next for backend development.
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).
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.
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.
Click the record button, and perform some interactions on the 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).
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.
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.
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.”
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.
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.
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.
Sentry is also adding support for Google’s new Core Web Vital, INP, starting on March 12. Stay tuned here to see how you’ll be able to take action on poor INP in Sentry and see what you can do with Web Vitals in Sentry today. Have questions? You can also find us on GitHub and Discord.