Why responsiveness keeps mattering after load
Chrome usage data shows that 90% of a user’s time on a page happens after it finishes loading. That makes it essential to measure responsiveness throughout the page lifecycle, not just at the initial load moment. Interaction to Next Paint (INP) is the metric built for that job.
Good responsiveness means a page reacts quickly when a user interacts with it. The fastest way a browser can provide feedback is by painting the next frame, letting the user know their action registered—whether that’s adding an item to a cart, opening a mobile menu, or submitting a form. When that next frame is delayed, users start to feel the page is unresponsive, even if the underlying work eventually completes.
INP is intentionally scoped: it doesn’t measure all the eventual effects of an interaction, such as network fetches or UI updates from async operations. Instead, it captures the time until the next paint is possible. That’s the moment when the user gets visible confirmation the page heard them.
How INP works
INP observes the latency of all click, tap, and keyboard interactions across the entire visit to a page. An interaction is a group of event handlers fired during the same logical user gesture. For example, a tap on a touchscreen includes pointerdown, pointerup, and click events. Interactions can be driven by JavaScript, CSS, built-in browser controls such as form elements, or a mix of these.
An interaction’s latency is the single longest duration of that group of event handlers—spanning from when the user begins the interaction to the moment the browser can next paint a frame. In rare cases where no frame needs painting, the interaction still ends at the point the browser would be able to paint.
The final INP value is calculated when the user leaves the page, producing one number that represents overall responsiveness for the entire lifecycle. For most pages, the interaction with the worst latency becomes the INP score. To reduce outlier noise on pages with heavy interaction counts, the metric ignores one of the highest-latency interactions for every 50 interactions observed. The result is then aggregated at the 75th percentile across all page views, a cut that further dampens the effect of anomalies.
What a good INP score looks like
Several factors complicate assigning simple “good” or “poor” labels to a responsiveness metric. There’s wide variability in the devices people use, and setting development expectations requires balancing an emphasis on fast responses with practical realities. Still, a commonly used threshold to gauge field data is the 75th percentile of page loads, segmented per device type:
- An INP below or equal to 200 milliseconds means good responsiveness.
- An INP between 200 and 500 milliseconds means responsiveness needs improvement.
- An INP above 500 milliseconds means poor responsiveness.
Anatomy of an interaction’s latency
Most interactivity on the web is powered by JavaScript, though browsers also provide native controls for things like checkboxes, radio buttons, and CSS-driven widgets that don’t rely on JavaScript.
INP observes only three interaction types:
- Clicking with a mouse.
- Tapping on a touchscreen.
- Pressing a key on a physical or onscreen keyboard.
These interactions can happen within the main document or inside embedded iframes—say, pressing play on an embedded video. Since users won’t know whether content lives in an iframe, INP includes iframe activity to represent the top-level page experience. Because JavaScript Web APIs can’t access iframe contents, this can surface as a difference between data from the Chrome User Experience Report (CrUX) and your own Real User Monitoring (RUM).
Because each interaction can consist of several events, only the single longest event contributes to its latency. For instance, a keystroke might produce keydown, keypress, and keyup events, and a tap generates both pointerup and pointerdown. The one with the longest duration is the one that counts.
That latency breaks down into three parts. Input delay is the time before any callback for the interaction is handled. The processing duration covers all the event handler callbacks executing in that frame. Finally, the presentation delay is the time after callbacks finish until the frame shows on the user’s screen. A lower total value means a page was reliably responsive when the user interacted with it.
How INP improves on FID
INP replaces First Input Delay (FID) as the primary responsiveness metric. FID only captured the input delay of the very first interaction on a page, treating responsiveness mainly as a load-time property and measuring a user’s first impression. INP measures every interaction throughout the page’s lifespan, covering everything from input delay through event handler execution and the next paint. This makes INP a more trustworthy signal of overall responsiveness, not just how well the page performs at the moment it loads.
When no INP value appears
A page can still report no INP value under certain conditions:
- The user never clicked, tapped, or pressed a key during their visit.
- The user only interacted using gestures that aren’t measured, such as scrolling or hovering.
- The page was accessed by a bot, search crawler, or headless browser that wasn’t scripted to interact.
Measuring INP in the field and lab
Field data from Real User Monitoring (RUM) is the ideal starting point for optimizing INP, since it can reveal not just a page's INP value but also which specific interaction drove it, whether that interaction happened during or after page load, and the interaction type (click, keypress, or tap). If your site is in the Chrome User Experience Report (CrUX), you can quickly get INP field data via PageSpeed Insights, though CrUX generally provides only an origin-level (or sometimes URL-level) picture of whether there's a problem—not the cause behind it. A dedicated RUM solution can attribute INP to individual interactions, helping you avoid guesswork.
Lab testing is most useful after field data points to a page with slow interactions, making the problematic scenario easier to reproduce. Without field data, lab-based INP measurements are dependent on which interactions happen during the test—and since user behavior varies, you may miss the interactions that are slow in the real world. Some lab tools also report no INP at all because they only observe page load without any interaction. In that case, Total Blocking Time (TBT) is a reasonable proxy but not a substitute. When you do test in the lab, follow common user flows and interact with the page during load, when the main thread is typically at its busiest, to surface slow interactions.
Measuring INP with JavaScript
To measure INP yourself, you need to collect Event Timing entries for every interaction and take the 98th percentile across all interactions when the page unloads. The web-vitals JavaScript library's onINP source is a reference implementation. In most cases, the INP value at unload is the final value, but there are several exceptions you need to handle:
evententries with a duration under 104 milliseconds aren't reported by default in performance observers. You can lower this with thedurationThresholdparameter, but the minimum there is 16 milliseconds. Observing thefirst-inputentry—also an Event Timing entry—ensures pages with interactions always report some INP value.- Calculating an exact p98 requires holding all samples in memory, which may be costly. Keeping a small worst-N list (10 is common) approximates high percentiles well.
- If a page is restored from the back/forward cache (bfcache), its INP should reset to zero, since users experience it as a fresh page visit.
- The Event Timing API ignores interactions inside iframes, but the INP metric counts them. Sub-frames can report their
event-timingentries to the parent frame to close this gap, which otherwise shows up as a CrUX-vs-RUM difference.
INP also adds complexity because it covers a page's full lifespan. Users may keep tabs open for a long time, and on mobile browsers, unload callbacks often aren't run for background tabs. The metric should therefore be reported any time the page goes to the background—the visibilitychange event covers both that and unload—with the final INP value calculated on the analytics backend. Rather than implementing all of this yourself, use the web-vitals library, which handles every case above except the iframe one:
import {onINP} from 'web-vitals';
// Measure and log INP in all situations
// where it needs to be reported.
onINP(console.log);
Improving INP and tracking changes
A collection of guides on optimizing INP is available to help you identify slow interactions in field data and use lab data to diagnose and fix the underlying causes. Because bugs are occasionally discovered in the APIs used to measure metrics—and sometimes in the metric definitions themselves—all changes to either the implementation or the definition of INP are tracked in a dedicated changelog. Those changes can show up as improvements or regressions in your internal dashboards. For feedback on the metric itself, the web-vitals-feedback Google group is the place to report it.



