Frontend Performance/Core Web Vitals
Lesson 6 of 20 · Episode 6

Interaction to Next Paint (INP)

Responsiveness as a metric: input delay, processing, presentation — and how a busy main thread wrecks it.

INPResponsivenessMain threadYielding
Watch on YouTube ↗

Interaction to Next Paint measures the thing that makes a site feel alive: when you tap, type, or click, how long until the screen actually updates? It watches every interaction for the whole visit and reports the worst. Good is ≤ 200 ms; cross ~500 ms and the page feels broken.

See it for yourself

Feel a slow interaction

Turn up the background work — simulating JavaScript hogging the main thread — then tap the button. The “Done” state only appears after the interaction completes, so you literally feel the lag. Then flip the optimize switch and watch INP fall back into the green:

InteractiveINP live simulator
60%
Taps: 0

Crank up background work, then tap — feel the delay before “Done” appears.

Input delay · 180ms Processing · 170ms Presentation · 80ms
INP ≈430msNeeds workGood ≤ 200ms
Background work delays when the browser can even start your handler (input delay). Optimizing yields the thread and shrinks the work.

That was a simulation — this one is not. The search box below filters 30,000 products with a deliberately expensive scorer, and every keystroke's input→paint delay is measured on your machine with performance.now(). Mash the keyboard in each mode and watch the chips:

InteractiveSearch 30,000 products — your real input latency

The full 30,000-item filter (with a deliberately expensive fuzzy score) runs inside the input handler. Type fast and feel the keys stick.

Worst keystroke → paint
Matches
0
Results ready in
30,000 products loaded. Start typing.

The latency chips are real: performance.now() at the input event, read again after the next frame paints. Green is under 100 ms — the INP “good” threshold. Mash the keyboard in the first mode, then switch and mash again.

Blocking filters inside the handler; debouncing delays the work; chunking slices it with yields so the thread stays free to paint. Green chips are under the 100 ms INP threshold.
What's an 'interaction'?

An interaction is a group of events

From the user's view, they “clicked a button.” Under the hood, that fires a group of events — and INP measures the whole group plus the paint after it. INP only counts clicks, taps, and keystrokes; hover and scroll don't count:

InteractiveOne interaction → several events
one interaction →pointerdownpointerupclick

INP measures the whole group — every handler that fires for the interaction, plus the paint that follows. Each handler is a chance to do too much work. (Note: hover and scroll don't count toward INP.)

Each event can run its own handler. The slowest path through them all is what INP captures.
The anatomy

The three phases

Every interaction breaks into three phases — and the live demo above maps directly onto them:

  1. Input delay — from your tap until the browser is free to run the handler. Big when the main thread is busy.
  2. Processing time — running all the event handlers for the interaction.
  3. Presentation delay — recalculating layout and painting the next frame.
Key idea
Because JavaScript is single-threaded, a long task already running means your tap just waits. That wait is input delay — the most common reason interactions feel sluggish.
Why it replaced FID

INP vs the old FID

FID (old)INP (now)
What it measuresInput delay of the first interaction onlyFull duration of (nearly) every interaction
CoversJust the first tapThe whole visit
Catches late slowdownsNoYes (e.g. memory leaks)
Includes processing + paintNo, delay onlyYes

FID could call a site “responsive” off one fast first tap, even if it bogged down later. INP watches the whole session, so it reflects how the app actually feels over time.

What to actually do

Optimizing each phase

Input delay — yield the main thread

The thread is often busy with script evaluation (downloading, parsing, compiling, running JS) right when the user first interacts. Ship less JS, defer non-critical work, and break long tasks so the thread is free to respond.

Processing time — do less, and break it up

In the handler, do only the critical work (show the visual feedback the user expects) and push the rest — analytics, syncing, spell-check — into a later task so the paint isn't blocked:

render first, defer the rest
input.addEventListener("input", (e) => {
  updateTextbox(e);            // critical: user must SEE their text now

  setTimeout(() => {           // hand the rest to a later task
    updateWordCount();
    runSpellCheck();
    syncToServer();
  }, 0);
});

Presentation delay — paint less

A huge DOM makes every frame expensive. Keep the DOM lean, render only what's above the fold, and use content-visibility: auto to let the browser skip off-screen work.

Q1Multiple choice
A dashboard feels janky while scrolling and hovering charts, yet its INP looks great. Why might INP miss this?
Q2Multiple choice
Clicking 'Filter' highlights the button instantly, but results take 400ms to appear and the page is frozen during it. Which INP phase dominates, and the fix?
Q3Multiple choice
Your INP is poor, but only the 'Export' button is slow — every other interaction is snappy. A teammate says 'it's one button, ignore it.' Why can't you?
Q4Sort each scenario
Each symptom points to one INP phase. Sort them.
A long task is still running, so your tap's handler can't even start
A third-party script monopolizes the thread the moment you click
The handler runs an expensive 300ms calculation before responding
The handler is quick, but the resulting update repaints a massive DOM
Key takeaways
  • INP measures responsiveness across the whole visit. Good ≤ 200 ms, poor > 500 ms.
  • It counts clicks, taps, keystrokes — not hover or scroll — and measures the whole event group + paint.
  • Three phases: input delay, processing, presentation.
  • It replaced FID, which only saw the first interaction's delay.
  • Fixes: yield the main thread, do less in handlers + break up tasks, keep the DOM lean.
← Previous
5. Cumulative Layout Shift (CLS)
Next →
7. RUM vs. Synthetic Monitoring