Why FID focuses on input delay
The First Input Delay (FID) metric measures how long the browser takes to begin processing the first user interaction on a page. It records the difference between when the user taps or presses a key and when the browser can actually start running event handlers. FID only considers the first occurrence of click, keydown, mousedown, or pointerdown (when followed by pointerup).
Notably, FID excludes the time spent executing those handlers or updating the screen afterwards. It captures the period the main thread was occupied before it could handle input, typically due to long JavaScript tasks that must finish before the browser can respond.
Why FID instead of alternatives?
When load-time metrics like Total Blocking Time (TBT) and Time To Interactive (TTI) are based on the same long-task blocking, developers often ask why they aren't preferred over FID. The key distinction is that TBT and TTI are indirect: they measure how much JavaScript runs, not what users experience. A high volume of long tasks doesn't necessarily hurt the user if they aren't interacting during those tasks, so a page can score well on these metrics yet feel slow, or score poorly yet feel fast.
FID was chosen because it directly captures the wait a user faces when deciding to interact with a freshly loaded site. It establishes a lower bound on the time before a response is visible. While lab-based diagnostics like TBT remain valuable, a user-centric metric ensures improvements translate to real conditions. Focusing on the user means working with a smaller slice of the experience, acknowledging that it's not yet the full picture.
A note on field measurement of TTI: capturing TTI for real users is challenging because it occurs late in the page load, after a five-second quiet network window. Users may navigate away or interact before that point, so in Chrome's data, only about half of page loads reached TTI. This limits the metric's usefulness in the field.
The gap: what comes after FID
FID offers a clear, purposeful first step, but its narrow range reflects only the delay before input handling begins. The timespan from the interaction through handler execution to the final painted frame is a more complete representation of what the user feels as latency. Capturing that requires not just the time to first handling, but the end-to-end duration for each event.
There is also a need to look beyond the first interaction. A single measurement at load time can miss responsiveness issues that surface throughout the entire lifetime of a page. The eventual goal is a metric that accounts for the full spectrum of individual event latencies and gives a holistic view of how the page performs across its life, not a brief window.
Towards measuring total event latency
The browser already has data available to close this gap. An input event's processing time spans from when it is received up to when the browser finishes updating the display. This includes not just running event handlers, but also any rendering and painting work that follows. Because many interactions trigger animations or asynchronous work, defining the precise end point is part of the design challenge.
The team's proposal is to keep the event-driven approach, but treat each input's total latency as the meaningful unit. This can be computed from existing browser instrumentation and gives a direct reflection of how long it takes for the user to see the result of each interaction. The structure is similar to FID in that it remains a user experience measurement, but broader by design.
Feedback on the direction is appreciated from developers and site owners, particularly around which interactions matter most and where the metric's boundaries should be drawn. The goal of the refinement is accuracy for a wider range of sites while retaining the core reliability found in FID. Insights gathered will inform the development and release of a more comprehensive responsiveness metric in the coming cycles.
Rethinking How We Measure Page Responsiveness
FID has served the web platform well, but its scope is intentionally narrow. It only considers the delay before the browser begins processing an input event, and only for the first interaction on a page. That leaves significant gaps in our understanding of how responsive a page feels throughout its full lifecycle.
Our goal with a new metric is to extend FID's foundation while keeping a direct line to user experience. The metric we're exploring should:
- Cover the responsiveness of all user inputs on a page, not just the first.
- Measure each event's complete duration, not only the delay before processing starts.
- Group events that are part of the same logical interaction, defining that interaction's latency as the maximum duration of all its constituent events.
- Produce an aggregate score for the page's entire lifetime.
For this metric to be useful, we need high confidence that a poor score means the page is not responding quickly to interactions—nothing less.
Measuring Full Event Duration
The most direct improvement over FID is to account for the full end-to-end latency of an input event. FID stops measuring once the browser starts processing the event handlers; it doesn't include the time those handlers actually run, nor the time needed to paint the result.

Chrome processes an input through these steps:
- The user input occurs. The
timeStampof the event marks this moment. - The browser performs hit testing to assign the event to the correct HTML frame, then sends the event to the renderer process responsible for that frame.
- The renderer queues the event until it's able to process it.
- The renderer runs the event's handlers. These may schedule asynchronous work like
setTimeoutcalls or fetches, but the synchronous portion ends here. - A frame is painted that reflects the handlers' work. Any asynchronous tasks scheduled by those handlers may still be incomplete.
The interval between steps 1 and 3 is an event's delay; this is what FID measures. The interval between steps 1 and 5 is the event's duration, which is what our new metric targets.
An event's duration inherently includes its delay, plus the work done in the handlers and the time to present the next frame. Event Timing API entries already expose this value through the duration attribute.
A note on asynchronous work: we'd like to eventually capture async tasks triggered by event handlers. However, defining what counts as "triggered by the event" is tricky—if handlers kick off animation via setTimeout, capturing all posted tasks would extend the measured duration for as long as the animation runs. While we plan to investigate heuristics for identifying asynchronous work that needs immediate completion, we want to avoid penalizing long-running work that's intended to take time. So our initial implementation will stop at step 5: we'll measure synchronous handler work plus the time to paint, without making guesses about what happens asynchronously afterward.
This approach does miss meaningful cases—events that trigger fetches, or work deferred to the next requestAnimationFrame callback. Still, for many inputs the important work should execute synchronously; events are often dispatched sequentially and their handlers must run in order. Starting with a solid synchronous measurement is a pragmatic first step.
Grouping Events Into Interactions
Moving from delay to duration addresses one weakness of FID, but another remains: it evaluates individual events in isolation. A single user interaction usually produces multiple events, and looking at each one separately doesn't reflect what users actually experience when they tap, type, or drag.
To capture the perceived latency of these multi-event experiences, we're introducing the concept of interactions.
Interaction Types
We've identified four interaction types—keyboard, tap, drag, and scroll—and the DOM events associated with each:
| Interaction | Start / end | Desktop events | Mobile events |
|---|---|---|---|
| Keyboard | Key pressed | keydown |
keydown |
keypress |
keypress |
||
| Key released | keyup |
keyup |
|
| Tap or drag | Tap start or drag start | pointerdown |
pointerdown |
mousedown |
touchstart |
||
| Tap up or drag end | pointerup |
pointerup |
|
mouseup |
touchend |
||
click |
mousedown |
||
mouseup |
|||
click |
|||
| Scroll | N/A | ||
The first three are currently within FID's scope; we're adding scrolling because it's ubiquitous and central to how responsive a page feels. Note that some events fired during these actions aren't part of the measured interaction. For example, when a user scrolls, the scroll event is dispatched only after the screen updates, so we exclude it from the latency calculation.
Each tapped, dragged, or keyed interaction has a distinct down phase and up phase. We have to be careful not to include the time a user holds their finger or mouse button down between those phases as page latency.
Keyboard
A keyboard interaction produces keydown, keyup, and possibly keypress events. The keydown and keypress fire when the key goes down; keyup fires on release. For most sites, the meaningful UI update happens on key press, but we still include keyup because it occasionally triggers its own updates.

To define keyboard interaction latency, we'd take the maximum duration of the keydown and keyup events. These durations are normally disjoint because the frame from keydown is presented before keyup occurs, but they can overlap if both events share the same presented frame. Also, a frame can be presented mid-task, as the final presentation steps happen outside the renderer process.
One edge case: if a user holds a key down long enough for auto-repeat to trigger, the event sequence can vary. In those situtations, we'd treat each keydown as its own interaction, which may or may not have a matching keyup.
Tap
Tap and click interactions involve several events split across the press and release phases. Desktop and mobile dispatch different event sequences for the same physical action. While the release often triggers the primary reaction, measuring just that release misses pages that also update the UI on press. The full interaction can get long if the browser adds tap delay.
Unlike keyboard, where most events are functionally equivalent, some tap-related events can be safely dropped. Since events fired as part of a tap overlap so much, we only need three to cover the full interaction: pointerdown, pointerup, and click.
The pointerdown/pointerup pair alone isn't sufficient, though. In browsers with a tap delay, pointer events fire quickly while synthetic mouse events like mousedown, mouseup, and click are delayed until after the timeout passes. Dropping click would omit exactly that delay from the measurement, understating how long a user waits. Tracking click (and mouse events that follow it) keeps that delay in the calculation.
Drag
Given that dragging causes prominent UI updates, it has a natural place in this metric. To keep the analysis simple and the latency comparable across interaction types, we'll measure only the drag start and drag end—not the continuous motion between them. This is consistent with excluding other continuous event streams like mouseover. We're not considering the Drag and Drop API at all, since it's desktop-only and behaves differently from event-driven dragging.
Scrolling
Scrolling is both the most common interaction with a page and the one with the most peculiar semantics. Most of the scrolling experience is about smoothness across many frames—a concern that belongs to a separate proposal. What we want to measure is the latency of the initial scroll response: the time from when the user's gesture is large enough to trigger a scroll to when the first frame showing that scroll is presented.
This distinction matters because of how browsers treat scroll events. DOM events also matter for scrolling, since non-passive listeners can force scrolling to the main thread and degrade performance—behavior this metric should flag.
We exclude scroll events themselves from this calculation, as they fire after the scroll has already been rendered. Instead, the first DOM event that triggers scrolling (e.g. touchmove) provides the starting timestamp, and the first painted scroll frame is the end point.
Scrolling is usually very fast, but only because it's so heavily optimized—its importance means poor initial-scroll performance must be visible in our tooling. Excluding scroll from a responsiveness metric would leave a blind spot that could silently degrade over time.
Defining Interaction Latency
For interactions that involve press and release events, the wait attribute should include durations from both phases—minus the actual hold time between them. Because these events can overlap, using the maximum duration across an interaction's events is a simple definition that meets this constraint. A keyboard interaction, for example, is measured by the longer of the keydown or keyup durations.

When both release events update the UI, their durations may cover different frames, which the max correctly captures.

This maximum-based approach has its tradeoffs:
- In its favor: it aligns with how we intend to measure a scroll as a uniform single-duration value.
- In its favor: it reduces noise in long-lived interactions like keyboards, where a slowly-released
keyupmight otherwise inflate latency without reflecting visual delay. - The downside: it doesn't represent the entire wait time, since it captures only the beginning or end of an interaction such as a drag.
For scroll, which produces one relevant event-like trigger, the latency is just the difference between the event's timeStamp and the paint of the first resulting frame.
Aggregating Interactions Per Page
Defining individual interaction latencies gives us building blocks, but we need a single number per page load to be practical:
- Correlating with business metrics requires one value per page.
- Evaluating correlation with existing metrics (like LCP or CLS) is simpler when we're comparing single figures.
- Tooling should show responsive health without forcing users through interaction-level data.
Aggregation raises two specific questions: what values to aggregate and how to combine them. We are exploring options and want external feedback on both.
One direction is to set a per-type latency budget (say, 100 ms for taps) and then take the maximum amount by which any interaction exceeds its budget on the page. A tap with 150 ms latency, for instance, would contribute 50 ms of overage toward the aggregate.
Another is to use central-tendency statistics: compute the average (or median) latency across all interactions during the page's lifetime—so pages with latencies of 80, 90, and 100 ms would have a 90 ms average. We could also apply the over-budget framing when averaging, since different interaction types warrant different expectations.
Both approaches have merits, and we're actively evaluating them. The goal is to find an aggregation that is easy to interpret, stable per page, and clearly separating sites that respond well to interactions from those that don't.
Measuring responsiveness today
The ideas outlined above are not all directly supported by the current Event Timing API. There are two notable gaps:
- No interaction grouping: The API does not expose which events belong to a single user interaction. To address this, a proposal has been made to add an
interactionIDto the API, allowing developers to tie events back to a specific gesture. - No scroll support: Scroll-based interactions are entirely absent from Event Timing. Work is underway to enable these measurements, either through Event Timing itself or via a separate dedicated API.
What you can use now
Even without these upcoming features, it is possible to compute the maximum latency for the two interaction categories that matter most: taps/drags and keyboard input. The code below produces both metrics from the current Event Timing data.
let maxTapOrDragDuration = 0;
let maxKeyboardDuration = 0;
const observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => {
switch(entry.name) {
case "keydown":
case "keyup":
maxKeyboardDuration = Math.max(maxKeyboardDuration,
entry.duration);
break;
case "pointerdown":
case "pointerup":
case "click":
maxTapOrDragDuration = Math.max(maxTapOrDragDuration,
entry.duration);
break;
}
});
});
observer.observe({type: "event", durationThreshold: 16, buffered: true});
// We can report maxTapDragDuration and maxKeyboardDuration when sending
// metrics to analytics.
Questions or feedback?
For comments on these proposals or the metric design, contact: [email protected].



