Learn Measure Blog Live About

First Input Delay (FID)

Updated
Appears in: Metrics

First Input Delay (FID) is an important, user-centric metric for measuring load responsiveness because it quantifies the experience users feel when trying to interact with unresponsive pages—a low FID helps ensure that the page is usable.

We all know how important it is to make a good first impression. It's important when meeting new people, and it's also important when building experiences on the web.

On the web, a good first impression can make the difference between someone becoming a loyal user or them leaving and never coming back. The question is, what makes for a good impression, and how do you measure what kind of impression you're likely making on your users?

On the web, first impressions can take a lot of different forms—we have first impressions of a site's design and visual appeal as well as first impressions of its speed and responsiveness.

While it is hard to measure how much users like a site's design with web APIs, measuring its speed and responsiveness is not!

The first impression users have of how fast your site loads can be measured with First Contentful Paint (FCP). But how fast your site can paint pixels to the screen is just part of the story. Equally important is how responsive your site is when users try to interact with those pixels!

The First Input Delay (FID) metric helps measure your user's first impression of your site's interactivity and responsiveness.

What is FID?

FID measures the time from when a user first interacts with a page (i.e. when they click a link, tap on a button, or use a custom, JavaScript-powered control) to the time when the browser is actually able to begin processing event handlers in response to that interaction.

Good fid values are 2.5 seconds, poor values are greater than 4.0
            seconds and anything in between needs improvement

What is a good FID score?

To provide a good user experience, sites should strive to have a First Input Delay of less than 100 milliseconds. To ensure you're hitting this target for most of your users, a good threshold to measure is the 75th percentile of page loads, segmented across mobile and desktop devices.

To learn more about the research and methodology behind this recommendation, see: Defining the Core Web Vitals metrics thresholds

FID in detail

As developers who write code that responds to events, we often assume our code is going to be run immediately—as soon as the event happens. But as users, we've all frequently experienced the opposite—we've loaded a web page on our phone, tried to interact with it, and then been frustrated when nothing happened.

In general, input delay (a.k.a. input latency) happens because the browser's main thread is busy doing something else, so it can't (yet) respond to the user. One common reason this might happen is the browser is busy parsing and executing a large JavaScript file loaded by your app. While it's doing that, it can't run any event listeners because the JavaScript it's loading might tell it to do something else.

Gotchas!

FID only measures the "delay" in event processing. It does not measure the event processing time itself nor the time it takes the browser to update the UI after running event handlers. While this time does affect the user experience, including it as part of FID would incentivize developers to respond to events asynchronously—which would improve the metric but likely make the experience worse. See why only consider the input delay below for more details.

Consider the following timeline of a typical web page load:

Example page load trace

The above visualization shows a page that's making a couple of network requests for resources (most likely CSS and JS files), and—after those resources are finished downloading—they're processed on the main thread.

This results in periods where the main thread is momentarily busy, which is indicated by the beige-colored task blocks.

Long first input delays typically occur between First Contentful Paint (FCP) and Time to Interactive (TTI) because the page has rendered some of its content but isn't yet reliably interactive. To illustrate how this can happen, FCP and TTI have been added to the timeline:

Example page load trace with FCP and TTI

You may have noticed that there's a fair amount of time (including three long tasks) between FCP and TTI, if a user tries to interact with the page during that time (e.g. click on a link), there will be a delay between when the click is received and when the main thread is able to respond.

Consider what would happen if a user tried to interact with the page near the beginning of the longest task:

Example page load trace with FCP, TTI, and FID

Because the input occurs while the browser is in the middle of running a task, it has to wait until the task completes before it can respond to the input. The time it must wait is the FID value for this user on this page.

In this example the user just happened to interact with the page at the beginning of the main thread's most busy period. If the user had interacted with the page just a moment earlier (during the idle period) the browser could have responded right away. This variance in input delay underscores the importance of looking at the distribution of FID values when reporting on the metric. You can read more about this in the section below on analyzing and reporting on FID data.

What if an interaction doesn't have an event listener?

FID measures the delta between when an input event is received and when the main thread is next idle. This means FID is measured even in cases where an event listener has not been registered. The reason is because many user interactions do not require an event listener but do require the main thread to be idle in order to run.

For example, all of the following native HTML elements need to wait for in-progress tasks on the main thread to complete prior to responding to user interactions:

  • Text fields, checkboxes, and radio buttons (<input>, <textarea>)
  • Select dropdowns (<select>)
  • links (<a>)

Why only consider the first input?

While a delay from any input can lead to a bad user experience, we primarily recommend measuring the first input delay for a few reasons:

  • The first input delay will be the user's first impression of your site's responsiveness, and first impressions are critical in shaping our overall impression of a site's quality and reliability.
  • The biggest interactivity issues we see on the web today occur during page load. Therefore, we believe initially focusing on improving site's first user interaction will have the greatest impact on improving the overall interactivity of the web.
  • The recommended solutions for how sites should fix high first input delays (code splitting, loading less JavaScript upfront, etc.) are not necessarily the same solutions for fixing slow input delays after page load. By separating out these metrics we'll be able to provide more specific performance guidelines to web developers.

What counts as a first input?

FID is a metric that measures a page's responsiveness during load. As such, it only focuses on input events from discrete actions like clicks, taps, and key presses.

Other interactions, like scrolling and zooming, are continuous actions and have completely different performance constraints (also, browsers are often able to hide their latency by running them on a separate thread).

To put this another way, FID focuses on the R (responsiveness) in the RAIL performance model, whereas scrolling and zooming are more related to A (animation), and their performance qualities should be evaluated separately.

What if a user never interacts with your site?

Not all users will interact with your site every time they visit. And not all interactions are relevant to FID (as mentioned in the previous section). In addition, some user's first interactions will be at bad times (when the main thread is busy for an extended period of time), and some user's first interactions will be at good times (when the main thread is completely idle).

This means some users will have no FID values, some users will have low FID values, and some users will probably have high FID values.

How you track, report on, and analyze FID will probably be quite a bit different from other metrics you may be used to. The next section explains how best to do this.

Why only consider the input delay?

As mentioned above, FID only measures the "delay" in event processing. It does not measure the event processing time itself nor the time it takes the browser to update the UI after running event handlers.

Even though this time is important to the user and does affect the experience, it's not included in this metric because doing so could incentivize developers to add workarounds that actually make the experience worse—that is, they could wrap their event handler logic in an asynchronous callback (via setTimeout() or requestAnimationFrame()) in order to separate it from the task associated with the event. The result would be an improvement in the metric score but a slower response as perceived by the user.

However, while FID only measure the "delay" portion of event latency, developers who want to track more of the event lifecycle can do so using the Event Timing API. See the guide on custom metrics for more details.

How to measure FID

FID is a metric that can only be measured in the field, as it requires a real user to interact with your page. You can measure FID with the following tools.

FID requires a real user and thus cannot be measured in the lab. However, the Total Blocking Time (TBT) metric is lab-measurable, correlates well with FID in the field, and also captures issues that affect interactivity. Optimizations that improve TBT in the lab should also improve FID for your users.

Field tools

Measure FID in JavaScript

The easiest way to measure FID (as well as all Web Vitals field metrics) is with the web-vitals JavaScript library, which wraps all the complexity of manually measuring FID into a single function:

import {getFID} from 'web-vitals';

// Measure and log the current FID value,
// any time it's ready to be reported.
getFID(console.log);

To manually measure FID, you can use the Event Timing API. The following example shows how to create a PerformanceObserver that listens for first-input entries, calculates FID, and logs the value to the console:

// Keep track of whether (and when) the page was first hidden, see:
// https://github.com/w3c/page-visibility/issues/29
// NOTE: ideally this check would be performed in the document <head>
// to avoid cases where the visibility state changes before this code runs.
let firstHiddenTime = document.visibilityState === 'hidden' ? 0 : Infinity;
document.addEventListener('visibilitychange', (event) => {
firstHiddenTime = Math.min(firstHiddenTime, event.timeStamp);
}, {once: true});

// Sends the passed data to an analytics endpoint. This code
// uses `/analytics`; you can replace it with your own URL.
function sendToAnalytics(data) {
const body = JSON.stringify(data);
// Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
(navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
fetch('/analytics', {body, method: 'POST', keepalive: true});
}

// Use a try/catch instead of feature detecting `first-input`
// support, since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
function onFirstInputEntry(entry, po) {
// Only report FID if the page wasn't hidden prior to
// the entry being dispatched. This typically happens when a
// page is loaded in a background tab.
if (entry.startTime < firstHiddenTime) {
const fid = entry.processingStart - entry.startTime;

// Disconnect the observer.
po.disconnect();

// Report the FID value to an analytics endpoint.
sendToAnalytics({fid});
}
}

// Create a PerformanceObserver that calls `onFirstInputEntry` for each entry.
const po = new PerformanceObserver((entryList, po) => {
entryList.getEntries().forEach((entry) => onFirstInputEntry(entry, po));
});

// Observe entries of type `first-input`, including buffered entries,
// i.e. entries that occurred before calling `observe()` below.
po.observe({
type: 'first-input',
buffered: true,
});
} catch (e) {
// Do nothing if the browser doesn't support this API.
}

Analyzing and reporting on FID data

Due to the expected variance in FID values, it's critical that when reporting on FID you look at the distribution of values and focus on the higher percentiles.

While choice of percentile for all Core Web Vitals thresholds is the 75th, for FID in particular we still strongly recommend looking at the 95th–99th percentiles, as those will correspond to the particularly bad first experiences users are having with your site. And it will show you the areas that need the most improvement.

This is true even if you segment your reports by device category or type. For example, if you run separate reports for desktop and mobile, the FID value you care most about on desktop should be the 95th–99th percentile of desktop users, and the FID value you care about most on mobile should be the 95th–99th percentile of mobile users.

How to improve FID

To learn how to improve FID for a specific site, you can run a Lighthouse performance audit and pay attention to any specific opportunities the audit suggests.

While FID is a field metric (and Lighthouse is a lab metric tool), the guidance for improving FID is the same as that for improving the lab metric Total Blocking Time (TBT).

For a deep dive on how to improve FID, see Optimize FID. For additional guidance on individual performance techniques that can also improve FID, see:

CHANGELOG

Occasionally, bugs are discovered in the APIs used to measure metrics, and sometimes in the definitions of the metrics themselves. As a result, changes must sometimes be made, and these changes can show up as improvements or regressions in your internal reports and dashboards.

To help you manage this, all changes to either the implementation or definition of these metrics will be surfaced in this CHANGELOG.

Last updated: Improve article