Déboguer les performances sur le terrain

Découvrez comment attribuer des informations de débogage à vos données de performances pour vous aider à identifier et à résoudre les problèmes des utilisateurs réels avec Analytics.

Google propose deux catégories d'outils pour mesurer et déboguer les performances:

  • Outils de l'atelier:outils tels que Lighthouse, où votre page est chargée dans un environnement simulé qui peut simuler différentes conditions (par exemple, un réseau lent et un appareil mobile bas de gamme).
  • Outils de terrain:outils tels que le rapport d'expérience utilisateur Chrome (CrUX), basé sur des données utilisateur réelles agrégées provenant de Chrome. (Notez que les données réelles fournies par des outils tels que PageSpeed Insights et Search Console proviennent des données CrUX.)

Alors que les outils de terrain offrent des données plus précises, c'est-à-dire des données qui représentent réellement l'expérience utilisateur réelle, les outils de test sont souvent plus efficaces pour vous aider à identifier et à résoudre les problèmes.

Les données CrUX sont plus représentatives des performances réelles de votre page, mais connaître vos scores CrUX ne vous aidera probablement pas à déterminer comment améliorer vos performances.

Lighthouse, quant à lui, identifie les problèmes et propose des suggestions d'amélioration spécifiques. Toutefois, Lighthouse ne fait des suggestions que pour les problèmes de performances qu'il détecte au moment du chargement de la page. Elle ne détecte pas les problèmes qui ne se manifestent qu'à la suite d'une interaction de l'utilisateur, comme un défilement ou un clic sur des boutons de la page.

Cela soulève une question importante: comment collecter des informations de débogage pour les Core Web Vitals ou d'autres métriques de performances auprès d'utilisateurs réels sur le terrain ?

Cet article explique en détail quelles API vous pouvez utiliser afin de collecter des informations de débogage supplémentaires pour chacune des métriques Core Web Vitals actuelles. Il vous explique également comment collecter ces données dans votre outil d'analyse existant.

API pour l'attribution et le débogage

CLS

De toutes les métriques Core Web Vitals, le CLS est peut-être celui pour lequel la collecte des informations de débogage sur le terrain est la plus importante. Le CLS est mesuré tout au long de la durée de vie de la page. Par conséquent, la façon dont un utilisateur interagit avec la page (dans quelle mesure il la fait défiler, sur quoi il clique, etc.) peut avoir un impact significatif sur l'existence ou non de décalages de mise en page, et sur les éléments qui se décalent.

Prenons l'exemple du rapport suivant de PageSpeed Insights:

Un rapport PageSpeed Insights avec différentes valeurs CLS

La valeur rapportée pour le CLS de l'atelier (Lighthouse) par rapport au CLS du terrain (données CrUX) est assez différente, ce qui est logique si vous considérez que la page comporte peut-être beaucoup de contenu interactif qui n'est pas utilisé lors des tests dans Lighthouse.

Toutefois, même si vous comprenez que l'interaction de l'utilisateur affecte les données réelles, vous devez tout de même savoir quels éléments de la page sont décalés, ce qui donne un score de 0,3 au 75e centile.

C'est possible avec l'interface LayoutShiftAttribution.

Obtenir l'attribution du décalage de mise en page

L'interface LayoutShiftAttribution est exposée sur chaque entrée layout-shift émise par l'API Layout Instability.

Pour obtenir une explication détaillée de ces deux interfaces, consultez la section Déboguer les décalages de mise en page. Pour les besoins de cet article, la principale chose à savoir est qu'en tant que développeur, vous pouvez observer chaque décalage de mise en page qui se produit sur la page, ainsi que les changements d'éléments.

Voici un exemple de code qui enregistre chaque décalage de mise en page, ainsi que les éléments qui ont été décalés:

new PerformanceObserver((list) => {
  for (const {value, startTime, sources} of list.getEntries()) {
    // Log the shift amount and other entry info.
    console.log('Layout shift:', {value, startTime});
    if (sources) {
      for (const {node, curRect, prevRect} of sources) {
        // Log the elements that shifted.
        console.log('  Shift source:', node, {curRect, prevRect});
      }
    }
  }
}).observe({type: 'layout-shift', buffered: true});

Il n'est probablement pas pratique de mesurer et d'envoyer des données à votre outil d'analyse pour chaque décalage de mise en page qui se produit. Toutefois, en surveillant tous les décalages, vous pouvez suivre les pires décalages et vous contenter de générer des informations à leur sujet.

L'objectif n'est pas d'identifier et de corriger tous les décalages de mise en page qui se produisent pour chaque utilisateur. L'objectif est d'identifier les décalages qui affectent le plus grand nombre d'utilisateurs et qui contribuent donc le plus au CLS de votre page au 75e centile.

De plus, vous n'avez pas besoin de calculer le plus grand élément source chaque fois qu'il y a un changement. Vous ne devez le faire que lorsque vous êtes prêt à envoyer la valeur CLS à votre outil d'analyse.

Le code suivant prend une liste d'entrées layout-shift qui ont contribué au CLS et renvoie le plus grand élément source lors du décalage le plus important:

function getCLSDebugTarget(entries) {
  const largestEntry = entries.reduce((a, b) => {
    return a && a.value > b.value ? a : b;
  });
  if (largestEntry && largestEntry.sources && largestEntry.sources.length) {
    const largestSource = largestEntry.sources.reduce((a, b) => {
      return a.node && a.previousRect.width * a.previousRect.height >
          b.previousRect.width * b.previousRect.height ? a : b;
    });
    if (largestSource) {
      return largestSource.node;
    }
  }
}

Une fois que vous avez identifié l'élément le plus important ayant contribué à la variation la plus importante, vous pouvez le signaler à votre outil d'analyse.

L'élément contribuant le plus au CLS pour une page donnée variera probablement d'un utilisateur à l'autre. Toutefois, si vous regroupez ces éléments pour tous les utilisateurs, vous pourrez générer une liste d'éléments changeants affectant le plus grand nombre d'utilisateurs.

Une fois que vous avez identifié et corrigé la cause des variations de ces éléments, votre code d'analyse commence à signaler des variations mineures, car elles correspondent aux "pires" variations pour vos pages. À terme, toutes les variations enregistrées seront suffisamment minimes pour que vos pages se situent bien en deçà du "bon" seuil de 0,1.

Voici d'autres métadonnées qu'il peut être utile de capturer avec l'élément source de décalage le plus important:

  • L'heure du plus grand glissement
  • Chemin de l'URL au moment du plus grand décalage (pour les sites qui mettent à jour l'URL de manière dynamique, tels que les applications monopages).

LCP

Pour déboguer le LCP dans le champ, la principale information dont vous avez besoin est l'élément le plus grand (l'élément LCP candidat) pour ce chargement de page particulier.

Notez qu'il est tout à fait possible (en fait, c'est assez courant) que l'élément LCP candidat soit différent d'un utilisateur à l'autre, même pour la même page.

Plusieurs raisons sont possibles :

  • Les appareils des utilisateurs ont des résolutions d'écran différentes, ce qui entraîne des mises en page différentes et donc différents éléments visibles dans la fenêtre d'affichage.
  • Les utilisateurs ne chargent pas toujours les pages qu'ils font défiler jusqu'en haut. Souvent, les liens contiennent des identifiants de fragments, voire des fragments de texte, ce qui signifie que vos pages peuvent être chargées et affichées n'importe où sur la page.
  • Le contenu peut être personnalisé pour l'utilisateur actuel. L'élément candidat pour le LCP peut donc varier considérablement d'un utilisateur à l'autre.

Cela signifie que vous ne pouvez pas supposer quel élément ou ensemble d'éléments sera l'élément LCP candidat le plus courant pour une page particulière. Vous devez la mesurer en fonction du comportement réel de l'utilisateur.

Identifier l'élément LCP candidat

Pour déterminer l'élément candidat pour le LCP en JavaScript, vous pouvez utiliser l'API Largest Contentful Paint, qui est la même API que celle utilisée pour déterminer la valeur de durée LCP.

Lorsque vous observez des entrées largest-contentful-paint, vous pouvez déterminer l'élément LCP actuel en examinant la propriété element de la dernière entrée:

new PerformanceObserver((list) => {
  const entries = list.getEntries();
  const lastEntry = entries[entries.length - 1];

  console.log('LCP element:', lastEntry.element);
}).observe({type: 'largest-contentful-paint', buffered: true});

Une fois que vous connaissez l'élément candidat pour le LCP, vous pouvez l'envoyer à votre outil d'analyse avec la valeur de la métrique. Comme pour le CLS, cela vous aidera à identifier les éléments à optimiser en priorité.

En plus de l'élément candidat pour le LCP, il peut également être utile de mesurer la durée de la sous-partie LCP, ce qui peut être utile pour déterminer quelles étapes d'optimisation spécifiques sont pertinentes pour votre site.

FID

Pour déboguer le FID sur le terrain, il est important de garder à l'esprit que FID ne mesure que la partie retard de la latence globale du premier événement d'entrée. Cela signifie que ce avec quoi l'utilisateur a interagi n'est pas vraiment aussi important que ce qui se passait sur le thread principal au moment de l'interaction.

Par exemple, de nombreuses applications JavaScript compatibles avec l'affichage côté serveur (SSR) fournissent du code HTML statique pouvant être affiché à l'écran avant d'être interactif avec l'entrée utilisateur, c'est-à-dire avant que le code JavaScript requis pour rendre le contenu interactif ne soit terminé.

Pour ces types d'applications, il peut être très important de savoir si la première entrée s'est produite avant ou après l'hydratation. S'il s'avère que de nombreuses personnes tentent d'interagir avec la page avant la fin de l'hydratation, envisagez d'afficher vos pages dans un état désactivé ou de chargement plutôt que dans un état qui semble interactif.

Si le framework d'application expose le code temporel d'hydratation, vous pouvez le comparer à celui de l'entrée first-input pour déterminer si la première entrée s'est produite avant ou après l'hydratation. Si votre framework n'expose pas cet horodatage ou n'utilise pas du tout l'hydratation, un autre signal utile peut indiquer si l'entrée a eu lieu avant ou après la fin du chargement de JavaScript.

L'événement DOMContentLoaded se déclenche une fois que le code HTML de la page est entièrement chargé et analysé, ce qui inclut l'attente du chargement des scripts synchrones, différés ou de module (y compris tous les modules importés de manière statique). Vous pouvez donc utiliser la chronologie de cet événement et la comparer au moment où le FID s'est produit.

Le code suivant observe les entrées first-input et consigne si la première entrée a eu lieu ou non avant la fin de l'événement DOMContentLoaded:

new PerformanceObserver((list) => {
  const fidEntry = list.getEntries()[0];
  const navEntry = performance.getEntriesByType('navigation')[0];
  const wasFIDBeforeDCL =
    fidEntry.startTime < navEntry.domContentLoadedEventStart;

  console.log('FID occurred before DOMContentLoaded:', wasFIDBeforeDCL);
}).observe({type: 'first-input', buffered: true});

Identifier l'élément cible du FID et le type d'événement

D'autres signaux de débogage potentiellement utiles sont l'élément avec lequel l'utilisateur a interagi ainsi que le type d'interaction (par exemple, mousedown, keydown ou pointerdown). Bien que l'interaction avec l'élément lui-même ne contribue pas au FID (n'oubliez pas que le FID ne correspond qu'à la partie retard de la latence totale de l'événement), il peut être utile de savoir avec quels éléments vos utilisateurs interagissent pour déterminer la meilleure façon d'améliorer le FID.

Par exemple, si la grande majorité des premières interactions de l'utilisateur concernent un élément particulier, envisagez d'intégrer le code JavaScript nécessaire à cet élément dans le code HTML et de charger le reste de manière différée.

Pour obtenir le type et l'élément d'interaction associés au premier événement d'entrée, vous pouvez référencer les propriétés target et name de l'entrée first-input:

new PerformanceObserver((list) => {
  const fidEntry = list.getEntries()[0];

  console.log('FID target element:', fidEntry.target);
  console.log('FID interaction type:', fidEntry.name);
}).observe({type: 'first-input', buffered: true});

INP

INP est très semblable au FID dans la mesure où les informations les plus utiles à capturer dans le champ sont les suivantes:

  1. Élément avec lequel l'utilisateur a interagi
  2. Pourquoi le type d'interaction
  3. La date à laquelle cette interaction a eu lieu

Comme le FID, le thread principal bloqué est l'une des principales causes de la lenteur des interactions, ce qui peut être courant lors du chargement de JavaScript. Le fait de savoir si la plupart des interactions lentes se produisent lors du chargement de la page est utile pour déterminer les mesures à prendre pour résoudre le problème.

Contrairement au FID, la métrique INP prend en compte la latence complète d'une interaction, y compris le temps nécessaire pour exécuter des écouteurs d'événements enregistrés, ainsi que le temps nécessaire pour peindre le frame suivant une fois que tous les écouteurs d'événements ont été exécutés. Cela signifie que pour INP, il est encore plus utile de savoir quels éléments cibles ont tendance à entraîner des interactions lentes, et quels sont les types d'interactions.

Étant donné que INP et FID sont tous deux basés sur l'API Event Timing, la manière dont vous déterminez ces informations en JavaScript est très semblable à l'exemple précédent. Le code suivant enregistre l'élément cible et l'heure (par rapport à DOMContentLoaded) de l'entrée INP.

function logINPDebugInfo(inpEntry) {
  console.log('INP target element:', inpEntry.target);
  console.log('INP interaction type:', inpEntry.name);

  const navEntry = performance.getEntriesByType('navigation')[0];
  const wasINPBeforeDCL =
    inpEntry.startTime < navEntry.domContentLoadedEventStart;

  console.log('INP occurred before DCL:', wasINPBeforeDCL);
}

Notez que ce code ne montre pas comment déterminer quelle entrée event correspond à l'entrée INP, car cette logique est plus complexe. Cependant, la section suivante explique comment obtenir ces informations à l'aide de la bibliothèque JavaScript web-vitals.

Utilisation avec la bibliothèque JavaScript web-vitals

Les sections ci-dessus proposent des suggestions générales et des exemples de code pour capturer les informations de débogage à inclure dans les données que vous envoyez à votre outil d'analyse.

Depuis la version 3, la bibliothèque JavaScript web-vitals inclut une création d'attribution qui affiche toutes ces informations, ainsi que quelques signaux supplémentaires.

L'exemple de code suivant montre comment définir un paramètre d'événement supplémentaire (ou une dimension personnalisée) contenant une chaîne de débogage utile pour identifier l'origine des problèmes de performances.

import {onCLS, onFID, onINP, onLCP} from 'web-vitals/attribution';

function sendToGoogleAnalytics({name, value, id, attribution}) {
  const eventParams = {
    metric_value: value,
    metric_id: id,
  }

  switch (name) {
    case 'CLS':
      eventParams.debug_target = attribution.largestShiftTarget;
      break;
    case 'LCP':
      eventParams.debug_target = attribution.element;
      break;
    case 'FID':
    case 'INP':
      eventParams.debug_target = attribution.eventTarget;
      break;
  }

  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/ga4
  gtag('event', name, eventParams);
}

onCLS(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
onFID(sendToGoogleAnalytics);
onINP(sendToGoogleAnalytics);

Ce code est spécifique à Google Analytics, mais l'idée générale doit également s'appliquer à d'autres outils d'analyse.

Ce code montre également comment générer des rapports sur un seul signal de débogage, mais il peut être utile de collecter plusieurs signaux différents par métrique pour générer des rapports les concernant. Par exemple, pour déboguer l'INP, vous pouvez collecter le type d'interaction, l'heure et l'élément avec lequel vous interagissez. Le build de l'attribution web-vitals présente toutes ces informations, comme illustré dans l'exemple suivant:

import {onCLS, onFID, onINP, onLCP} from 'web-vitals/attribution';

function sendToGoogleAnalytics({name, value, id, attribution}) {
  const eventParams = {
    metric_value: value,
    metric_id: id,
  }

  switch (name) {
    case 'INP':
      eventParams.debug_target = attribution.eventTarget;
      eventParams.debug_type = attribution.eventType;
      eventParams.debug_time = attribution.eventTime;
      eventParams.debug_load_state = attribution.loadState;
      break;

    // Additional metric logic...
  }

  // Assumes the global `gtag()` function exists, see:
  // https://developers.google.com/analytics/devguides/collection/ga4
  gtag('event', name, eventParams);
}

onCLS(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
onFID(sendToGoogleAnalytics);
onINP(sendToGoogleAnalytics);

Consultez la documentation sur l'attribution web-vitals pour obtenir la liste complète des signaux de débogage exposés.

Créer des rapports et visualiser les données

Une fois que vous avez commencé à collecter des informations de débogage ainsi que les valeurs des métriques, l'étape suivante consiste à agréger les données de tous vos utilisateurs pour commencer à rechercher des modèles et des tendances.

Comme indiqué ci-dessus, vous n'avez pas nécessairement besoin de résoudre tous les problèmes rencontrés par vos utilisateurs. Vous devez aborder, en particulier au début, ceux qui affectent le plus grand nombre d'utilisateurs, mais aussi ceux qui ont le plus d'impact négatif sur vos scores Core Web Vitals.

Pour GA4, consultez l'article dédié sur comment interroger et visualiser les données à l'aide de BigQuery.

Résumé

Nous espérons que cet article vous a permis de comprendre comment utiliser les API Performance existantes et la bibliothèque web-vitals pour obtenir des informations de débogage afin de diagnostiquer les performances en fonction des visites réelles des utilisateurs sur le terrain. Bien que ce guide soit axé sur les métriques Core Web Vitals, les concepts s'appliquent également au débogage des métriques de performances mesurables en JavaScript.

Si vous commencez tout juste à mesurer les performances et que vous utilisez déjà Google Analytics, le rapport sur les métriques Web peut constituer un bon point de départ, car il prend déjà en charge les rapports de débogage des informations de débogage pour les métriques Core Web Vitals.

Si vous êtes un fournisseur de solutions d'analyse et que vous souhaitez améliorer vos produits et fournir plus d'informations de débogage à vos utilisateurs, envisagez certaines des techniques décrites ici, mais ne vous limitez pas uniquement aux idées présentées ici. Cet article est destiné à s'appliquer de manière générale à tous les outils d'analyse. Toutefois, les outils d'analyse individuels peuvent (et doivent) collecter et rapporter encore plus d'informations de débogage.

Enfin, si vous pensez qu'il y a des lacunes dans votre capacité à déboguer ces métriques en raison de fonctionnalités ou d'informations manquantes dans les API elles-mêmes, envoyez vos commentaires à web-vitals-feedback@googlegroups.com.