ESC

Type to search the knowledge base.

Event Timing for INP

Event Timing API fields that power INP: input delay, processing, presentation delay, and attribution.

advanced3 min read
  • browser
  • event-timing
  • inp
  • web-vitals
  • performance

INP (Interaction to Next Paint) is the Core Web Vital for responsiveness. Under the hood, browsers expose interaction timing through the Event Timing API (PerformanceEventTiming). Understanding those fields turns “INP is bad” into a fixable budget: input delay vs handler cost vs paint delay.

Docs: Event Timing API — MDN, web.dev INP, Optimize INP.

Interaction latency anatomy

pointer/key down → [input delay] → handlers run → [processing] → next paint → [presentation]
Part Meaning Typical fix
Input delay Main thread busy before handler starts Break long tasks, defer third parties
Processing Your listeners + framework updates Thinner handlers, defer non-UI work
Presentation delay Style/layout/paint until frame shows Avoid thrash, reduce render work

INP looks at a high percentile of qualifying interactions across the page life, not only first input (FID is retired).

Observing Event Timing

const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (entry.entryType !== 'event') continue;
    // entry.name: 'click', 'keydown', ...
    const duration = entry.duration; // roughly to next paint
    const inputDelay = entry.processingStart - entry.startTime;
    const processing = entry.processingEnd - entry.processingStart;
    console.log({ name: entry.name, duration, inputDelay, processing });
  }
});
po.observe({ type: 'event', buffered: true, durationThreshold: 16 });

Use the web-vitals library in production for INP with attribution helpers.

import { onINP } from 'web-vitals';

onINP((metric) => {
  console.log(metric.value, metric.attribution);
});

durationThreshold

Event Timing can be noisy. durationThreshold (ms) filters short events. Lab tooling and RUM libraries choose sensible defaults so you don’t ship megabytes of telemetry.

What “next paint” means

INP cares that the user saw a response — a button state, open menu, spinner. Work that finishes without a frame update still leaves the UI feeling dead. Yield so the browser can paint:

async function onSubmit() {
  setButtonPending(true); // needs a paint
  await scheduler.yield?.();
  await saveForm(); // heavy
}

See Long tasks and yielding and scheduler.yield.

Lab vs field

Lighthouse TBT is a load proxy, not INP. To debug INP in lab: Performance panel + interact + watch long tasks around the event. Field RUM catches the real slow interactions (autocomplete, filters, checkout).

Interview out-loud

“INP measures click/tap/key latency to next paint using Event Timing. I split input delay, processing, and presentation delay — long tasks cause input delay; fat handlers and heavy renders cause the rest. web-vitals attribution plus Performance panel pins the interaction.”

Attribution in the field

When web-vitals attribution is available, log interactionTarget, eventType, and script URLs for long scripts. Tag metrics with route name. You’ll often discover that INP is fine on marketing pages and terrible on one authenticated dashboard filter — optimize that route first instead of “the whole SPA.”

Further depth

Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.

Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.

Further reading

Related guides