In March 2024, Google replaced First Input Delay with Interaction to Next Paint as a Core Web Vital. The swap looked like a footnote at the time. Two years on, it’s the metric that quietly broke a lot of sites that thought they were fine, because FID and INP measure responsiveness in two very different ways.
FID measured the delay before the browser started handling your first interaction on the page, and only the first one. INP measures the full latency of nearly every interaction during a visit, from the tap or keypress to the next frame the browser paints. A site could score well on FID by being quick to acknowledge the first click and still feel sluggish on every interaction after it. INP closes that gap. If your menu takes 400ms to open or a filter hangs the page for half a second, INP sees it now and FID never did.
What INP actually measures
INP times the worst (or near-worst) interaction across the whole page visit. Every interaction has three phases, and web.dev breaks the latency down into exactly these parts:
Input delay is the time before your event handlers can even start, usually because the main thread is busy running other JavaScript. Processing time is your own event handler code executing. Presentation delay is the wait before the browser paints the resulting frame. INP is the sum of all three, and the thresholds Google publishes are 200ms or less for “good,” up to 500ms for “needs improvement,” and anything above 500ms for “poor.” Those are measured at the 75th percentile of real visits in the field, so a fast lab run on your own machine proves very little.
Why sites that passed FID now fail
FID had a structural blind spot: it only ever timed the input delay of the first interaction, and never the processing or rendering that followed. A page could acknowledge the first click in 50ms, spend 600ms running the handler, and still post a great FID. Three things that FID waved through now show up under INP:
- Heavy event handlers. A click that triggers a large state update, a sort over thousands of rows, or an expensive re-render. FID stopped the clock before any of that ran. INP includes it.
- Later interactions, not just the first. A page that warms up fine but bogs down once it’s hydrated and interactive. The fifth interaction counts as much as the first now.
- Framework re-render cost. Component trees that re-render far more than necessary on each interaction. Common in client-rendered apps where one state change cascades through the tree.
If your site leaned on JavaScript for interactivity and passed Core Web Vitals before, INP is the metric most likely to have flipped you to failing.
The field data, and a catch worth knowing
The aggregate numbers are better than you’d expect. Per the 2025 Web Almanac, which runs on real Chrome field data, 77% of mobile sites now hit a good INP, up from 74% the year before, and the top sites improved from 53% to 63%. INP is rarely the metric that fails an origin outright; only 48% of mobile origins pass all three Core Web Vitals, and the usual choke point is LCP at 62%, not INP. If your site is failing the overall assessment, check LCP first.
There’s a catch in those gains worth understanding before you celebrate a passing score. Over the same period that mobile INP improved, Total Blocking Time rose 58%. TBT is a lab metric for how long the main thread was blocked, and it moving the opposite direction from INP tells you something specific: a lot of sites are getting the measured interactions to paint quickly while the page underneath is doing more work than ever, not less. They’re prioritizing the interactions INP happens to catch rather than reducing the JavaScript that causes the problem.
That distinction matters because lab and field tools disagree on purpose. Lighthouse can’t measure INP at all, since INP needs real interactions over a real session, so it reports TBT as a proxy. A green INP in CrUX with a rising TBT in the lab means you’ve optimized the symptom the metric watches and left the cause in place. The page can still feel heavy on the interactions Google didn’t happen to sample, which is the reason INP is a field metric and a clean lab score doesn’t settle it.
What to fix, in priority order
Almost every INP problem traces back to JavaScript monopolizing the main thread. The optimization work web.dev documents sorts into a few moves, roughly in the order they pay off:
- Break up long tasks. Any task over 50ms blocks interaction. Splitting the work and yielding to the main thread (via
scheduler.yield()where supported, or asetTimeoutof zero as the fallback) lets a pending interaction slot in between chunks instead of waiting behind the whole job. - Cut the JavaScript you ship. Remove unused dependencies, defer non-critical scripts, and swap heavy libraries for lighter ones. Less code parsed and executed means less input delay on every interaction, not just the sampled ones. This is the fix that moves TBT and INP together.
- Tame framework re-renders. Memoize expensive components, narrow what each state change touches, and virtualize long lists so a single interaction doesn’t re-render thousands of nodes. This is the most common processing-time culprit in client-rendered apps.
- Move heavy work off the main thread. Genuinely expensive computation belongs in a web worker, where it can run without blocking the interaction or the paint that follows it.
Higher up the list is closer to the root cause. Yielding to the main thread (item 1) makes a heavy page feel responsive, which is the right first move under deadline. Shipping less JavaScript (item 2) is the one that actually makes the page lighter, and it’s the harder, more durable fix.
The most durable answer is architectural: ship less JavaScript to begin with. A page that doesn’t hydrate a large framework on the client has very little to block the main thread, so input delay stays near zero by default. We build this site on Astro because it ships zero JavaScript unless a component explicitly needs it, which makes INP a non-issue for content pages rather than a number to chase after launch. The tradeoff is real, and it’s the same one we laid out for highly interactive pages: a dashboard genuinely needs client-side interactivity, and there the work shifts to keeping that JavaScript lean and yielding well.
When to bring in help
Most INP work is diagnosable with field data and a profiler. Do it yourself if you can read a Chrome performance trace, you have RUM or CrUX data showing which interactions are slow, and the fixes are contained: a few heavy handlers, some scripts to defer, a list to virtualize.
Bring in help when the field data and the lab data disagree and you can’t tell why, when the slow interactions are spread across a large client-rendered app with no obvious single cause, or when the honest fix is architectural and you’re weighing whether to optimize the current build or rebuild the interactive parts on a lighter foundation. That diagnosis is the work Monitor exists to do: pull the field data, find the interactions that actually fail at the 75th percentile, and fix the cause instead of the score.