Interaction to Next Paint (INP): The 2026 Guide to Passing Core Web Vitals
By Eoin Villarin, 2026-10-19
INP is the Core Web Vital most sites fail on mobile. Learn what changed in 2026, how to find your slowest interactions, and seven code-level fixes that bring INP under 200 ms.
You fixed your images, your Largest Contentful Paint is green and layout shift is under control, yet Search Console still says "INP issue: longer than 200ms". Interaction to Next Paint is the Core Web Vital most sites struggle with, because it is not about how fast a page loads but how quickly it responds every time someone taps, clicks or types.
The numbers show how common the problem is. The 2025 Web Almanac performance chapter found that 97% of desktop origins had good INP, but only 77% of mobile origins did, and just 63% of the top 1,000 mobile sites passed. Busy, feature-rich sites on mid-range phones are exactly where INP fails.
This guide explains what INP measures, what changed in 2026, how to find the interactions that are hurting you, and the specific code-level fixes I use on Shopify, WordPress and React projects to bring INP under 200 milliseconds.
What is Interaction to Next Paint (INP)?
INP measures how long it takes from a user's click, tap or key press until the browser paints the next frame that shows a response. It watches every interaction during a visit and reports roughly the slowest one, ignoring one outlier for every 50 interactions so a single random hiccup does not ruin the score. Hovering, scrolling and zooming are not counted.
It replaced First Input Delay as a Core Web Vital in March 2024. FID only measured the delay before the first interaction started processing, while INP covers the whole interaction, including your event handlers and the render that follows. According to web.dev's INP documentation, the thresholds are assessed at the 75th percentile of page loads, separately for mobile and desktop:
| Metric | Good | Needs improvement | Poor |
|---|---|---|---|
| Interaction to Next Paint (INP) | 200 ms or less | 200 to 500 ms | Over 500 ms |
| Largest Contentful Paint (LCP) | 2.5 s or less | 2.5 to 4 s | Over 4 s |
| Cumulative Layout Shift (CLS) | 0.1 or less | 0.1 to 0.25 | Over 0.25 |
To pass Core Web Vitals, a page needs all three in the "good" band at the 75th percentile. If you are still working on the other two, start with my guide to achieving a strong Core Web Vitals and Lighthouse score.
What changed for INP in 2026?
The thresholds have not changed, but how INP is measured and reported has moved forward in three important ways.
INP now works in every major browser
Safari 26.2, released in December 2025, added the Event Timing API that INP depends on, making INP measurable in Chromium, Firefox and Safari. That matters for real user monitoring, especially if many of your customers use iPhones. Google's Chrome UX Report (CrUX), which feeds Search Console and PageSpeed Insights, still only uses data from eligible Chrome users.
Soft navigations are coming to CrUX
Single-page apps built with React, Next.js or similar frameworks change pages without a full reload, which historically meant INP was measured across an entire session. On October 13, 2026, Google announced experimental CrUX metrics that include soft navigations, measuring responsiveness per page view instead. Google reports that 35% of the top 1,000 sites on Android and 42% on desktop use soft navigations for more than half of their page views. The stable Core Web Vitals used today are unchanged, and Google aims to graduate the new metrics in May 2027.
Better debugging tools
The Chrome DevTools Performance panel shows live INP as you interact and, since Chrome 152, reports Core Web Vitals for soft navigations by default. The web-vitals library, now at version 6, also supports soft navigation reporting in Chromium 151 and later.
How do you find your slowest interactions?
The hardest part of fixing INP is knowing which interaction is slow. A page can have dozens of buttons, filters and menus, and only one of them may be causing the problem.
Step 1: Check field data
Open the Core Web Vitals report in Google Search Console to see which URL groups fail INP on mobile and desktop. Then run key templates, such as the home page, a product page and a category page, through PageSpeed Insights. Both use CrUX data collected over a rolling 28-day window, so they tell you where the problem is, but not which element causes it.
Step 2: Add real user monitoring with attribution
The web-vitals library's attribution build tells you exactly which element was clicked and how long each phase took. Send it to your analytics endpoint:
import { onINP } from 'web-vitals/attribution';
onINP(({ value, rating, attribution }) => {
navigator.sendBeacon('/analytics/inp', JSON.stringify({
value,
rating,
target: attribution.interactionTarget,
type: attribution.interactionType,
inputDelay: attribution.inputDelay,
processing: attribution.processingDuration,
presentation: attribution.presentationDelay,
loadState: attribution.loadState,
script: attribution.longestScript?.entry?.sourceURL
}));
});
After a week, group the results by target. You will usually find that two or three elements, such as a filter panel, a variant picker or a mobile menu toggle, account for most poor scores.
Step 3: Reproduce in the lab
Open Chrome DevTools, go to the Performance panel and enable 4x or 6x CPU throttling to mimic a mid-range phone. Interact with the elements your field data flagged. The live metrics view shows INP for each interaction and flags anything over 200 ms. Then record a trace of that interaction and look for long tasks in the main thread.
What are the three phases of an interaction?
Every interaction breaks down into three phases, and the fix depends on which one is slow.
| Phase | What it measures | Common causes | Main fixes |
|---|---|---|---|
| Input delay | Time before your event handler starts running | Other scripts busy on the main thread, often during page load | Reduce and defer startup JavaScript, delay third-party scripts |
| Processing duration | Time your event handlers take to run | Heavy logic, large re-renders, synchronous analytics calls | Do less, yield early, move non-urgent work later |
| Presentation delay | Time from handler end to the next painted frame | Large DOM, expensive style and layout recalculation | Smaller DOM, content-visibility, avoid layout thrashing |
How to fix INP: 7 techniques that work
These are the techniques I reach for most often, in roughly the order I try them. Google's guide to optimizing INP covers the theory behind each one in more depth.
1. Give instant feedback, then yield
The single most effective pattern is to update the UI first, then hand control back to the browser so it can paint, and only then run the heavy work. scheduler.yield() is built for this. It is supported in Chromium browsers and Firefox but is not yet Baseline, so always include a fallback:
function yieldToMain() {
if (globalThis.scheduler?.yield) {
return scheduler.yield();
}
return new Promise((resolve) => setTimeout(resolve, 0));
}
filterButton.addEventListener('click', async () => {
filterButton.setAttribute('aria-busy', 'true'); // instant feedback
await yieldToMain(); // let the browser paint
applyFilters(); // heavy work after the paint
filterButton.removeAttribute('aria-busy');
});
2. Break up long tasks
Any task longer than 50 ms counts as a long task and can delay the next interaction. If you loop over hundreds of products or rows, yield every few items so incoming clicks can be handled in between:
async function renderRows(rows) {
for (let i = 0; i < rows.length; i++) {
renderRow(rows[i]);
if (i % 25 === 0) await yieldToMain();
}
}
3. Do less inside event handlers
- Move analytics and tracking calls after a yield, or send them with
navigator.sendBeacon. - Debounce search-as-you-type inputs so you are not filtering on every keystroke.
- Cache results of expensive calculations instead of recomputing them on each click.
4. Avoid layout thrashing
Reading a layout value, such as offsetHeight, right after changing styles forces the browser to recalculate layout synchronously. Inside a loop, that can cost hundreds of milliseconds. Batch all reads first, then all writes:
// Slow: read and write interleaved
cards.forEach((card) => {
card.style.height = card.scrollHeight + 'px';
});
// Faster: read everything, then write everything
const heights = cards.map((card) => card.scrollHeight);
cards.forEach((card, i) => {
card.style.height = heights[i] + 'px';
});
5. Shrink the DOM and use content-visibility
Large DOMs make every style and layout recalculation slower, which shows up as presentation delay. Remove hidden duplicate markup such as separate mobile and desktop menus, paginate long lists, and let the browser skip rendering off-screen sections:
.product-grid__item {
content-visibility: auto;
contain-intrinsic-size: auto 420px;
}
6. Tame third-party scripts
Chat widgets, review apps, A/B testing tools, heatmaps and tag managers all compete for the main thread. Audit each one, remove anything unused, and load non-essential widgets only after the first user interaction or when the browser is idle. On ecommerce sites, this is often the biggest single win.
7. Keep framework updates small
In React, a single state change high in the tree can re-render hundreds of components. Keep state close to where it is used, memoise expensive children, and wrap non-urgent updates, such as filtering a large list, in startTransition so React can keep the input responsive. My post on React performance optimisation techniques covers these patterns with examples.
INP fixes for Shopify, WordPress and single-page apps
The same principles apply everywhere, but each platform has its usual suspects.
- Shopify: variant pickers that re-render the whole product form, cart drawers that refetch sections synchronously, collection filters and app scripts injected on every page. Remove leftover code from uninstalled apps and defer review and upsell widgets. My Shopify speed optimization guide goes deeper.
- WordPress: page builders that create very deep DOM trees, mega menus built with jQuery, sliders and popup plugins that run on every page. Lighter block themes and fewer plugins help most. If you are moving to the 7.x branch, my WordPress 7.0 Armstrong guide covers the upgrade.
- Single-page apps: expensive route transitions, large hydration work and global state updates. Measure soft navigations with web-vitals v6 so you see the same picture CrUX will report from 2027.
A quick INP optimisation checklist
- Find failing URL groups in Search Console and confirm with PageSpeed Insights.
- Add web-vitals attribution logging and collect at least a week of data.
- Identify the top three slowest interaction targets.
- Reproduce each one in DevTools with CPU throttling.
- Determine which phase is slow: input delay, processing or presentation.
- Apply the matching fix: yield, defer, reduce DOM or remove scripts.
- Deploy, then watch field data over the next 28 days.
INP is rarely one big problem. It is usually the slowest of many small ones, so fix the worst interaction, measure again and repeat.
Frequently asked questions
What is a good INP score?
A good INP is 200 milliseconds or less, measured at the 75th percentile of real page visits, separately for mobile and desktop. Between 200 and 500 milliseconds needs improvement, and anything over 500 milliseconds is poor. Aim well below 200 on mobile, because mid-range Android phones are where most sites fail and where most of your customers browse.
Does INP affect Google rankings?
INP is one of the Core Web Vitals that Google uses as part of its page experience signals, and Google recommends keeping it under 200 milliseconds. Good scores do not guarantee higher rankings, since relevance and content quality matter far more. But a slow, unresponsive page hurts conversions directly, so it is worth fixing for users even before ranking effects.
Why does Lighthouse look fine while Search Console reports INP problems?
A standard Lighthouse page load test does not interact with the page, so it cannot measure INP. It reports Total Blocking Time as a rough proxy instead. Search Console uses real Chrome user data, including interactions on slower phones. Use field data to find the problem and DevTools, or Lighthouse timespan mode, to reproduce it.
How long until Search Console shows my INP improvements?
Search Console and PageSpeed Insights use CrUX data from a rolling 28-day window, so improvements appear gradually over about four weeks after you deploy. Your own real user monitoring shows the change within days. After deploying, use the validate fix option in Search Console to start tracking the affected URL groups.
Next steps: make your site feel instant
Interaction to Next Paint rewards sites that respect the main thread: less JavaScript, smaller DOMs, fewer third-party scripts and handlers that give feedback first. Measure in the field, reproduce in the lab, fix the slowest phase and repeat.
If your Shopify store, WordPress site or React app is stuck in "needs improvement", I can audit it, find the slow interactions and fix them. Tell me about your site through my contact form, or browse my case studies to see the stores and sites I have built.