PerformanceEventTiming
======================

The `PerformanceEventTiming` interface of the Event Timing API provides insights into the latency of certain event types triggered by user interaction.

Description
-----------

This API enables visibility into slow events by providing event timestamps and duration for certain event types (see below). For example, you can monitor the time between a user action and the start of its event handler, or the time an event handler takes to run.

This API is particularly useful for measuring the first input delay (FID): the time from the point when a user first interacts with your app to the point when the browser is actually able to respond to that interaction.

You typically work with `PerformanceEventTiming` objects by creating a `PerformanceObserver` instance and then calling its `observe()` method, passing in `"event"` or `"first-input"` as the value of the `type` option. The `PerformanceObserver` object's callback will then be called with a list of `PerformanceEventTiming` objects which you can analyze. See the example below for more.

 By default, `PerformanceEventTiming` entries are exposed when their `duration` is 104ms or greater. Research suggests that user input that is not handled within 100ms is considered slow and 104ms is the first multiple of 8 greater than 100ms (for security reasons, this API is rounded to the nearest multiple of 8ms).
 However, you can set the `PerformanceObserver` to a different threshold using the `durationThreshold` option in the `observe()` method.

This interface inherits methods and properties from its parent, `PerformanceEntry`:

PerformanceEntry

PerformanceEventTiming### Events exposed

The following event types are exposed by the Event Timing API:

|  |  |
| --- | --- |
| Click events | `auxclick`,
 `click`,
 `contextmenu`,
 `dblclick` |
| Composition events | `compositionend`,
 `compositionstart`,
 `compositionupdate` |
| Drag & drop events | `dragend`,
 `dragenter`,
 `dragleave`,
 `dragover`,
 `dragstart`,
 `drop` |
| Input events | `beforeinput`,
 `input` |
| Keyboard events | `keydown`,
 `keypress`,
 `keyup` |
| Mouse events | `mousedown`,
 `mouseenter`,
 `mouseleave`,
 `mouseout`,
 `mouseover`,
 `mouseup` |
| Pointer events | `pointerover`,
 `pointerenter`,
 `pointerdown`,
 `pointerup`,
 `pointercancel`,
 `pointerout`,
 `pointerleave`,
 `gotpointercapture`,
 `lostpointercapture` |
| Touch events | `touchstart`,
 `touchend`,
 `touchcancel` |

 Note that the following events are not included in the list because they are continuous events and no meaningful event counts or performance metrics can be obtained at this point: `mousemove`, `pointermove`,
 `pointerrawupdate`, `touchmove`, `wheel`, `drag`.

To get a list of all exposed events, you can also look up keys in the `performance.eventCounts` map:


```js
const exposedEventsList = [...performance.eventCounts.keys()];
```

Constructor
-----------

This interface has no constructor on its own. See the example below for how to typically get the information the `PerformanceEventTiming` interface holds.

Instance properties
-------------------

This interface extends the following `PerformanceEntry` properties for event timing performance entry types by qualifying them as follows:

`PerformanceEntry.duration` Read only 

Returns a `DOMHighResTimeStamp` representing the time from `startTime` to the next rendering paint (rounded to the nearest 8ms).

`PerformanceEntry.entryType` Read only 

Returns `"event"` (for long events) or `"first-input"` (for the first user interaction).

`PerformanceEntry.name` Read only 

Returns the associated event's type.

`PerformanceEntry.startTime` Read only 

Returns a `DOMHighResTimeStamp` representing the associated event's `timestamp` property. This is the time the event was created and can be considered as a proxy for the time the user interaction occurred.

This interface also supports the following properties:

`PerformanceEventTiming.cancelable` Read only 

Returns the associated event's `cancelable` property.

`PerformanceEventTiming.interactionId` Read only  
Experimental

Returns the ID that uniquely identifies the user interaction which triggered the associated event.

`PerformanceEventTiming.processingStart` Read only 

Returns a `DOMHighResTimeStamp` representing the time at which event dispatch started. To measure the time between a user action and the time the event handler starts to run, calculate `processingStart-startTime`.

`PerformanceEventTiming.processingEnd` Read only 

Returns a `DOMHighResTimeStamp` representing the time at which the event dispatch ended. To measure the time the event handler took to run, calculate `processingEnd-processingStart`.

`PerformanceEventTiming.target` Read only 

Returns the associated event's last target, if it is not removed.

Instance methods
----------------

`PerformanceEventTiming.toJSON()`

Returns a JSON representation of the `PerformanceEventTiming` object.

Examples
--------

### Getting event timing information

To get event timing information, create a `PerformanceObserver` instance and then call its `observe()` method, passing in `"event"` or `"first-input"` as the value of the `type` option. You also need to set `buffered` to `true` to get access to events the user agent buffered while constructing the document. The `PerformanceObserver` object's callback will then be called with a list of `PerformanceEventTiming` objects which you can analyze.


```js
const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    // Full duration
    const duration = entry.duration;

    // Input delay (before processing event)
    const delay = entry.processingStart - entry.startTime;

    // Synchronous event processing time
    // (between start and end dispatch)
    const eventHandlerTime = entry.processingEnd - entry.processingStart;
    console.log(`Total duration: ${duration}`);
    console.log(`Event delay: ${delay}`);
    console.log(`Event handler duration: ${eventHandlerTime}`);
  });
});

// Register the observer for events
observer.observe({ type: "event", buffered: true });
```


You can also set a different `durationThreshold`. The default is 104ms and the minimum possible duration threshold is 16ms.


```js
observer.observe({ type: "event", durationThreshold: 16, buffered: true });
```

### Reporting the First Input Delay (FID)

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


```js
// 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://webkit.org/b/209216
try {
  function onFirstInputEntry(entry) {
    // 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;

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

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

  // 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.
}
```

Specifications
--------------

| Specification |
| --- |
| Event Timing API # sec-performance-event-timing |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.