To improve INP (Interaction to Next Paint), find the clicks, taps and key presses that feel slow for real users, measure which of the three phases eats the time, and fix that phase. Input delay means the main thread was busy when the user acted. Processing duration means your event handlers do too much work. Presentation delay means the browser needs too long to render the next frame.
Google counts INP as good at 200 milliseconds or less for 75% of page visits. Most fixes come down to the same idea: run less JavaScript at the moment someone interacts, and split what’s left into small chunks the browser can interrupt.
That’s the short answer to how to improve INP. The rest of this guide is the exact order I work in when a client’s INP sits in orange or red, because in my experience guessing at the fix is how people waste a month.
What Is INP and What Score Counts as Good?
INP measures how quickly a page responds to user input across the whole visit, not just the first tap. According to web.dev’s INP documentation, it observes the latency of all click, tap and keyboard interactions and reports one of the slowest. Hovering, scrolling and zooming don’t count.
The thresholds are simple. Good is 200 ms or less, needs improvement is 201 to 500 ms, and poor is anything above 500 ms, measured at the 75th percentile of page loads. On busy pages Google ignores one of the highest interactions for every 50, so one random hiccup won’t define your score.
INP replaced First Input Delay as a Core Web Vital on March 12, 2024. FID is retired, so any guide that still tells you to “improve FID” is out of date. If you want the bigger picture of how INP sits next to LCP, CLS and your Lighthouse score, I’ve covered that in page speed vs Core Web Vitals.
The Three Phases That Decide Your Fix
Every interaction has three parts, and web.dev’s Optimize INP guide names them clearly. Your fix depends entirely on which one is long.
- Input delay. Starts when the user taps and ends when your event callbacks begin running. It grows when something else is hogging the main thread.
- Processing duration. The time your event callbacks take to run to completion. It grows when handlers do heavy work.
- Presentation delay. The time from the end of your callbacks until the browser paints the next frame. It grows with big DOMs and expensive rendering.
Here’s why this matters. If input delay is 300 ms and your click handler takes 20 ms, rewriting the handler does nothing. I’ve seen teams spend days optimizing the wrong phase because they skipped this split.
How to Improve INP: Find the Slow Interactions First
You need two kinds of data. Field data tells you whether real users have a problem. Lab data lets you reproduce it and see the cause.
Start in PageSpeed Insights. The “Discover what your real users are experiencing” section shows INP from the Chrome UX Report (CrUX) for the URL or the whole origin. The Search Console Core Web Vitals report does the same across your site and groups similar URLs, which quickly tells you whether the problem lives in one template.
Field data only says “slow”. It doesn’t say which button. For that, open Chrome DevTools and go to the Performance panel. The live metrics view records INP as you click around, and its Interactions tab lists each interaction with the element and phase timings, so you can see input delay, processing and presentation side by side.
One tip. Your laptop is much faster than your visitors’ phones. The Performance panel suggests CPU throttling and network presets to match your real users, and I always turn throttling on before judging an interaction.
Collect INP Attribution From Real Users
If the slow interaction only happens for real visitors, the web-vitals JavaScript library can report it for you. Its attribution build adds an attribution object that names the element and splits the time into the three phases. This follows the library’s README on GitHub:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {
interactionTarget,
inputDelay,
processingDuration,
presentationDelay,
loadState,
} = attribution;
// Replace console.log with your analytics call.
console.log(name, value, {
interactionTarget,
inputDelay,
processingDuration,
presentationDelay,
loadState,
});
});
Install it with npm install web-vitals. Send those fields to your analytics tool and, after a week, you’ll know which selector is slow and which phase is guilty. The loadState value is handy too, because a slow tap while the page is still loading points straight at input delay.
Branch 1: When Input Delay Is the Biggest Slice
If input delay dominates, the main thread was busy before your code even started. On most sites I audit, that’s script evaluation during load or a third-party tag running long tasks in the background.
Web.dev defines a long task as anything over 50 milliseconds. A tap that lands in the middle of one has to wait until it ends. So the job here is to shrink or remove whatever keeps the thread busy.
My order of attack:
- Cut third-party scripts first. Chat widgets, heatmaps, A/B testing tools, social embeds and old tracking pixels all compete for the same thread. Removing tags nobody uses is the cheapest INP fix I know.
- Defer non-critical code. Load what the first screen needs, and push the rest to after load or to user demand.
- Split big bundles. Ship less JavaScript per page so evaluation finishes sooner.
- Watch timers and intervals. A
setIntervalthat fires every few hundred milliseconds can keep blocking input all visit long.
If the slow interactions happen mostly while the page loads, focus on load-time script. If they happen later in the visit, look for background work like polling, analytics batching or autoplaying carousels.
Branch 2: When Processing Duration Is the Biggest Slice
If processing duration is long, the fault is inside your event handlers. Web.dev’s advice is blunt: do as little work as possible in the callback, then split the rest into separate tasks.
The clean way to split work is to yield to the main thread. scheduler.yield() does this, and its continuation runs before other queued tasks of similar priority. Per MDN’s compatibility data it works in Chrome 129+ and Firefox 142+, but Safari doesn’t support it yet and MDN doesn’t list it as Baseline. So always use a fallback. This helper comes from web.dev’s long tasks guide:
function yieldToMain() {
if (globalThis.scheduler?.yield) {
return scheduler.yield();
}
// Fall back to yielding with setTimeout.
return new Promise(resolve => {
setTimeout(resolve, 0);
});
}
async function handleSaveClick() {
// Work the user needs to see right away:
validateForm();
showSpinner();
await yieldToMain();
// Work that can wait for the next task:
saveToServer();
sendAnalytics();
}
The pattern is what matters. Update the UI first, yield, then do the invisible work like saving or analytics. The user sees a response right away, and the browser gets a chance to paint.
Two more fixes belong in this branch.
Debounce noisy inputs. A search box that filters a whole product catalog on every keystroke will choke. Wait until typing pauses, or only update the visible results, and keep the handler itself tiny.
Avoid layout thrashing. This happens when code writes a style, then reads a layout value like offsetHeight, then writes again in a loop. Each read forces the browser to recalculate layout. Batch all your reads first, then all your writes.
Branch 3: When Presentation Delay Is the Biggest Slice
If the handler is fast but the frame still arrives late, the cost is in rendering. The usual cause I find is a huge DOM, so every style or layout update touches thousands of nodes.
Web.dev lists three fixes. Keep the DOM small. Use content-visibility: auto on long off-screen sections so the browser skips rendering them until they’re needed. And avoid rendering large chunks of HTML with JavaScript during an interaction.
Big mega menus, product grids with hundreds of cards and page-builder sections nested ten levels deep all feed this phase. Honestly, deleting markup beats any clever trick here.
Why Is INP Often Worse on WordPress and Shopify?
The platform isn’t the problem. What gets installed on top of it usually is.
On WordPress, every plugin can add scripts to every page, whether or not the page uses them. Sliders, popup builders, form plugins and analytics add-ons stack up fast. Page builders also add wrapper markup and front-end scripts, which hits input delay and presentation delay at the same time. I compare the two main editors in Elementor vs block editor SEO, and it’s worth reading before you blame your hosting.
On Shopify, apps play the same role. Review widgets, upsell popups and tracking apps inject JavaScript into the storefront, and uninstalling an app doesn’t always remove code it added to your theme. Shopify’s own web performance dashboard, under Analytics and then Reports, shows LCP, INP and CLS from real visitors, and its help documentation notes that app installs and theme updates can change the numbers. I check it after every app change.
My rule on both platforms: test with the plugin or app turned off on a staging copy. If INP drops, you’ve found your culprit without writing a line of code. On Shopify, the next step is clearing out leftover app code, which I cover in Shopify speed optimization.
Edge Cases That Change the Path
- If PageSpeed Insights shows no INP data, then your page lacks enough real interactions. Use DevTools and the web-vitals library until CrUX has data.
- If INP is only bad on mobile, then test with CPU throttling on. Slow phones turn a 40 ms handler into a long task.
- If one element causes most slow interactions, then fix that component first, even if the page has other issues. Often it’s the cookie banner or the mobile menu button.
- If the page is a single-page app, then check route changes. Rendering a whole new view on click is a presentation delay problem.
INP Decision Matrix
| If the slowest phase is | And it happens | Then fix this first |
|---|---|---|
| Input delay | During page load | Defer or remove load-time scripts, especially third-party tags |
| Input delay | Later in the visit | Find background timers, polling and autoplay widgets |
| Processing duration | On one button or form | Update UI first, then yield with scheduler.yield() plus setTimeout fallback |
| Processing duration | On typing | Debounce the handler, update only visible results |
| Presentation delay | On menus or grids | Shrink the DOM, use content-visibility on off-screen sections |
| Any phase | Only on WordPress or Shopify | Test with plugins or apps disabled on staging |
When Should You Call a Developer?
Some INP problems sit deep in custom code. If the long task comes from your own framework bundle, a checkout app or a theme you can’t edit, you need someone who reads performance traces for a living. The same goes for a React or Vue app where every click re-renders half the page.
That kind of work is part of our technical SEO service. If layout jumps are your other problem, my guide on how to fix CLS covers that side, and I’ll cover how to improve LCP in its own guide. Not sure where to start? Ask for a free SEO audit and I’ll tell you which pages fail and why.
Frequently Asked Questions
What Is a Good INP Score?
A good INP score is 200 milliseconds or less at the 75th percentile of page loads. Between 201 and 500 ms needs improvement, and above 500 ms is poor, according to web.dev. Google measures mobile and desktop separately.
Is INP the Same as FID?
No. FID only measured the input delay of the first interaction. INP covers all clicks, taps and key presses during a visit and includes processing and presentation time too. INP replaced FID as a Core Web Vital on March 12, 2024.
Can a Lighthouse Test Measure INP?
A standard Lighthouse page load doesn’t interact with the page, so it can’t report INP. Use field data from PageSpeed Insights or Search Console, and reproduce slow interactions yourself in the DevTools Performance panel.
How Long Does It Take for INP Improvements to Show?
PageSpeed Insights and Search Console use a rolling 28-day window of Chrome user data. You’ll usually see the number move within a week or two after deploying a fix, with the full effect after about four weeks.
Last updated: September 2026 by Mizanur Rahman



