Interaction to Next Paint: how to find and fix a slow INP

Short answer

INP measures how quickly a page responds when someone clicks, taps or presses a key. Aim for 200 ms or less. Slow INP usually comes from JavaScript keeping the browser busy, so find the slow interaction, see which phase takes longest, then break up that work.

What INP measures

Interaction to Next Paint is the Core Web Vital for responsiveness. It times how long the page takes to show a visual response after an interaction. It looks at the whole visit, not just the first click.

GoodNeeds improvementPoor
200 ms or lessOver 200 ms, up to 500 msOver 500 ms
  • What counts: mouse clicks, taps and key presses.
  • What doesn't: hovering, scrolling and zooming on their own.
  • Which interaction sets the score: usually the slowest one. On pages with many interactions, one of the slowest is ignored for every 50.

Why tests can miss it

A page has no INP until someone interacts with it. A bot or crawler that doesn't click gets no value, and some lab tools don't report it. Total Blocking Time can be a rough stand-in, but it doesn't measure a real interaction.

The score Google uses comes from real Chrome visitors at the 75th percentile, split by mobile and desktop. See it in Search Console's Core Web Vitals report or PageSpeed Insights, where a page has enough visits. Then reproduce it yourself, ideally on a mid-range phone or with CPU throttling, as a fast laptop can hide the problem.

How to find the slow interaction

1Run the snippet 3 minutes

Load the page, open DevTools (F12), go to the Console and paste this. Then use the page: open menus, add to basket, type in search, apply filters.

// Logs each click, tap or key press event and where its time went
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (!entry.interactionId) continue;
    const inputDelay = Math.round(entry.processingStart - entry.startTime);
    const processing = Math.round(entry.processingEnd - entry.processingStart);
    const presentation = Math.max(0, Math.round(entry.startTime + entry.duration - entry.processingEnd));
    console.log(entry.name, entry.duration + ' ms', { inputDelay, processing, presentation }, entry.target);
  }
}).observe({ type: 'event', durationThreshold: 16, buffered: true });

One interaction can log several events with the same duration, such as pointerup and click. Look for the longest duration, then find the event with the high processing time, as that's the one whose code ran slowly.

2Use the Performance panel 5 minutes

Record in the Performance tab while you repeat that interaction. It shows which scripts ran and for how long, so you can see who owns the slow work.

Try interactions during load as well as after it. A click while scripts are still starting up is often the slowest one.

Where the time goes

PhaseWhat it isUsual cause
Input delayWaiting for the browser to start your event codeLong tasks already running, often during load
ProcessingRunning your event handlersToo much work in the handler
Presentation delayGetting from the finished handler to the next frameA large page or heavy rendering

How to fix it

  • Input delay: break up long tasks during load, and find out whether a third-party script is the one holding the browser up.
  • Processing: show the visual change first, then defer everything else, such as saving or analytics. Keep handlers small.
  • Layout work: don't read layout values straight after changing styles in the same task, as that forces a layout.
  • Presentation delay: reduce DOM size, add elements when they're needed, and consider content-visibility for off-screen sections. Be careful rendering large chunks of HTML from JavaScript.

Handing control back to the browser lets it paint before the heavy work starts:

button.addEventListener('click', async () => {
  showLoadingState();                                  // Visible change first
  await new Promise((resolve) => setTimeout(resolve)); // Hand back to the browser
  runSlowWork();                                       // Then the heavy work
});

A loading state isn't a fix for slow work, but it does mean the visitor sees a response straight away. For the other two Core Web Vitals, see Largest Contentful Paint and Cumulative Layout Shift.

How crawlers report this

Crawlers report likely causes, not which click was slow. These labels come from PageSpeed data, so they can change between versions.

Screaming FrogSitebulbWhat it means
PageSpeed: Reduce JavaScript Execution TimeNo direct matchScripts take a long time to run.
PageSpeed: Minimize Main-Thread WorkNo direct matchThe browser is busy, so it responds later.
PageSpeed: Reduce Unused JavaScriptRemove unused JavaScriptThe page loads code it doesn't use.
PageSpeed: Optimize DOM SizeAvoid excessive DOM sizeA large page makes each update slower.

Handing this to a developer?

See the slowest interaction

SEOSnip's Speed tab measures INP as you use the page. Click a button or menu, then reopen the extension. It's your browser's result, not field data, so use it to find the cause. You get:

  • INP with a good, needs improvement or poor rating
  • The slowest interaction and the element involved
  • Its input delay, processing and paint time
  • How many interactions were measured
  • A ticket with those numbers attached