Performance

INP: what it measures and how to improve it

INP measures the time from a tap to the frame that shows the response: good under 200 ms. The three phases, the commands and the fixes that move p75.

Key points

  • INP measures interaction latency, not the delay of the first input.
  • The threshold is 200 ms at the 75th percentile of visits, split between mobile and desktop.
  • An aggregate p75 hides the slow route: read the number per route and per device.

INP measures the time from a tap to the frame that shows the response: under 200 ms is good. It is not the delay of the first input, which is why it replaced FID on 12 March 2024.

The three parts of latency

Interaction latency splits into input delay, processing duration and presentation delay. Input delay comes from a busy main thread when the user taps, processing is your handler, and presentation is the frame the browser still has to paint.

PhaseTypical causeHow to reduce it
Input delayA long task already runningBreak tasks and yield the main thread
ProcessingA handler that computes synchronouslyMove the work to a worker
PresentationA large tree to repaintFewer nodes and fewer recomputed styles

Reading INP in the field

curl -s -H "x-admin-token: $ADMIN_TOKEN" "https://ui.eneawork.it/api/rum/summary?days=30" | jq '.metrics.INP, .devices.mobile.INP'

The endpoint returns a count, p75 and threshold per metric, plus the same reading split by device. It needs ADMIN_TOKEN on the server: without it the answer is 503, with a wrong token 401.

Measuring one interaction

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

The minimum value for durationThreshold is 16 ms, and 40 cuts the noise. Events without an interactionId, such as scroll or mouse movement, are not interactions and stay out of the count.

Three fixes that move p75

  • Yield the main thread after 50 ms of work: await scheduler.yield() where it exists, setTimeout(…, 0) as the fallback.
  • Cut the JavaScript that runs on load: every kilobyte of entry code is work before a tap can be handled.
  • Do not hydrate whole interactive trees: load the behaviour when the component enters the viewport.

The limitation you have to name

INP is a per-visit metric, not a per-page one: a long visit weighs as much as a short one, and the aggregate p75 hides the slow route. Our 66 readings include automated sessions, so they do not replace the Chrome UX Report: read them per route and per device before claiming a pass.

Where to continue

In the catalogue: interactive components, image accordion and dashboard blocks. The guides: one import that grows the bundle and what Core Web Vitals are; the sibling article on LCP and the measured comparison of React libraries 2026.

Frequently asked questions

Did INP replace FID?

Yes. INP has been a Core Web Vital since 12 March 2024 and replaced First Input Delay, which measured only the delay of the first input.

What is the INP threshold?

200 ms at the 75th percentile of visits, split between mobile and desktop. Above 500 ms a page needs work; between 200 and 500 ms the value is in between.

Does Lighthouse measure INP?

No. Lighthouse measures tasks, TBT and JavaScript weight, which cause INP but are not INP. For responsiveness you need field data or a trace in the Performance panel.

Why is INP worse on mobile?

Because the CPU is slower and the main thread is still parsing when the first tap arrives. The same handler costs two or three times more on a mid-range phone.

How do I measure one interaction?

With a PerformanceObserver on the event type, durationThreshold at 40 ms and a filter on interactionId. The entry carries the duration, the type and the node that received the event.