INP optimization comes down to three things: breaking up long JavaScript tasks, lightening event handlers, and removing excess code from the interaction path. The INP threshold is 200 milliseconds at the 75th percentile of visits. While LCP and CLS get fixed by swapping an image or reserving space for a block, INP requires rewriting the interface’s response logic - which is why teams put it off.
According to Google’s CrUX report for May 2026, INP has the highest individual pass rate among the three Core Web Vitals - 86.6% versus 68.6% for LCP, per DigitalApplied’s benchmark review. That doesn’t mean INP is an easy metric - it just gets less attention. LCP gets fixed with one image swap and a preload tag, while INP requires redesigning how clicks are handled.
In headless migration projects, we consistently see the same pattern: LCP and CLS get fixed in the first week after launch, while INP stays poor for months. The stack isn’t the problem - Astro and Next.js are fast on their own. The problem is third-party code and event handlers nobody profiled.
Below: what INP technically measures, why it replaced FID in March 2024, and how to fix it by addressing specific causes - long tasks, event handlers, third-party scripts, and framework hydration.
The problem isn’t visible on a Lighthouse chart - it shows up in real use. A user taps “Add to Cart,” the interface doesn’t respond for 400-500 milliseconds, and on mobile that reads as a freeze. Google uses INP as part of its page experience signals for ranking, but conversion drops before any SEO report catches it.
INP (Interaction to Next Paint): a Core Web Vitals metric that measures the time from the start of any user interaction with a page - a click, a tap, a keypress - to the moment the browser paints the visible result of that action.
How to Measure INP: Field Data vs. Lab Tests
INP can’t be reliably measured with a single lab run - the metric needs real user interactions on a real device.
Field data (CrUX) is collected from real Chrome traffic over a rolling 28-day window. This is what Google Search Console shows in its “Core Web Vitals” section, and it’s what affects ranking. Lighthouse in DevTools or PageSpeed Insights is a lab test: it shows an estimated INP based on emulated interactions, but it doesn’t replace field data.
For accurate production profiling, use Google’s web-vitals library: it sends real INP values from users’ devices to your analytics. To debug a specific interaction, use the Performance tab in Chrome DevTools: record a session, click the problematic element, and look for red blocks in the Main track.
Threshold values, current as of mid-2026:
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP | < 2.5s | 2.5 - 4s | > 4s |
| CLS | < 0.1 | 0.1 - 0.25 | > 0.25 |
| INP | < 200ms | 200 - 500ms | > 500ms |
The threshold is measured at the 75th percentile of visits, separately for mobile and desktop. One fast visit doesn’t save the average - what matters is consistent responsiveness across the whole session.
LCP and CLS Are Easy to Fix, INP Isn’t: Here’s the Difference
LCP and CLS are solved declaratively: set up preload and width/height on images once, and the metric is locked in. INP doesn’t work that way, which is why site teams fix the first two metrics and leave the third alone.
Quick wins for LCP: preloading the hero image, converting to WebP, font-display: swap for fonts, faster TTFB via a CDN. Quick wins for CLS: width and height attributes on every image, reserved space for banners and widgets. These are one-time infrastructure fixes.
INP doesn’t get fixed that way. It requires working through every interactive element on every page: a filter, a button, a form field, a chat widget. There’s no single “enable in settings” checkbox for it.
If your site runs on WordPress specifically, LCP and CLS for that platform are covered separately - the Core Web Vitals guide for WordPress walks through specific causes for Elementor and common plugins. This article focuses on INP and on what works the same way across WordPress, Astro, Next.js, and any headless stack.
The Three Phases of INP: Where Response Time Gets Lost
INP isn’t a single number - it’s the sum of three phases. To optimize it, you need to know which phase is losing time for a given interaction.
Input delay - the time from the tap or click to the moment the event handler starts running. It grows when the main thread is busy with something else at that moment: a script loading, rendering, or processing a previous event.
Processing time - the execution of the event handler itself: state updates, calculations, synchronous DOM operations.
Presentation delay - the time from when the handler finishes to when the browser paints the new frame. It grows with a complex DOM tree, expensive CSS calculations, or large lists that recalculate the entire layout.
The sum of the three phases is the INP for a given interaction. The page-level metric is the worst (or near-worst) value among all interactions in the session - not the average.
Long Tasks Are the Main Cause of Poor INP
Long task: any piece of JavaScript that runs on the main thread for more than 50 milliseconds without yielding control back to the browser. While such a task is running, the browser can’t process a user’s click - that’s input delay.
The main sources of long tasks: heavy JS bundles that run synchronously on load, loops that aren’t broken into chunks, expensive state recalculations on every change, and back-to-back synchronous DOM reads and writes (layout thrashing - when the browser is forced to recalculate the page layout multiple times within a single frame).
Breaking a long task into chunks returns control to the browser between iterations, so it has time to process the user’s click.
Example: breaking up a long task
// Bad: a long task blocks the main thread entirely
function processItems(items) {
for (const item of items) {
updateDOM(item); // e.g., 10,000 synchronous iterations
}
}
// Better: the task yields via scheduler.yield()
async function processItems(items) {
for (const item of items) {
updateDOM(item);
if (navigator.scheduling?.isInputPending()) {
await scheduler.yield();
}
}
}
scheduler.yield() is Chrome’s current API for this. Browsers without support can fall back to setTimeout(fn, 0) or requestIdleCallback - the effect is weaker, but the principle is the same: don’t hold the main thread for more than 50 milliseconds at a time.
Event Handlers That Create Their Own Delay
The second most common source of poor INP is handlers that do too much work on every event firing, not just on click.
input handlers for search or live form validation often run heavy calculations on every keystroke. scroll and resize handlers without rate limiting fire dozens of times per second, recalculating layout each time.
What actually helps: debouncing input fields (150-250 millisecond delay before reacting to input), throttling scroll and resize, and passive event listeners ({ passive: true }) for touch and wheel so the browser doesn’t wait for the handler to finish before scrolling. DOM changes should be batched via requestAnimationFrame rather than applied one at a time on every event.
A separate common mistake is reading an element’s geometry (offsetWidth, getBoundingClientRect) right after changing its style. This forces a synchronous layout recalculation and adds presentation delay at the exact moment of interaction.
Third-Party Scripts: The Silent Source of Poor INP
Chat widgets, analytics, and ad scripts rarely get suspected first, but they’re the most common source of long tasks outside the site developer’s control.
These scripts attach their own global event handlers and run heavy initialization right at page load - this happens before the user’s first interaction and goes unnoticed by the team building the main site.
You can find the culprit in the Performance tab of Chrome DevTools: long tasks there are labeled by script source, and PageSpeed Insights has a “Reduce the impact of third-party code” section with a specific list of domains and blocking time.
A working approach is deferred loading (a “facade”): instead of the real widget, the page first shows a lightweight placeholder, and the full script loads only after the first scroll, click, or a few seconds of idle time. The user sees the interface right away, and the heavy code doesn’t compete for the main thread at the moment when responsiveness matters most.
Hydration on Astro, Next.js, and Headless Sites
Headless sites have a separate cause of poor INP - hydration: the page looks visually ready, but clicks on it aren’t processed yet.
The server delivers ready-made HTML fast, so LCP looks good. But the browser still needs to download and execute the JS bundle that makes the interface interactive. If the framework hydrates the entire component tree at once, clicks made during that process queue up and get processed late - an INP of 500ms or more usually comes from this, not from one heavy handler.
Astro solves this with its islands architecture: JavaScript is sent to the browser only for genuinely interactive components, while the rest of the markup stays static HTML with no hydration at all. Next.js with React Server Components and selective or streaming hydration achieves a similar effect: interactive parts get priority instead of marking the entire page tree with the use client directive.
If you’re still choosing a stack for a migration from WordPress or Tilda, the choice of headless CMS meaningfully affects your final INP - more on that in the comparison of Sanity, Contentful, and Strapi for a B2B site.
Real Case: INP from 480 to 140 Milliseconds
In a typical e-commerce migration project to a headless stack, INP was the worst of the three metrics despite a fast LCP: 480 milliseconds at the 75th percentile of mobile visits.
Profiling in DevTools revealed three sources. The support chat widget initialized synchronously on load and held the main thread for over 300 milliseconds. The catalog filters recalculated the entire product list on every checkbox click, with no debounce. Product cards hydrated in full, even though only the “Add to Cart” button in each one was interactive.
Over three weeks, the team applied three targeted fixes: switched the chat widget to facade loading after the first scroll, added a 150-millisecond debounce to the catalog filters, and moved product cards to islands-based hydration. Field-data INP dropped to 140 milliseconds within a month - exactly how long the CrUX rolling window needs to fully reflect the changes.
After launch, field-data INP is worth checking monthly, not just once after release: this falls under site support, because a single new script from marketing - another pixel, say, or a survey widget - can roll the metric back in a single deploy.
Who Needs INP Optimization
Sites with frequent interactive actions suffer most from poor INP: e-commerce sites with filters and a cart, SaaS dashboards with forms and tables, landing pages with live field validation. The delay feels sharper on mobile traffic because processors are weaker and the user’s finger is on the screen, physically seeing the pause before the response.
A separate category is companies whose site has already accumulated a pile of marketing and analytics scripts: a chat widget, several pixels, a survey form, a reviews widget. Each one is unnoticeable on its own, but together they push INP above 400 milliseconds even on fast hosting. This is typical for companies with 15+ employees, where marketing, sales, and support all manage the site at once.
Frequently Asked Questions
What counts as a good INP score?
An INP below 200 milliseconds at the 75th percentile of visits, measured separately for mobile and desktop users, counts as good. Google flags the 200-500 millisecond range as “needs improvement” and anything above 500 milliseconds as “poor.” The threshold is measured using CrUX field data over a rolling 28-day window, not a single Lighthouse lab run.
Why did INP replace FID in March 2024?
FID (First Input Delay) measured the delay of only the page’s first user interaction, and only the time before the event handler started - not the processing or rendering itself. A page could show a great FID score while still lagging on every click after the first one. INP measures the delay of every interaction in a session and accounts for all three phases - input delay, processing, and presentation - so it reflects the real user experience more accurately.
How long does INP optimization take on a site with a lot of third-party scripts?
An audit and targeted fixes - facade-loading widgets, debouncing handlers, breaking up long tasks - typically take one to three weeks on a typical project, depending on how much third-party code is involved. After the changes are deployed, CrUX field data updates gradually: expect the full picture in Search Console after 28 days, since the metric is calculated over a rolling window.
Can INP be improved without migrating to a different framework?
Yes - for most sites, the biggest gains don’t come from switching stacks but from addressing specific causes: auditing long tasks, facade-loading third-party widgets, and debouncing/throttling event handlers. The hydration problem is specific to headless sites built on React-like frameworks without selective hydration - it simply doesn’t exist in that form on WordPress or classic server rendering.
Does INP affect a site’s Google search rankings?
Yes, INP is one of the page experience signals - alongside LCP and CLS - that Google factors into ranking. Its effect on rankings is smaller than content relevance, but all else being equal, a site with good Core Web Vitals gets an edge, especially in mobile search results. INP has a more direct effect on conversion: users leave a page when the interface doesn’t respond to their actions quickly.
What to do first:
- Check INP using field data in Search Console or PageSpeed Insights, not just the lab Lighthouse score
- Find long tasks in the Performance tab of Chrome DevTools and trace them to a specific script
- Move heavy third-party widgets to facade loading, and add debounce and throttle to event handlers
- For headless sites on Astro or Next.js, separately review your hydration strategy - it isn’t solved with the same techniques as LCP
If your site runs on Astro, Next.js, or another headless stack and field data shows an INP above 200 milliseconds - describe the situation to the Exceltic.dev team. We’ll go through the long tasks, event handlers, and hydration strategy, and propose a concrete fix plan. This is part of the site development and optimization work Exceltic.dev does.