Performance

How to Fix Your Interaction to Next Paint: INP Under 200ms Step by Step

Interaction to Next Paint INP cover with the title in gold on black and a runner leaping mid-air, arms spread, against a yellow panel

Interaction to Next Paint, or INP, measures how fast a page responds when someone clicks, taps, or types. It watches every interaction through the whole visit, times each one from the moment of input to the moment the screen visibly reacts, and reports the worst of them. A good INP is 200 milliseconds or less. INP replaced First Input Delay in Google's Core Web Vitals in March 2024, which makes it a ranking signal, and it is the metric businesses fail most often. This post walks the workflow we use to get a page under 200ms, step by step: find the slowest interaction in field data, reproduce it, then fix it phase by phase, with code.

The short version

  • Good is 200ms or less, poor is above 500ms, measured at the 75th percentile of real visits.
  • INP replaced FID in March 2024 and covers every interaction, not just the first.
  • Each interaction splits into input delay, processing, and presentation; diagnose the phase before fixing.
  • The main enemy is long JavaScript tasks holding the main thread while a click waits.
  • One bad handler can fail the whole page, so start from your worst interaction, not your average.

Why INP replaced First Input Delay

FID had two blind spots that eventually killed it. It watched only the first interaction of a visit, and it timed only the wait before the event handler started, not the handler itself or the screen update afterward. A page could pass FID with a clean first click and then freeze on every menu tap for the next five minutes. INP closes both gaps: it measures all interactions across the full page lifetime, and it times the complete journey from input to painted response. It spent two years as an experimental metric before Google promoted it to the Core Web Vitals on March 12, 2024. Anything you read about FID today is history, not advice.

Which interactions count and how the score is picked

Clicks, taps, and key presses count. Scrolling and hovering do not, because the browser handles them off the main thread. When a visit has many interactions, the reported INP is roughly the 98th percentile rather than the absolute worst, so one freak stall out of five hundred keystrokes does not define the page. What reaches Google is the field aggregate: the 75th percentile of those per-visit values across all real Chrome visits in a rolling 28-day window, mobile and desktop assessed separately. In practice that means your score is set by your slowest common interaction on your slowest common device, which on most sites is a mid-range Android phone opening a menu or filtering a list.

The three phases of every interaction

Phase The clock runs while What stretches it
Input delayThe click waits for the main thread to free upLong tasks from your code and third-party scripts
Processing timeYour event handlers runHeavy synchronous work inside the handler
Presentation delayThe browser recalculates layout and paintsLarge DOMs, layout thrashing, complex styles

FID only ever measured the first of these three, and only for the first interaction. The phase breakdown matters because each phase has its own cure: input delay responds to breaking up long tasks, processing time responds to leaner handlers, and presentation delay responds to a smaller DOM and calmer styles. The DevTools Performance panel shows the three phases for any interaction you record, which turns guesswork into reading.

What causes poor INP

  • Long JavaScript tasks. Anything over 50ms holds the main thread hostage, and every click that arrives mid-task waits in line. This is the top cause in nearly every audit.
  • Heavy event handlers. Handlers that compute, rebuild DOM, and fire analytics synchronously pile all of it into the visible latency.
  • Hydration and re-rendering. Single-page apps that re-render large component trees on every state change turn a checkbox into a paragraph of JavaScript work.
  • Large DOM size. More elements mean slower style and layout recalculation after every change. Past roughly 1,500 elements, every update drags.
  • Layout thrashing. Alternating DOM reads and writes forces the browser to recalculate layout over and over inside one handler.
  • Third-party scripts. Tag managers, chat widgets, and ad tech compete for the same main thread your buttons need, and they produce long tasks you never wrote.

The step-by-step path under 200 milliseconds

  1. Pull the field data first

    Search Console's Core Web Vitals report names the URL groups that fail INP, and PageSpeed Insights shows the field number per page. This tells you where to work; never start from a lab run.

  2. Reproduce the slow interaction in DevTools

    Record yourself using the failing page in the Performance panel with CPU throttling on. The interactions track shows each one with its three-phase breakdown, so you know which phase to attack.

  3. Break up long tasks

    Split anything over 50ms into chunks and yield between them with scheduler.yield() or a setTimeout fallback, so pending input gets processed mid-work.

  4. Make handlers show feedback first

    Update the screen immediately, then do the heavy lifting afterward. Users forgive work that takes a moment; they do not forgive a button that ignores them.

  5. Move non-urgent work out of the click path

    Analytics, logging, and prefetching belong in requestIdleCallback, not inside the handler the user is waiting on.

  6. Shrink the DOM and contain your components

    Remove wrapper cruft, virtualize long lists, and use CSS contain and content-visibility so each update recalculates less of the page.

  7. Batch reads, then writes

    Reading offsetHeight between style writes forces a synchronous layout every time. Group all reads first, then all writes.

  8. Audit the third-party scripts

    Sort the Performance panel's long tasks by source. Load surviving tags after first interaction, and drop the ones whose value does not justify their main-thread cost.

The fixes in code

// Blocking: one long task, frozen page
items.forEach((item) => heavyProcessing(item));

// Responsive: yield between chunks
for (const item of items) {
  heavyProcessing(item);
  if (scheduler.yield) await scheduler.yield();
  else await new Promise((r) => setTimeout(r, 0));
}

// Lean handler: feedback now, work deferred
button.addEventListener('click', () => {
  button.classList.add('loading');
  requestAnimationFrame(() => updateDOM(calculate()));
  requestIdleCallback(() => sendAnalytics());
});

// Thrash-free: batch reads, then writes
const heights = els.map((el) => el.offsetHeight);
els.forEach((el, i) => { el.style.height = heights[i] + 10 + 'px'; });

Notes for specific frameworks

INP is where architecture shows. Single-page apps carry a structural handicap, because hydration and state-driven re-renders are exactly the long tasks the metric punishes; in React, memoization and useTransition keep urgent updates ahead of expensive ones. Islands-based builders like Astro, which this site runs on, ship less JavaScript in the first place, and less code on the main thread is the one fix that needs no tuning. On WordPress, the usual INP offenders are page builders and the pile of plugin scripts loading on every page; the fix is fewer scripts far more often than faster ones. Whatever the stack, the third-party tags you added in five minutes each are usually a bigger cost than the framework itself.

What does not fix INP

  • Faster hosting. INP happens on the visitor's device after the page arrives. Server speed moves loading metrics, not responsiveness.
  • Passive event listeners. They smooth scrolling, which INP does not measure. Your click handlers gain nothing.
  • Web workers, for most sites. Workers help pure computation, but they cannot touch the DOM, and most real INP cost is DOM and render work that has to stay on the main thread.
  • Image and CSS weight cuts. Worth doing for loading speed, but a lighter page with the same long tasks has the same INP.
  • Debouncing everything. Debounce helps typing-heavy widgets fire less often, but it does nothing for one slow click handler, which is what usually fails the page.

A judgment call from the field: of the three Core Web Vitals, INP is the one where a rewrite can be cheaper than a rescue. If a page builder or an old SPA produces 800ms interactions, weeks of handler surgery often buys less than rebuilding the template on a lighter stack. Price both paths before committing to either.

What INP means for rankings

Core Web Vitals are a real but modest ranking input, closer to a tiebreaker than a lever, and INP earns its effort elsewhere: a page that responds instantly gets used, and a page that freezes gets abandoned mid-task, usually right before a form submit. INP is also the costliest of the three metrics to fix, because it lives in code spread across the whole application rather than one loading path. Its siblings are cheaper wins: Largest Contentful Paint usually comes down to one image and one server, and Cumulative Layout Shift to reserved space. If you can only fund one sprint, fix those two first and budget INP properly.

Where Egochi fits

Egochi handles Core Web Vitals as part of our technical SEO services: finding the slow interactions in your field data, fixing the handlers and scripts behind them, and monitoring for regressions. Page experience is one signal among many, so that work runs inside a full SEO engagement rather than as a metric chased for its own sake. Fast pages are a means; rankings and revenue are the point.

Questions people ask about INP

What is a good INP score?

A good INP score is 200 milliseconds or less. Between 200 and 500ms needs improvement, and above 500ms is poor. Google measures the 75th percentile of real visits over a rolling 28-day window, so most of your interactions need to land under 200ms to pass.

How is INP different from FID?

FID measured only the first interaction, and only the delay before its handler started. INP measures every click, tap, and key press through the whole visit, covering input delay, processing, and rendering, then reports the worst latency. INP replaced FID in March 2024 because pages could pass FID and still feel slow.

Why is my INP score worse than my FID score was?

Because INP sees more. A page could pass FID while its handlers ran slowly or its later interactions lagged, since FID never looked at either. Nothing got slower when the metric changed; the measurement got honest.

Can I test INP in Lighthouse?

Not directly. INP needs real interactions, and a lab run has none, so Lighthouse reports Total Blocking Time as a proxy. For real INP, use PageSpeed Insights field data, Search Console, or the DevTools Performance panel while you actually click around the page.

Which interactions count toward INP?

Clicks, taps, and key presses. Scrolling and hovering are excluded. Pages with many interactions report roughly the 98th percentile rather than the single worst, so one freak outlier does not define the score.

What is scheduler.yield()?

A browser API that lets a long JavaScript task hand control back to the main thread mid-run, so pending user input gets processed before the task continues. It is the cleanest way to break up heavy work, with a setTimeout fallback for browsers that lack it.

Written by , Head of Web Design & Development at Egochi. Every post on this blog comes from the person who runs that work for clients, not a content mill.

Want this handled for you?

Egochi is a US digital marketing agency working with local businesses through enterprise brands from offices in New York, Miami, Milwaukee, and Madison. Tell us what you are trying to grow and we will send back a plan with real numbers in it.

Get a Free Proposal Call (888) 644-7795

Grade Your Website in About 30 Seconds

Egochi's free audit scores any page for technical SEO, content, and AI search readiness. The report renders on screen, and an analyst reviews every run.