Interaction
Interactions

Interactions

This script it's 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
});