Interaction to Next Paint (INP)
Responsiveness—that is, how fast a page responds to user input—is crucial to the user experience. Chrome usage data shows that roughly 90% of a user's time on a page is spent after it loads, thus, careful measurement of responsiveness is important especially as more websites rely increasingly on JavaScript to provide interactivity. This is what INP measures, and it encompasses the entire lifecycle of a page.
When responsiveness is good, pages respond quickly to the interactions made with it. When an app responds to interactions, the changes in the user interface that result are visual feedback. Visual feedback is what tells us if—for example—an item we've asked to add to an online shopping cart is indeed being added, if a login form's contents are being authenticated by the server, whether a mobile menu has opened, and so on.
This article explains how INP works, how to measure it, and offers suggestions for improving it, as good responsiveness is imperative to a good user experience.
What is INP? #
INP is a metric that aims to represent a page's overall interaction latency by selecting one of the single longest interactions that occur when a user visits a page. For pages with less than 50 interactions in total, INP is the interaction with the worst latency. For pages with many interactions, INP is most often the 98th percentile of interaction latency.
An interaction is a set of related input events that fire during the same logical user gesture. For example, "tap" interactions on a touchscreen device include multiple events, such as pointerup
, pointerdown
, and click
, all of which may contribute to the overall interaction's latency.
A single interaction's latency consists of the single longest duration of any event that is part of the interaction, where the duration is measured from the point at which the user interacted with the page until the next frame is presented after all associated event handlers have executed. The duration is the sum of the following timespans:
- The input delay, which is the time between when the user interacts with the page, and when event handlers execute.
- The processing time, which is the total amount of time it takes to execute code in associated event handlers.
- The presentation delay, which is the time between when event handlers have finished executing, and when the browser presents the next frame.
What is a good INP value? #
Pinning labels such as "good" or "poor" on a responsiveness metric is tough. On one hand, you want to encourage development of user experiences that deliver good responsiveness. On the other hand, you must account for the fact that there's considerable variability in the capabilities of devices people use, and set achievable expectations by selecting a target that's not impossible to meet on low-end devices.
With that in mind, it's important that a responsiveness metric will be appropriate for broad use cases. To ensure you're hitting this target, a good threshold to measure at the 75th percentile of page loads recorded in the field, segmented across mobile and desktop devices:
- An INP below or at 200 milliseconds means that your page has good responsiveness.
- An INP above 200 milliseconds and below or at 500 milliseconds means that your page's responsiveness needs improvement.
- An INP above 500 milliseconds means that your page has poor responsiveness.
What's in an interaction? #
When an interaction is made with a page, the driver of that interactivity is often JavaScript—though browsers do provide interactivity through controls not powered by JavaScript, such as checkboxes, radio buttons, the HTML <details>
element, and so on. As far as INP is concerned, an interaction consists of one of the following:
- Clicking on an interactive element with a mouse.
- Tapping on an interactive element on a device with a touchscreen.
- Pressing a key on either a physical or onscreen keyboard.
An interaction may consist of multiple events. For example, a keystroke consists of the keydown
and keyup
events. Tap interactions contain pointerup
and pointerdown
events. All an interaction's events are part of what's known as a logical user interaction.
You'll recall that each interaction consists of three phases: the input delay, the processing time, and the presentation delay. The duration of an interaction's associated event callbacks is the sum of the time involved for all three phases. The event with the longest duration in the logical user interaction is recorded.
Similar to CLS, INP is calculated when the user leaves the page, resulting in a single value that is representative of the page's overall responsiveness throughout the entire page's lifecycle. If high percentile page interactions are responded to quickly, that means that interactions at all lower percentiles are fast as well.
Why not the worst interaction latency? #
For pages with relatively few interactions, the worst interaction is fine to use. Yet, not all web pages are the same. Some require more interactivity than others—for example, a text editor or video game app versus a blog or news website.
For pages with a very high number of interactions, sampling the worst one could be misleading. Occasional hiccups occur even on websites that prioritize responsiveness, and those interactions should be overlooked.
By focusing on a high percentile—yet not the highest in all cases—it can be fairly assessed whether the vast majority of a page's interactions are responded to in a timely fashion. If you're interested in seeing how the number of interactions affect which percentile of interaction latency is chosen, you can expand the section below for more information.INP candidate by number of page interactions.
How is INP different from First Input Delay (FID)? #
Where INP considers all page interactions, First Input Delay (FID) only accounts for the first interaction. It also only measures the input delay, not the processing time of event handlers, or the delay in presenting the next frame.
Given that FID is also a load responsiveness metric, the rationale behind it is that if the first interaction made with a page in the loading phase has little to no perceptible input delay, the page has made a good first impression.
INP is more than about first impressions. It covers the entire spectrum of interactions that can occur from the time the page begins loading to the time the user leaves the page. By sampling all interactions, responsiveness can be assessed comprehensively. This makes INP a more reliable indicator of responsiveness than FID.
What if a user never interacts with the page? #
Sometimes a page is loaded, but not interacted with. This can occur for any number of reasons:
- It's possible that someone has loaded a page, but became distracted, and never used it.
- Someone loaded the page, scrolled through it (which isn't an interaction INP takes into account), but never clicked, tapped, or pressed a key on their keyboard. Perhaps the useful part of the page that the user was seeking required no interaction to reach.
- The page is being accessed by a bot (for example, a search crawler or headless browser) which has not been scripted to interact with the page.
In cases such as these, no INP value will be reported.
How to measure INP #
INP can be measured both in the field and in the lab (with some effort) through a variety of tools.
Field tools #
- PageSpeed Insights.
- Chrome User Experience Report (CrUX).
- Via BigQuery in the CrUX dataset's
experimental.interaction_to_next_paint
table. - CrUX API via
experimental_interaction_to_next_paint
. - CrUX Dashboard.
- Via BigQuery in the CrUX dataset's
web-vitals
JavaScript library.
Lab tools #
- Lighthouse Panel in DevTools, available in "Timespan Mode".
- Lighthouse npm module.
- Lighthouse User Flows.
- Web Vitals extension for Chrome.
Measure INP In JavaScript #
Writing your own PerformanceObserver
to measure INP can be difficult. To measure INP in JavaScript, it's advised that you use the web-vitals
JavaScript library, which exports an onINP
function to do this work for you. At the moment, getting INP data is only possible in version 3 of web-vitals
, currently in beta, which can be installed with the following command:
npm install web-vitals@next --save
You can then get a page's INP by passing a function to the onINP
method:
import {onINP} from 'web-vitals';
onINP(({value}) => {
// Log the value to the console, or send it to your analytics provider.
console.log(value);
});
Like other methods exported by web-vitals
, onINP
accepts a function as an argument, and will pass metric data to the function you give it. From there, you can send that data to an endpoint for collection and further analysis.
See the onINP()
reference documentation for additional usage instructions.
Measuring INP on your own in JavaScript is tricky. To get the best results, it's strongly recommended that you use the web-vitals
JavaScript library. However, if you want to get a sense of what the longest interactions may look like on your page, you can copy and paste the JavaScript snippet below in the console of your browser's developer tools and tweak as needed.JavaScript snippet for logging interaction latency to the console.
let maxDuration = 0;
new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
// Comment this out to show ALL event entry types (useful e.g. on Firefox).
if (!entry.interactionId) continue;
if (entry.duration > maxDuration) {
// New longest Interaction to Next Paint (duration).
maxDuration = entry.duration;
console.log(`[INP] duration: ${entry.duration}, type: ${entry.name}`, entry);
} else {
// Not the longest Interaction, but uncomment the next line if you still want to see it.
// console.log(`[Interaction] duration: ${entry.duration}, type: ${entry.name}`, entry);
}
}
}).observe({
type: 'event',
durationThreshold: 16, // Minimum supported by the spec.
buffered: true
});
How to improve INP #
If your website is reporting INP values that fall outside of the "good" threshold, you'll naturally want to figure out what you can do to improve these values. High INP values are usually indicative of a high reliance on JavaScript, or other non-JavaScript main thread work that may run concurrently with user interactions.
Improving INP during page startup #
INP can be a factor during page load, because users may attempt to interact with a page as it's fetching JavaScript to set up event handlers that provide the interactivity required for a page to work.
To improve responsiveness during page load, look into the following solutions:
- Remove unused code using the coverage tool in Chrome's DevTools.
- Find code-splitting opportunities so you can lazy load JavaScript not needed during page load. The coverage tool can help with this.
- Identify slow third-party JavaScript that you may be loading during startup.
- Use the performance profiler to find long tasks that you can optimize.
- Ensure you aren’t asking too much out of the browser rendering after your JavaScript is done—that is, large component tree re-rendering, large image decodes, too many heavy css effects, and so on.
Improving INP after page startup #
Because INP is calculated from inputs sampled during the entire page lifecycle, it's possible that your site's INP could be influenced by what happens after page startup. If that's the case for your website, here are a few areas to look into for solutions:
- Use the
postTask
API to appropriately prioritize tasks. - Schedule non-essential work when the browser is idle with
requestIdleCallback
. - Use the performance profiler to assess discrete interactions (for example, toggling a mobile navigation menu) and find long tasks to optimize.
- Audit third-party JavaScript in your website to see if it's affecting page responsiveness.
CHANGELOG #
No changes have occurred to this metric since it has shipped. If changes occur, they will be noted in this CHANGELOG. If you have feedback for this metric, you can provide it in the web-vitals-feedback Google group.