Skip to content
CWV Checker

How to fix slow INP

INP measures how quickly your page responds to taps and clicks. Here's how to find the JavaScript that's blocking it.

What INP measures

Tap something. INP is the time from that tap until the browser paints the next frame showing a response. It covers three phases, and they fail for different reasons:

  • Input delay — the main thread was busy with something else, so your tap sat in a queue. This is the load-time problem: a script parsing, a framework hydrating.
  • Processing time — your event handler running. Long handlers, expensive state updates, synchronous storage access.
  • Presentation delay — the browser recalculating style and layout for a large DOM before it can paint the result.

Find out which phase is slow

Chrome DevTools’ Performance panel, recorded with 4× CPU throttling on, will show you a long task with the interaction sitting inside it. But the fastest way to see the real distribution is to log it from live traffic:

new PerformanceObserver((list) => {
  for (const e of list.getEntries()) {
    if (e.duration > 200) {
      console.log(e.name, Math.round(e.duration), e.target);
    }
  }
}).observe({ type: "event", durationThreshold: 200, buffered: true });

Run that on a page you suspect and use the site normally for a minute. The elements that print are your problem, in your own hands, on your own device — and on a mid-range Android they will print a lot more often.

The fixes that actually move it

Audit your third parties honestly

Open the Lighthouse third-party summary. For each entry, ask who asked for it and what happens if it goes. Live chat widgets that load on every page for the 0.3% of visitors who open them are the classic case: load the button, and only load the widget when the button is clicked. Session recorders and heatmap tools are the next worst offenders.

Break up long tasks

Anything over 50ms blocks input for its whole duration. Yield back to the browser between chunks of work so a queued tap can jump in:

// After each meaningful chunk of work
await scheduler.yield?.() ?? new Promise((r) => setTimeout(r, 0));

Separate the visible response from the real work

The visitor needs feedback in the next frame, not the finished result. Update the UI first, then do the expensive part:

button.addEventListener("click", () => {
  showSpinner();                    // paints on the next frame
  requestAnimationFrame(() => {
    setTimeout(() => doExpensiveWork(), 0);
  });
});

Ship less JavaScript in the first place

Input delay during load is the largest single contributor to bad INP on content sites, and it is almost entirely a question of how much script has to be parsed and executed before the page will listen. Code-split by route, drop polyfills for browsers you no longer support, and check whether you are shipping the same library twice.

Watch the DOM size

Presentation delay grows with the number of nodes the browser has to restyle. A page with 5,000 elements — common with page builders — will be sluggish however tight your JavaScript is. Virtualise long lists rather than rendering all of them.

A caution about the number

Because INP takes the worst interaction rather than the average, a single expensive control can dominate. That cuts both ways: it means one fix can move the number a long way, and it means an improvement to your most common interaction may show up as nothing at all. Check that your load-time scripts are in order at the same time — they set the floor everything else sits on.

Common questions

What counts as a good INP?
200ms or less at the 75th percentile. Up to 500ms needs work; beyond that is poor. It measures the worst interaction on the page for most visits, not the average, so one slow control can sink the whole page.
Why does the lab test not show an INP number?
Because INP needs a real person tapping real things, and a lab run never taps anything. Lighthouse reports Total Blocking Time instead, which measures how long the main thread was blocked during load. It correlates with INP but it is not the same measurement, which is why field data matters more for this vital than for any other.
INP replaced First Input Delay. What changed?
FID only measured the delay before the browser started handling your very first interaction, which meant a page could score perfectly and still feel awful for the entire rest of the session. INP measures every interaction, and it measures all the way to the next frame being painted — so slow event handlers and slow rendering both count.
Will removing jQuery fix it?
Rarely on its own. The usual culprits are third-party tags — chat widgets, session recorders, tag managers loading a dozen other things — and your own handlers doing synchronous work on every keystroke or scroll. Measure before you rewrite anything.

Check a page against this

Free, no signup, no ads. We keep nothing except the shareable result, for 30 days.

Enter any public URL. You’ll get the one change that recovers the most load time, what it’s worth, and the measurements underneath.

Other guides