Articles

Interaction to Next Paint (INP) Explained

INP measures how long a page takes to visually respond to a click, tap, or keypress. What it counts, how it's scored, and how to bring it down.

Takina Takina · · 4 min read
Dashboard graphs showing web performance metrics

Interaction to Next Paint (INP) is a Core Web Vital that measures how responsive a page feels once a user starts interacting with it — the time from a click, tap, or keypress to the moment the browser paints the next visual update. Where load-time metrics tell you how fast a page appears, INP tells you how fast it responds.

What INP actually measures

A page can have dozens or hundreds of interactions over its lifetime — every click, every keystroke, every tap. For each one, the browser tracks three phases:

  1. Input delay — the gap between the user’s action and the browser starting to handle it. Usually caused by the main thread being busy with something else (a long task, a script still parsing).
  2. Processing time — how long your event handlers and any resulting work take to run.
  3. Presentation delay — the time between the handler finishing and the browser actually painting the updated frame.

INP takes the worst interaction on the page (technically, it discards a small number of outliers on pages with many interactions) and reports its total duration. It replaced First Input Delay (FID) as an official Core Web Vital, because FID only measured the first phase of the first interaction — a page could score a perfect FID and still feel sluggish on every click after the first.

The scoring thresholds

Google’s guidance splits INP into three bands, measured at the 75th percentile of real users:

INPRating
≤ 200msGood
200ms–500msNeeds improvement
> 500msPoor

Because it’s measured across the full session rather than a single load, INP is sensitive to things that don’t show up in a lab test at all — a component that only gets slow after the page has been open for ten minutes and accumulated event listeners, for instance.

Why interactions get slow

The usual culprits all funnel into one of the three phases above:

  • Long tasks blocking the main thread. Any JavaScript task over 50ms delays every pending interaction behind it. A large synchronous computation, an unoptimized re-render, or a heavy third-party script are common causes.
  • Oversized event handlers. A click handler that synchronously updates state, recalculates layout, and fires analytics all in one pass adds up. Breaking work into smaller chunks — or deferring the non-essential parts — keeps individual tasks short.
  • Layout thrashing. Reading a layout property (like offsetHeight) right after writing one forces the browser to recalculate styles synchronously, which shows up as processing time.
  • Large DOM updates. Re-rendering a big subtree, especially in a framework that diffs inefficiently, delays presentation even after your handler logic is done.

Practical fixes

Break up long tasks. Yielding to the main thread periodically — with setTimeout, requestIdleCallback, or the newer scheduler.yield() — lets the browser process pending input between chunks of work instead of after all of it.

Debounce or throttle expensive handlers. If an interaction triggers work on every keystroke or scroll tick, debouncing or throttling it reduces how often the expensive path runs at all.

Move work off the main thread. A web worker can handle heavy computation without blocking rendering, at the cost of some message-passing overhead.

Reduce JavaScript on the critical path. Less code parsing and executing during the interaction window means fewer opportunities for a long task to land in the middle of it. This overlaps with general critical rendering path optimization.

Use content-visibility and virtualization for large lists. Rendering only what’s visible avoids paying the DOM-update cost for offscreen elements on every interaction.

Prefetch and preconnect for interactions that trigger navigation. Resource hints and the Speculation Rules API can make the next page feel instant even when the current interaction itself is unavoidably synchronous.

INP vs the other Core Web Vitals

INP sits alongside Largest Contentful Paint (loading) and Cumulative Layout Shift (visual stability) as one of the three metrics Google uses to assess real-world page experience — see the full Core Web Vitals guide for how they fit together. Unlike LCP, which is a single measurement per page load, INP is a running statistic collected across a user’s whole visit, which means it can only really be measured with real-user monitoring (RUM), not a one-shot lab test — though tools like Lighthouse can still simulate individual interactions to catch obvious problems before they ship.

The takeaway

INP measures the slowest meaningful interaction on a page, from input to paint, and a score over 500ms means users are noticing the lag. Most fixes come down to keeping the main thread free: break up long tasks, move heavy work off-thread, trim what runs inside event handlers, and avoid triggering large DOM updates on every interaction. Because INP is a real-user metric, the only reliable way to know your score is to measure actual sessions, not just a synthetic test run.

The Lycoris Team The Lycoris Team · · 5 min read

What Is Incremental Static Regeneration (ISR)?

ISR lets a static page be rebuilt in the background after deploy, on a timer or on demand, without a full site rebuild. How it works and its tradeoffs.

#Web Development #Performance #Frontend
Takina Takina · · 3 min read

Reflow vs Repaint: How Browsers Redraw Pages

Reflow recalculates layout; repaint just redraws pixels. Why the difference matters for animation performance and how to avoid triggering reflow.

#Web Development #Performance #Frontend