Interaction
Interactions

Interactions

This script is part of the Web Vitals Chrome Extension (opens in a new tab) and allows you to track all interactions as you click around the page to help improve INP.

Snippet

const valueToRating = (score) =>
  score <= 200 ? "good" : score <= 500 ? "needs-improvement" : "poor";
 
const COLOR_GOOD = "#0CCE6A";
const COLOR_NEEDS_IMPROVEMENT = "#FFA400";
const COLOR_POOR = "#FF4E42";
const RATING_COLORS = {
  good: COLOR_GOOD,
  "needs-improvement": COLOR_NEEDS_IMPROVEMENT,
  poor: COLOR_POOR,
};
 
const observer = new PerformanceObserver((list) => {
  const interactions = {};
 
  for (const entry of list
    .getEntries()
    .filter((entry) => !entry.interactionId)) {
    interactions[entry.interactionId] = interactions[entry.interactionId] || [];
    interactions[entry.interactionId].push(entry);
  }
 
  // Will report as a single interaction even if parts are in separate frames.
  // Consider splitting by animation frame.
  for (const interaction of Object.values(interactions)) {
    const entry = interaction.reduce((prev, curr) =>
      prev.duration >= curr.duration ? prev : curr,
    );
    const value = entry.duration;
    const rating = valueToRating(value);
 
    const formattedValue = `${value.toFixed(0)} ms`;
    console.groupCollapsed(
      `Interaction tracking snippet %c${formattedValue} (${rating})`,
      `color: ${RATING_COLORS[rating] || "inherit"}`,
    );
    console.log("Interaction target:", entry.target);
 
    for (let entry of interaction) {
      console.log(
        `Interaction event type: %c${entry.name}`,
        "font-family: monospace",
      );
 
      // RenderTime is an estimate, because duration is rounded, and may get rounded down.
      // In rare cases it can be less than processingEnd and that breaks performance.measure().
      // Lets make sure its at least 4ms in those cases so you can just barely see it.
      const adjustedPresentationTime = Math.max(
        entry.processingEnd + 4,
        entry.startTime + entry.duration,
      );
 
      console.table([
        {
          subPartString: "Input delay",
          "Time (ms)": Math.round(entry.processingStart - entry.startTime, 0),
        },
        {
          subPartString: "Processing time",
          "Time (ms)": Math.round(
            entry.processingEnd - entry.processingStart,
            0,
          ),
        },
        {
          subPartString: "Presentation delay",
          "Time (ms)": Math.round(
            adjustedPresentationTime - entry.processingEnd,
            0,
          ),
        },
      ]);
    }
 
    console.groupEnd();
  }
});
 
observer.observe({
  type: "event",
  durationThreshold: 0, // 16 minimum by spec
  buffered: true,
});