Event Timing for INP
Event Timing API fields that power INP: input delay, processing, presentation delay, and attribution.
- 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.”
Related
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
- Layout Instability API CLSLayoutShift entries, value calculation, hadRecentInput, and how to attribute CLS in the field.
- Long Tasks APIDetect main-thread tasks over 50ms with PerformanceObserver longtask entries and fix INP-killing work.
- BFCache Back Forward CacheHow the back/forward cache freezes pages for instant history nav, what blocks it, and how to restore state safely.
- Browser DevTools Network PanelRead waterfalls, timing phases, headers, throttling, and initiator chains in the Network panel like a production debugger.
- Browser DevTools Performance PanelRecord main-thread timelines: long tasks, style/layout/paint, frames, and how to turn flame charts into INP fixes.