INP (Interaction to Next Paint): The Complete 2026 Deep-Dive Guide
Technical SEO

INP (Interaction to Next Paint): The Complete 2026 Deep-Dive Guide

 Rahul Sharma  Oct 07, 2026  11  ~2,107 words

Interaction to Next Paint (INP) replaced First Input Delay as a Core Web Vital in March 2024, and it is now the metric most websites fail. The short version: INP measures how long your page takes to visually respond every time a visitor clicks, taps, or types — and Google wants that under 200 milliseconds. This guide goes deep on what INP actually measures, how to diagnose your specific problem, and the fixes that work.

What INP measures (and why it replaced FID)

First Input Delay only measured one thing: the delay before the browser started processing the very first interaction on a page. It ignored everything after that first click, and it ignored how long the page took to actually show a response. A page could have a great FID and still feel broken — menus that freeze for half a second when opened, filters that lock the page while they recalculate.

INP fixes both blind spots. It observes all interactions across the entire page visit — clicks, taps, and key presses — and measures the full latency from input until the browser paints the next frame showing a response. Google then reports essentially the worst interaction on the page (with extreme outliers excluded), because one frozen click is what visitors remember.

The thresholds, measured at the 75th percentile of real visits:

  • Good: 200ms or less
  • Needs improvement: 200–500ms
  • Poor: over 500ms

Two hundred milliseconds is roughly the point where humans perceive a response as instant. Above 500ms, the page feels broken. That perceptual gap is why this metric exists.

The three phases of an interaction

Every interaction's latency breaks down into three phases. Knowing which phase dominates your score tells you which fix to apply — and this is where most shallow INP advice goes wrong, because it prescribes the same fix for all three.

Phase 1: Input delay

The time between the user's input and when your event handler starts running. This happens when the browser's main thread is already busy — typically chewing through a long JavaScript task. The click sits in a queue, waiting.

Symptom: the page feels dead for a beat after clicking, then suddenly responds. Fix: break up long tasks so the main thread is free to pick up input promptly.

Phase 2: Processing time

The time your event handler itself takes to run. Click handlers that trigger expensive re-renders, synchronous network requests, or heavy DOM updates live here.

Symptom: simple interactions (opening a menu, toggling a tab) feel sluggish even on a fast device. Fix: make handlers do less, defer the expensive parts, and avoid doing layout work inside handlers.

Phase 3: Presentation delay

The time between your handler finishing and the browser actually painting the result. Large DOM updates, forced reflows, and expensive style recalculations stretch this phase.

Symptom: the handler runs fast but the visual update visibly lags. Fix: minimize DOM churn per interaction and avoid layout thrashing.

Chrome DevTools' Performance panel now shows these phases directly in the Interactions track — record a trace while clicking around, and you can see exactly which phase eats your budget on each interaction.

How to measure INP properly

INP is the hardest vital to measure in the lab because lab tools do not click around your page like a real user. You need both field and lab data, used correctly.

Field data: the source of truth

  • PageSpeed Insights field section — shows your real-user INP at the 75th percentile from CrUX data. If this says "poor," that is your grade regardless of any lab result.
  • Search Console Core Web Vitals report — groups failing URLs so you can tell whether INP is a site-wide theme problem or limited to specific interactive pages.
  • Real User Monitoring with the web-vitals library — Google's official web-vitals JavaScript library lets you collect INP from your own visitors and send it to your analytics. This is how you find out which interactions are slow, because CrUX only gives you the aggregate number.

Lab data: for diagnosis, not grading

  • DevTools Performance panel — record while interacting with the page. The Interactions track breaks each click into input delay, processing, and presentation phases, and long tasks show up as red-flagged blocks on the main thread.
  • Lighthouse "Timespan" mode — run a timespan audit while interacting to get lab-side interaction metrics.
  • Total Blocking Time (TBT) — not a Core Web Vital, but a useful lab proxy: pages with high TBT usually have INP problems in the field, because both measure main-thread congestion.

The classic confusing result — "my lab score is fine but field INP is poor" — almost always means real users interact with parts of the page your lab test never touched: the mobile menu, the search overlay, filters, accordions, checkout steps. Test those paths manually in DevTools.

Fix 1: Break up long tasks

A "long task" is any JavaScript task running longer than 50ms on the main thread. While it runs, input waits. This is the single most common INP root cause, and the fix is yielding: voluntarily pausing your work so the browser can handle pending input, then resuming.

The classic pattern splits work across task boundaries:

async function processItems(items) {
  for (const item of items) {
    doExpensiveWork(item);
    // Yield to the main thread so input can be handled
    await new Promise(resolve => setTimeout(resolve, 0));
  }
}

For modern browsers there is a cleaner primitive, scheduler.yield(), designed exactly for this — it yields and continues in a new task with better scheduling behavior than setTimeout. Support is broad in Chromium browsers; keep the setTimeout fallback for older engines:

async function yieldToMain() {
  if ('scheduler' in window && 'yield' in scheduler) {
    await scheduler.yield();
  } else {
    await new Promise(resolve => setTimeout(resolve, 0));
  }
}

Move genuinely non-urgent work — analytics batching, prefetching, below-fold setup — to idle time with requestIdleCallback() (with a setTimeout fallback where unsupported) so it never competes with interaction handling at all.

Fix 2: Make event handlers cheap

Handlers run on the critical path of every interaction. Four patterns cover most handler-side INP problems:

  • Debounce rapid-fire inputs. Search-as-you-type, window resize, and scroll handlers should wait until the user pauses (150–300ms) before doing expensive work — not fire on every keystroke.
  • Delegate instead of attaching. One listener on a parent container beats hundreds of listeners on individual list items — less setup work, less memory, faster teardown.
  • Separate urgent updates from expensive ones. When a user toggles a filter, update the visual state immediately (the checkbox, the button press), then do the heavy re-render of results in a yielded follow-up task. The perceived responsiveness comes from the instant feedback.
  • Stop layout thrashing. Reading layout properties (offsetHeight, getBoundingClientRect()) and then writing styles in a loop forces the browser to recalculate layout repeatedly. Batch all reads first, then all writes.

Also mark scroll and touch listeners as passive: true where you do not call preventDefault() — this lets the browser scroll without waiting for your handler, removing a whole class of input delay.

Fix 3: Audit third-party scripts ruthlessly

On real-world sites, third-party scripts are the most common INP killer: tag managers, chat widgets, heatmap recorders, social embeds, and ad scripts all run on your main thread, on your INP budget. The audit:

  1. List every third-party script on your key templates (DevTools Network panel, filtered by domain).
  2. For each one, ask: does this need to run before the user interacts? Analytics, chat, and heatmaps almost never do.
  3. Defer what you keep. Load chat widgets on first user interaction or after a few seconds of idle time, not on page load.
  4. Use facades for embeds. A video or map embed can start as a lightweight static preview that only loads the full third-party player when clicked — this removes hundreds of kilobytes of JavaScript from the initial main-thread load.
  5. Set a third-party budget and enforce it: for example, no more than a fixed number of third-party requests on key templates, with any addition requiring removal of something else.

One bloated tag manager firing five marketing pixels on every page is a completely typical INP failure. It is also completely fixable without losing the data — it is about when the scripts run, not only whether.

Fix 4: Framework-specific patterns

React

INP problems in React apps usually come from state updates that trigger expensive re-renders synchronously inside event handlers. The tools:

  • Split urgent from non-urgent updates with startTransition — the input's visual feedback stays instant while the heavy list re-render happens as a lower-priority transition.
  • Memoize expensive components (React.memo, useMemo) so a filter click does not re-render the entire page tree.
  • Virtualize long lists. Rendering 5,000 rows on a filter change will blow any INP budget; render only the visible window.
  • Watch hydration. Server-rendered React apps can have a painful window where the page looks ready but the main thread is busy hydrating — clicks during hydration queue up. Reduce hydration cost with selective or lazy hydration of below-fold components.

General SPA guidance

Route transitions are interactions too. Prefetch route data during idle time, show instant navigation feedback (skeleton or progress state) before the heavy render, and code-split so each route loads only its own JavaScript.

Fix 5: Reduce rendering work with CSS

Not all INP wins are JavaScript. The browser's rendering work after your handler runs counts toward presentation delay:

  • CSS containment (content-visibility: auto on below-fold sections) lets the browser skip rendering work for off-screen content entirely — less layout, less paint, faster next paint after interactions.
  • Animate transform and opacity only. These are compositor-friendly; animating layout properties forces main-thread recalculation on every frame.
  • Keep DOM size reasonable. Pages with tens of thousands of DOM nodes make every style recalculation and layout pass slower. If your page has 10,000+ nodes, simplify the markup.

Retesting and setting targets

After fixes, verify in this order:

  1. Re-record DevTools Performance traces on the previously slow interactions — confirm the long tasks are gone and each phase is within budget.
  2. Re-run Lighthouse to confirm Total Blocking Time dropped (lab proxy).
  3. Deploy, then watch field data. Remember the CrUX 28-day rolling window: full confirmation takes weeks, but your own RUM data via the web-vitals library will show improvement within days.

Aim for comfortably under 200ms at p75, not exactly 200ms — field data fluctuates with device mix and network conditions, and you want margin.

FAQ

What counts as a "long task"?

Any continuous block of JavaScript execution on the main thread lasting more than 50ms. The browser cannot respond to input while a task runs, so a 300ms task guarantees at least ~250ms of input delay for any click that lands during it.

Is scheduler.yield() safe to use in production?

It is supported in Chromium-based browsers (Chrome, Edge, and others), which represent the large majority of traffic. Use it with a setTimeout(..., 0) fallback, as shown above, and it degrades gracefully everywhere else.

Why is my INP fine in lab tests but poor in the field?

Lab tools load the page but do not interact with it the way visitors do. Field INP captures every real interaction — mobile menus, search overlays, filters, form inputs — on real devices with slower CPUs. Record DevTools traces while performing those exact interactions to reproduce field problems in the lab.

Does INP affect Google rankings?

INP is one of the three Core Web Vitals, which feed Google's page experience signals. Google describes these as tiebreakers between pages of similar relevance — worth fixing, especially since poor INP usually means genuinely frustrated visitors, but not a substitute for good content.

How is INP different from Total Blocking Time?

Total Blocking Time is a lab-only metric measuring main-thread congestion during page load. INP is a field metric measuring actual interaction latency across the whole visit. High TBT strongly predicts INP problems, which makes TBT useful for catching regressions in CI before they reach real users.

Can a mostly static content site fail INP?

Yes — and many do. A WordPress blog with a heavy theme, a chat widget, two ad networks, and social embeds can easily exceed 200ms INP on mobile without a single line of custom JavaScript. The third-party audit in Fix 3 is where content sites usually find their problem.

Checklist

  • Identify your worst interactions from field/RUM data, not guesses
  • Break long tasks with yielding (scheduler.yield() + setTimeout fallback)
  • Debounce, delegate, and slim down event handlers; eliminate layout thrash
  • Defer or facade third-party scripts; set a third-party budget
  • Apply framework patterns (transitions, memoization, virtualization, lean hydration)
  • Use CSS containment and compositor-friendly animations
  • Verify with DevTools traces, then confirm in field data over the following weeks

For the canonical references, read web.dev's INP explainer and web.dev's INP optimization guide. While you are tuning the interactive parts of your pages, it is also worth making sure your server-level caching and compression are solid — the .htaccess generator covers that side — and keeping your document head lean with the meta tags generator.

Related Topics & Keywords

Share this article

Related Articles