Fix Poor INP (Interaction to Next Paint)
Interaction to Next Paint (INP) measures how quickly a page visually responds when users tap, click, or type. Your audit flagged INP as either "poor" (above 500ms) or "needs improvement" (200 to 500ms), which means users feel a lag between acting and seeing a result. INP is a Core Web Vital, so it feeds Google's page-experience signal and ranking eligibility. The fix is almost always about reducing main-thread JavaScript: breaking up long tasks, deferring non-critical scripts, trimming heavy event handlers, and letting the browser paint the response before running expensive logic.
What this means
INP is a Core Web Vital that measures responsiveness. When a user clicks a button, opens a menu, or types into a field, the browser runs your JavaScript, recalculates layout, and paints the result. INP records the latency of that full cycle, from the interaction until the next frame is painted, and reports one of the slowest interactions across the whole visit.
The thresholds are set by Google and measured at the 75th percentile of real interactions: 200ms or less is "good," 200 to 500ms is "needs improvement," and above 500ms is "poor." The poor_inp code means at least one common interaction crossed 500ms; moderate_inp means it landed in the 200 to 500ms band.
INP replaced First Input Delay (FID) as a Core Web Vital on March 12, 2024, and it is a stricter test. FID only measured the delay before the browser began processing the first interaction. INP measures the full round trip, including event-handler processing and rendering, across every interaction in the visit. A page that passed FID can easily fail INP.
The number an audit reports comes from either lab conditions or field data (the Chrome UX Report). Field data is what Google uses for ranking, so the real target is a 75th-percentile INP under 200ms on actual devices, especially mid-range mobile phones where main-thread budgets are tight.
Why it matters
INP is one of the three Core Web Vitals, alongside LCP and CLS. Google uses Core Web Vitals in its page-experience signals. They act more as a tie-breaker than a dominant factor, but they matter on competitive queries where content quality is otherwise comparable. A page stuck in "poor" INP falls out of the "good URLs" bucket in Search Console, which is the segment Google prefers to surface. Fixing it moves the page back into the eligible pool.
The user-experience cost is more immediate than the ranking cost. A 500ms gap between tapping "Add to cart" and seeing anything happen reads as a frozen page. Users double-tap, rage-click, or leave, which hurts conversion on exactly the interactive elements (checkout, filters, forms) that drive revenue. Slow INP is felt most on the interactions that matter most commercially.
For the AI-answer-engine angle, INP is less directly relevant than crawlability or structured data, because AI crawlers like GPTBot, PerplexityBot, and Google's AI Overviews fetchers mostly read server-rendered HTML and do not simulate clicks. The indirect link is real, though: sites that pile on enough client-side JavaScript to fail INP often render key content late or only after interaction, which means AI crawlers can miss it. Getting your interactivity budget under control usually means shipping less blocking JavaScript, which makes your content more visible to both users and machine readers.
How to fix it
- 1
Find the slow interactions before touching code
Do not guess. Open Chrome DevTools, go to the Performance panel, and record while you click the buttons, menus, and form fields on the page. DevTools flags long tasks and shows which event handler ran and how long it blocked the main thread. The Web Vitals extension shows a live INP value as you interact. Cross-reference with field data in Search Console's Core Web Vitals report or PageSpeed Insights, since lab and real-user numbers diverge. Usually one or two handlers cause most of the damage, so fix those first.
- 2
Break up long tasks so the browser can paint
The biggest INP killer is a long synchronous task that blocks the main thread while the user waits for feedback. Split expensive work into smaller chunks and yield control back to the browser between them so it can render. Chrome exposes
scheduler.yield()for this; a portable fallback isawait new Promise(r => setTimeout(r, 0)). The key move is to paint the immediate response first, such as showing a spinner or the opened menu, then do the heavy lifting. Never make the user wait for the whole computation before anything appears. - 3
Defer and trim JavaScript you don't need at interaction time
Every script the main thread parses and executes competes with your event handlers. Add
deferto script tags, or usetype="module", which defers by default, so parsing does not block. Code-split so heavy libraries load only on the routes that use them, and lazy-load below-the-fold widgets, third-party embeds, chat bubbles, and analytics. Audit third-party tags aggressively. Tag managers, A/B-testing scripts, and heavy analytics are frequent INP offenders because they hook into the main thread and can run on every interaction. - 4
Move heavy work off the main thread or debounce it
If an interaction triggers genuinely heavy computation such as parsing large JSON, filtering thousands of rows, or image processing, move it into a Web Worker so the main thread stays free to paint. For input-driven work like search-as-you-type or live filtering, debounce or throttle the handler so it does not fire on every keystroke. Use
requestAnimationFramefor visual updates andrequestIdleCallbackfor non-urgent background work. No single handler should occupy the main thread long enough to delay the next paint. - 5
Reduce what the browser re-renders per interaction
A fast handler can still cause slow INP if the DOM change it triggers forces a large layout or style recalculation. Avoid layout thrashing, which is reading then writing DOM geometry in a loop, and keep the DOM node count reasonable. Use CSS
content-visibility: autoon large offscreen sections so the browser skips rendering them until needed. Animate withtransformandopacity, which the compositor handles, rather thanwidth,top, orheight, which trigger full layout. Smaller, contained rendering work lets the next paint land faster. - 6
Re-measure with field data, not just lab scores
After deploying, INP will not update instantly in Search Console. The Core Web Vitals report is based on 28 days of rolling Chrome UX Report field data, so it lags. Use the web-vitals JavaScript library to log real INP values from your own users for faster feedback, and confirm in DevTools that the interactions you fixed now paint quickly under a throttled mid-range mobile profile (4x CPU slowdown). Aim for a 75th-percentile field INP under 200ms. The lab score is a proxy; the field number is what Google ranks on.
Example
button.addEventListener('click', async () => {
// 1. Give instant visual feedback so the next paint is fast
button.classList.add('is-loading');
resultsPanel.hidden = false;
// 2. Yield so the browser can paint the feedback above
// scheduler.yield() where supported; setTimeout(0) as a fallback
await (window.scheduler?.yield?.() ??
new Promise((resolve) => setTimeout(resolve, 0)));
// 3. Now do the expensive work
const rows = await filterLargeDataset(query);
render(rows);
button.classList.remove('is-loading');
});
// For genuinely heavy CPU work, offload it entirely:
// const worker = new Worker('/filter-worker.js');
// worker.postMessage(query);
// worker.onmessage = (e) => render(e.data);Paint the immediate response first, then yield to the browser before running heavy work. This is the core pattern for good INP.
Platform-specific steps
Yoast and RankMath do not control INP directly. The culprit is usually your theme and plugins piling scripts onto the main thread. A performance plugin like WP Rocket, Perfmatters, or FlyingPress can defer and delay JavaScript until user interaction; the "delay JS execution" setting is the biggest INP lever. Disable scripts on pages that do not use them (Perfmatters' script manager), remove unused plugins, and audit page builders like Elementor or Divi, which inject heavy interaction handlers. Keep the theme lean and avoid slider or mega-menu plugins that run expensive JS on every click.
INP problems on Shopify usually come from the theme's JavaScript and from apps that inject scripts on every page. Audit installed apps and remove any you do not actively use, since each one can add main-thread work. Use a lightweight Online Store 2.0 theme (Dawn-based themes are well optimized), and load third-party widgets like reviews, chat, and upsell popups lazily rather than on page load. In theme.liquid, add defer to custom script tags and avoid render-blocking inline scripts in the head.
Use next/dynamic to code-split heavy components and lazy-load anything below the fold or behind interaction. Prefer Server Components in the App Router so less JavaScript ships and hydrates on the client. For expensive event handlers, wrap non-urgent state updates in startTransition so React keeps the interaction responsive, and yield to the browser inside long loops. Audit your bundle with @next/bundle-analyzer, and move heavy computation into a Web Worker instead of running it in a click handler.
On closed platforms you cannot rewrite the core JavaScript, so focus on what you control. Remove unused third-party embeds, custom code injections, and marketing scripts like chat widgets, popups, and extra analytics, since these are the main INP offenders you can actually delete. Keep animations and interactive blocks to a minimum, and avoid stacking multiple heavy apps or widgets on one page. Both platforms have improved their built-in performance, so the fastest win is usually trimming the extras you added rather than the platform's own code.
Frequently asked
An INP of 200ms or less is "good." Between 200ms and 500ms is "needs improvement," and above 500ms is "poor." Google measures this at the 75th percentile of real user interactions, so most of your real visitors, especially on mobile, need to stay under 200ms. A fast desktop test alone is not enough.
FID (First Input Delay) only measured the delay before the browser began processing the very first interaction, and it ignored everything after. INP measures the full latency of interactions throughout the visit, including input delay, event-handler processing, and time to paint the result, and reports one of the slowest. INP is much stricter, which is why pages that passed FID often fail INP. INP replaced FID as a Core Web Vital on March 12, 2024.
The overall PageSpeed and Lighthouse score is weighted heavily toward loading metrics like LCP, and lab tests only run a scripted interaction, so they can miss the real handlers users trigger. INP is an interaction metric measured in the field. A page can load fast but still lag badly when someone opens a menu or filters a list, because a heavy JavaScript handler blocks the main thread at that moment.
Indirectly, yes. Heavy client-side frameworks that ship large bundles and hydrate a lot of interactivity on the main thread make it easier to fail INP if you are not careful. The metric does not care which framework you use; it cares how much main-thread work runs per interaction. Code-splitting, deferring hydration, server-side rendering, and yielding to the browser matter more than the framework name.
Search Console's Core Web Vitals report uses 28 days of rolling Chrome UX Report field data, so improvements appear gradually over several weeks rather than immediately. To verify a fix faster, measure INP directly in Chrome DevTools on a throttled mobile profile, or use the web-vitals JavaScript library to collect real INP values from your own users right after deploying.
Does your site have this issue?
Run a free, AI-powered audit and we’ll flag this and 150+ other checks in about a minute. No signup.