Article No. 53
Interaction to Next Paint (INP): Causes and Fixes
Abstract
Interaction to Next Paint measures how long it takes a page to visually respond to a user's interaction, tap, click, or keypress, capturing the full latency from the moment the...
On this page
- The threshold
- How INP is actually calculated
- FID to INP: the full history
- The three sub-phases of an interaction
- Long tasks: the recurring cause behind input delay and processing time
- Breaking up long tasks
- Third-party scripts and INP
- Testing and monitoring INP
- Interaction targets and elements to watch
- A note on the business-impact numbers you’ll see elsewhere
- Checklist
- Related:
Interaction to Next Paint measures how long it takes a page to visually respond to a user’s interaction, tap, click, or keypress, capturing the full latency from the moment the interaction happens to the moment the browser paints the next frame reflecting that response. It’s the metric that answers a very specific question: does this page feel responsive, or does it feel like the interface is ignoring you?
This guide assumes you already know what Core Web Vitals are as a category. If you need that context, or you’re not yet sure INP is your actual problem, start with the Core Web Vitals overview instead. This post covers INP specifically, in full depth.
The threshold
Per web.dev’s INP documentation, INP is scored at the 75th percentile of real-user page loads:
| Rating | INP time |
|---|---|
| Good | ≤200ms |
| Needs improvement | 200–500ms |
| Poor | >500ms |
How INP is actually calculated
Most content on INP stops at “keep it under 200ms” without explaining how that number gets produced, which matters because the calculation method affects how you should think about fixes. Per web.dev’s INP methodology, here’s the actual process:
A page can have dozens or hundreds of interactions over its lifetime. Rather than averaging all of them, or reporting only the worst one regardless of how many interactions occurred, INP uses a rule designed to filter out one-off outliers on highly interactive pages while still capturing genuinely poor responsiveness: for every 50 interactions on a page, the single highest (worst) interaction latency is discarded before the reported value is chosen. On a page with fewer than 50 interactions, this means the worst interaction is generally what gets reported, since there aren’t enough interactions yet to discard one. On a page with many more than 50 interactions, this discarding process effectively approximates a high percentile (around the 98th) of that page’s own interaction latencies, filtering out rare, unrepresentative spikes.
That per-page value is then what feeds into the site-wide 75th-percentile-of-page-views calculation described above. In other words, there are two percentile-like steps happening: one within a single page visit (filtering outlier interactions), and one across all page visits site-wide (the 75th percentile that determines your final rating). Don’t confuse the two when reading about the methodology elsewhere.
FID to INP: the full history
Before INP, the responsiveness metric in the Core Web Vitals set was First Input Delay (FID). The two metrics measure meaningfully different things, and understanding the difference explains why the switch happened.
FID measured only the delay before the browser could begin processing a page’s very first interaction, the input delay portion only, not the time it took to actually finish processing that interaction or paint the result. It also only looked at one interaction: whichever happened first. A page could score perfectly on FID while having terrible responsiveness on every subsequent click or tap.
INP measures the complete latency, input delay plus processing time plus presentation delay, for the interaction with the worst (or near-worst, per the calculation above) latency across the entire page lifetime, not just the first one. This is a categorically more complete measurement. Google announced INP as an experimental metric and the intended eventual replacement for FID in May 2023, gave the ecosystem roughly ten months to prepare, and INP officially became the third Core Web Vital, replacing FID in the official set on March 12, 2024.
The practical effect, illustrated with a hypothetical rather than a specific site’s real numbers: imagine a page where the first interaction, say, tapping a mobile menu icon right after load, responds in 40ms. Under FID, that’s the only interaction that counts, and the page scores “good.” Now imagine that same page has a filterable product list further down, and applying a filter after the page has been open for a minute triggers a re-render that freezes the interface for 600ms because of an inefficient event handler. Under FID’s measurement scope, which only ever looked at that first menu tap, this second interaction is completely invisible to the metric, the page still reports “good.” Under INP, which considers every interaction across the page’s lifetime and reports at or near the worst one, that 600ms filter interaction is exactly what gets captured, and the page correctly reports “poor.” This is the practical gap FID had and INP was built to close.
The three sub-phases of an interaction
Same diagnostic principle as LCP: figure out which phase is slow before picking a fix. An interaction’s total latency breaks into three parts:
- Input delay. The time between the user’s action and the browser actually starting to run the relevant event handlers. This is usually caused by the main thread being busy with something else (a long task) when the interaction happens.
- Processing time. How long the event handlers themselves take to execute.
- Presentation delay. The time between the handlers finishing and the browser painting the visual update to the screen.
Chrome DevTools’ Performance panel will show you all three phases for a recorded interaction, which is the most direct way to find out where the time in a slow interaction actually went.
Long tasks: the recurring cause behind input delay and processing time
A “long task” is any single unit of work on the main thread that runs for more than 50 milliseconds without yielding control back to the browser, a definition web.dev formalizes based on the RAIL performance model. While a long task is running, the browser cannot respond to user input, which is why long tasks are the most common underlying cause of both slow input delay (the interaction has to wait for the task to finish before its handler can even start) and slow processing time (if the interaction’s own handler is itself a long task).
You can spot long tasks in the DevTools Performance panel (they render as blocks with a red flag in the flame chart) or programmatically via the PerformanceObserver API’s longtask entry type.
Breaking up long tasks
The general strategy is yielding: instead of running one large block of JavaScript synchronously, break it into smaller chunks and give the browser a chance to handle pending user input between them.
scheduler.yield(), where supported, is purpose-built for this: it pauses the current task and lets higher-priority work (like a pending interaction) run before continuing.isInputPending()lets a long-running task check whether there’s pending user input and yield early if so, rather than running to completion regardless.setTimeout(fn, 0)orrequestIdleCallback()are older, more broadly supported ways to defer non-critical chunks of work to a later point in the event loop, though they don’t guarantee input gets prioritized as precisely asscheduler.yield()does.- Debouncing and deferring non-critical work triggered by an interaction. Not everything that happens on a click needs to happen before the next paint. Logging, non-essential state updates, and analytics calls can often run after the visual response, not before it.
Third-party scripts and INP
This is legitimately INP’s territory in a way it isn’t LCP’s. Third-party scripts, analytics tags, ad scripts, chat widgets, session-replay tools, tend to register their own event listeners and run their own logic on user interactions, and they frequently do this inefficiently or in a way that blocks the main thread at exactly the moments a real user is trying to interact with the page. A single heavy chat widget or ad script initializing itself in response to a click can single-handedly push an otherwise-responsive page into “poor” INP territory.
The practical fixes: audit which scripts are actually firing on interaction versus on page load, load non-essential third-party scripts asynchronously or defer their initialization until after the page is interactive, and periodically re-audit, since third-party scripts change on the vendor’s schedule, not yours, and a script that was lightweight last quarter isn’t guaranteed to still be lightweight today.
Testing and monitoring INP
INP is harder to test in a lab environment than LCP, because lab tools can simulate a page load reasonably well but can’t simulate a real user’s interaction pattern. A Lighthouse run with no simulated interactions will not produce a meaningful INP score. This makes field data, real user monitoring (RUM) or CrUX, more essential for INP than it is for LCP or CLS. Chrome DevTools can record and analyze a specific interaction you perform manually, which is useful for debugging a known problem, but it won’t tell you what your actual visitors are experiencing across all the different ways they use your page.
Search Console’s Core Web Vitals report and the CrUX API both report INP based on real interactions from real visitors, which is the source of truth for whether a fix actually worked.
If you want to collect your own field data rather than waiting on CrUX (which reports on a rolling 28-day window and requires enough traffic to produce a stable score), Google maintains an open-source web-vitals JavaScript library that exposes an onINP function for capturing INP from real visits to your own site, matching Chrome’s own measurement methodology. Its “attribution” build goes a step further and reports the same three-phase breakdown described above (input delay, processing time, presentation delay) for each captured interaction, which is genuinely useful for diagnosing INP problems on pages that don’t get enough traffic to show up reliably in Search Console or CrUX.
Interaction targets and elements to watch
Not every element on a page is equally likely to cause an INP problem. A few patterns worth auditing specifically:
- Form inputs with on-keystroke validation or formatting. Running expensive validation logic on every keystroke, rather than on blur or submit, turns a normally cheap interaction into a repeated source of long tasks.
- Dropdown and autocomplete components that re-render a large list on every input change. If the list isn’t virtualized or debounced, typing can trigger a full re-render on each character.
- Click handlers on cards or rows in a large list or table. Anything that recalculates layout for a large DOM structure in response to a single click is a common long-task source, particularly in single-page applications that don’t paginate or virtualize long lists.
- Modal and overlay open/close transitions. Layout recalculation triggered by opening a modal, especially one that also fetches data at the same time, can combine input delay and processing time into a single sluggish interaction.
A note on the business-impact numbers you’ll see elsewhere
It’s common to see specific claims like “X% higher bounce rate with poor INP” or “a Yms improvement equals a Z% increase in engagement” attached to INP content, usually credited vaguely to “research” with no link or methodology attached. Faster, more responsive pages plausibly correlate with better engagement, that’s a reasonable directional claim, but the specific percentages circulating online rarely trace back to a real, checkable study, and the actual size of any effect varies enormously by site, audience, and what “poor INP” is being compared against. Treat any unsourced precise percentage in this space with skepticism, and look for the actual underlying study before repeating a number.
One number that is genuinely well-sourced: the perception that delays over roughly 100ms start to feel like noticeable lag traces back to human-factors research on response-time thresholds, most notably Jakob Nielsen’s widely cited work on the three response-time limits, which has held up since it was first described in the 1960s research it draws on. That’s a real, attributable finding, distinct from the unsourced business-impact percentages above.
Checklist
- Confirm INP is actually your problem before optimizing (see the Core Web Vitals overview for how to check).
- Understand the calculation: worst interaction on low-interaction pages, roughly the 98th percentile on high-interaction pages, then 75th percentile across page views site-wide.
- Break a slow interaction into its three phases (input delay, processing time, presentation delay) using DevTools to find the actual bottleneck.
- Look for long tasks (over 50ms) blocking the main thread, especially ones triggered by or coinciding with user interactions.
- Break up long tasks with yielding techniques rather than one large synchronous block.
- Audit third-party scripts specifically for interaction-triggered work, not just page-load weight.
- Rely on field data (Search Console, CrUX, RUM) to confirm real-world impact, since lab tools can’t fully replicate INP.