Métriques personnalisées

Il est très utile de disposer de métriques centrées sur l'utilisateur que vous pouvez mesurer de manière universelle sur n'importe quel site Web. Ces métriques vous permettent de:

  • Comprendre comment les utilisateurs réels utilisent le Web dans son ensemble
  • Comparez votre site à celui d'un concurrent.
  • Suivez des données utiles et exploitables dans vos outils d'analyse sans avoir à écrire de code personnalisé.

Les métriques universelles constituent une bonne référence, mais dans de nombreux cas, vous devez mesurer plus que ces métriques pour capturer l'expérience complète de votre site.

Les métriques personnalisées vous permettent de mesurer des aspects de l'expérience sur votre site qui ne s'appliquent peut-être qu'à votre site, par exemple:

  • Temps nécessaire à une application monopage (SPA) pour passer d'une "page" à une autre.
  • Temps nécessaire pour qu'une page affiche les données extraites d'une base de données pour les utilisateurs connectés.
  • Durée d'hydratation d'une application rendue côté serveur (SSR).
  • Taux de réussite du cache pour les ressources chargées par les visiteurs connus.
  • Latence des événements de clic ou de clavier dans un jeu.

API pour mesurer les métriques personnalisées

Historiquement, les développeurs Web n'avaient pas beaucoup d'API de bas niveau pour mesurer les performances. Ils ont donc dû recourir à des astuces pour déterminer si un site était performant.

Par exemple, il est possible de déterminer si le thread principal est bloqué en raison de tâches JavaScript de longue durée en exécutant une boucle requestAnimationFrame et en calculant le delta entre chaque frame. Si le delta est considérablement plus long que le frame rate de l'écran, vous pouvez le signaler comme une tâche longue. Toutefois, ces piratages ne sont pas recommandés, car ils affectent les performances elles-mêmes (en vidant la batterie, par exemple).

La première règle d'une mesure efficace des performances consiste à s'assurer que vos techniques de mesure des performances ne provoquent pas elles-mêmes de problèmes de performances. Par conséquent, pour toutes les métriques personnalisées que vous mesurez sur votre site, nous vous recommandons d'utiliser l'une des API suivantes, si possible.

API Performance Observer

Navigateurs pris en charge

  • Chrome: 52.
  • Edge: 79.
  • Firefox: 57.
  • Safari: 11.

Source

L'API Performance Observer est le mécanisme qui collecte et affiche les données de toutes les autres API de performances abordées sur cette page. Il est essentiel de le comprendre pour obtenir de bonnes données.

Vous pouvez utiliser PerformanceObserver pour vous abonner passivement aux événements liés aux performances. Cela permet aux rappels d'API de se déclencher pendant les périodes d'inactivité, ce qui signifie qu'ils n'interfèrent généralement pas avec les performances de la page.

Pour créer un PerformanceObserver, transmettez-lui un rappel à exécuter chaque fois que de nouvelles entrées de performances sont distribuées. Vous indiquez ensuite à l'observateur les types d'entrées à écouter à l'aide de la méthode observe():

const po = new PerformanceObserver((list) => {
 
for (const entry of list.getEntries()) {
   
// Log the entry and all associated details.
    console
.log(entry.toJSON());
 
}
});

po
.observe({type: 'some-entry-type'});

Les sections suivantes répertorient tous les types d'entrées disponibles à l'observation. Toutefois, dans les navigateurs plus récents, vous pouvez inspecter les types d'entrées disponibles via la propriété statique PerformanceObserver.supportedEntryTypes.

Observer les entrées qui se sont déjà produites

Par défaut, les objets PerformanceObserver ne peuvent observer les entrées que lorsqu'elles se produisent. Cela peut entraîner des problèmes si vous souhaitez charger de manière différée votre code d'analyse des performances afin qu'il ne bloque pas les ressources de priorité plus élevée.

Pour obtenir les entrées de l'historique (après leur occurrence), définissez l'indicateur buffered sur true lorsque vous appelez observe(). Le navigateur inclura les entrées historiques de son tampon d'entrée de performances la première fois que votre rappel PerformanceObserver sera appelé, jusqu'à la taille maximale du tampon pour ce type.

po.observe({
  type
: 'some-entry-type',
  buffered
: true,
});

Anciennes API de performances à éviter

Avant l'API Performance Observer, les développeurs pouvaient accéder aux entrées de performances à l'aide des trois méthodes suivantes définies sur l'objet performance:

Bien que ces API soient toujours compatibles, leur utilisation n'est pas recommandée, car elles ne vous permettent pas d'écouter quand de nouvelles entrées sont émises. De plus, de nombreuses nouvelles API (telles que largest-contentful-paint) ne sont pas exposées via l'objet performance, mais uniquement via PerformanceObserver.

À moins que vous n'ayez spécifiquement besoin de la compatibilité avec Internet Explorer, il est préférable d'éviter ces méthodes dans votre code et d'utiliser PerformanceObserver à l'avenir.

API User Timing

Navigateurs pris en charge

  • Chrome: 28.
  • Edge: 12.
  • Firefox: 38.
  • Safari: 11.

Source

L'API User Timing est une API de mesure à usage général pour les métriques basées sur le temps. Il vous permet de marquer arbitrairement des points dans le temps, puis de mesurer la durée entre ces repères plus tard.

// Record the time immediately before running a task.
performance
.mark('myTask:start');
await doMyTask
();

// Record the time immediately after running a task.
performance
.mark('myTask:end');

// Measure the delta between the start and end of the task
performance
.measure('myTask', 'myTask:start', 'myTask:end');

Bien que des API telles que Date.now() ou performance.now() vous offrent des fonctionnalités similaires, l'avantage de l'API User Timing est qu'elle s'intègre bien aux outils de performances. Par exemple, les outils de développement Chrome visualisent les mesures de la durée utilisateur dans le panneau "Performances". De nombreux fournisseurs d'analyse suivent également automatiquement toutes les mesures que vous effectuez et envoient les données de durée à leur backend d'analyse.

Pour enregistrer les mesures de timing utilisateur, vous pouvez utiliser PerformanceObserver et vous inscrire pour observer les entrées de type measure:

// Create the performance observer.
const po = new PerformanceObserver((list) => {
 
for (const entry of list.getEntries()) {
   
// Log the entry and all associated details.
    console
.log(entry.toJSON());
 
}
});

// Start listening for `measure` entries to be dispatched.
po
.observe({type: 'measure', buffered: true});

API Long Tasks

Navigateurs pris en charge

  • Chrome: 58.
  • Edge: 79.
  • Firefox: non compatible.
  • Safari: non compatible.

Source

L'API Long Tasks permet de savoir quand le thread principal du navigateur est bloqué suffisamment longtemps pour affecter la fréquence d'images ou la latence de saisie. L'API signale toutes les tâches qui s'exécutent pendant plus de 50 millisecondes.

Chaque fois que vous devez exécuter du code coûteux, ou charger et exécuter de grands scripts, il est utile de savoir si ce code bloque le thread principal. En fait, de nombreuses métriques de niveau supérieur sont basées sur l'API Long Tasks elle-même (comme le temps de réponse (TTI) et le temps de blocage total (TBT)).

Pour déterminer quand des tâches longues se produisent, vous pouvez utiliser PerformanceObserver et vous enregistrer pour observer les entrées de type longtask:

// Create the performance observer.
const po = new PerformanceObserver((list) => {
 
for (const entry of list.getEntries()) {
   
// Log the entry and all associated details.
    console
.log(entry.toJSON());
 
}
});

// Start listening for `longtask` entries to be dispatched.
po
.observe({type: 'longtask', buffered: true});

API Long Animation Frames

Navigateurs pris en charge

  • Chrome: 123.
  • Edge: 123.
  • Firefox: non compatible.
  • Safari: non compatible.

Source

L'API Long Animation Frames est une nouvelle itération de l'API Long Tasks qui examine les frames longs (plutôt que les tâches longues) de plus de 50 millisecondes. Cela résout certains des défauts de l'API Long Tasks, y compris une meilleure attribution et une couverture plus large des retards potentiellement problématiques.

Pour déterminer quand des frames longs se produisent, vous pouvez utiliser PerformanceObserver et vous enregistrer pour observer les entrées de type long-animation-frame:

// Create the performance observer.
const po = new PerformanceObserver((list) => {
 
for (const entry of list.getEntries()) {
   
// Log the entry and all associated details.
    console
.log(entry.toJSON());
 
}
});

// Start listening for `long-animation-frame` entries to be dispatched.
po
.observe({type: 'long-animation-frame', buffered: true});

API Element Timing

Navigateurs pris en charge

  • Chrome: 77.
  • Edge: 79.
  • Firefox: non compatible.
  • Safari: non compatible.

Source

La métrique LCP (Largest Contentful Paint) permet de savoir quand la plus grande image ou le plus grand bloc de texte a été affiché à l'écran. Toutefois, dans certains cas, vous souhaitez mesurer le délai de rendu d'un autre élément.

Dans ce cas, utilisez l'API Element Timing. L'API LCP est en fait basée sur l'API Element Timing et ajoute des rapports automatiques sur l'élément le plus volumineux. Vous pouvez toutefois également créer des rapports sur d'autres éléments en leur ajoutant explicitement l'attribut elementtiming et en enregistrant un PerformanceObserver pour observer le type d'entrée element.

<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
<!-- ... -->

<script>
 
const po = new PerformanceObserver((entryList) => {
   
for (const entry of entryList.getEntries()) {
     
// Log the entry and all associated details.
      console
.log(entry.toJSON());
   
}
 
});

 
// Start listening for `element` entries to be dispatched.
  po
.observe({type: 'element', buffered: true});
</script>

API Event Timing

Navigateurs pris en charge

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 89.
  • Safari: non compatible.

Source

La métrique Interaction to Next Paint (INP) évalue la réactivité globale d'une page en observant toutes les interactions (clic, appui et commandes au clavier) survenant au cours de la vie d'une page. L'INP d'une page correspond le plus souvent à l'interaction la plus longue, du moment où l'utilisateur a initié l'interaction jusqu'au moment où le navigateur peint le frame suivant affichant le résultat visuel de l'entrée utilisateur.

La métrique INP est rendue possible par l'API Event Timing. Cette API expose un certain nombre de codes temporels qui se produisent au cours du cycle de vie de l'événement, y compris:

  • startTime: heure à laquelle le navigateur reçoit l'événement.
  • processingStart: heure à laquelle le navigateur peut commencer à traiter les gestionnaires d'événements pour l'événement.
  • processingEnd: heure à laquelle le navigateur a terminé l'exécution de tout code synchrone lancé à partir des gestionnaires d'événements pour cet événement.
  • duration: temps (arrondi à huit millisecondes pour des raisons de sécurité) écoulé entre le moment où le navigateur reçoit l'événement et celui où il peut peindre le frame suivant après avoir terminé l'exécution de tout le code synchrone lancé à partir des gestionnaires d'événements.

L'exemple suivant montre comment utiliser ces valeurs pour créer des mesures personnalisées:

const po = new PerformanceObserver((entryList) => {
 
// Get the last interaction observed:
 
const entries = Array.from(entryList.getEntries()).forEach((entry) => {
   
// Get various bits of interaction data:
   
const inputDelay = entry.processingStart - entry.startTime;
   
const processingTime = entry.processingEnd - entry.processingStart;
   
const presentationDelay = entry.startTime + entry.duration - entry.processingEnd;
   
const duration = entry.duration;
   
const eventType = entry.name;
   
const target = entry.target || "(not set)"

    console
.log("----- INTERACTION -----");
    console
.log(`Input delay (ms): ${inputDelay}`);
    console
.log(`Event handler processing time (ms): ${processingTime}`);
    console
.log(`Presentation delay (ms): ${presentationDelay}`);
    console
.log(`Total event duration (ms): ${duration}`);
    console
.log(`Event type: ${eventType}`);
    console
.log(target);
 
});
});

// A durationThreshold of 16ms is necessary to include more
// interactions, since the default is 104ms. The minimum
// durationThreshold is 16ms.
po
.observe({type: 'event', buffered: true, durationThreshold: 16});

API Resource Timing

Navigateurs pris en charge

  • Chrome: 29.
  • Edge: 12.
  • Firefox: 35.
  • Safari: 11.

Source

L'API Resource Timing fournit aux développeurs des informations détaillées sur le chargement des ressources d'une page spécifique. Malgré le nom de l'API, les informations qu'elle fournit ne se limitent pas aux données de chronométrage (bien qu'il y en ait beaucoup). Voici d'autres données auxquelles vous pouvez accéder:

  • initiatorType : méthode utilisée pour extraire la ressource (par exemple, à partir d'un tag <script> ou <link>, ou d'un appel fetch()).
  • nextHopProtocol: protocole utilisé pour extraire la ressource, par exemple h2 ou quic.
  • encodedBodySize/decodedBodySize : taille de la ressource sous forme encodée ou décodée (respectivement)
  • transferSize: taille de la ressource effectivement transférée sur le réseau. Lorsque les ressources sont satisfaites par le cache, cette valeur peut être beaucoup plus faible que encodedBodySize, et dans certains cas, elle peut être nulle (si aucune revalidation du cache n'est requise).

Vous pouvez utiliser la propriété transferSize des entrées de timing des ressources pour mesurer une métrique taux d'accès au cache ou une métrique taille totale des ressources mises en cache, ce qui peut être utile pour comprendre l'impact de votre stratégie de mise en cache des ressources sur les performances des visiteurs réguliers.

L'exemple suivant consigne toutes les ressources demandées par la page et indique si chacune d'elles a été satisfaite par le cache ou non.

// Create the performance observer.
const po = new PerformanceObserver((list) => {
 
for (const entry of list.getEntries()) {
   
// If transferSize is 0, the resource was fulfilled using the cache.
    console
.log(entry.name, entry.transferSize === 0);
 
}
});

// Start listening for `resource` entries to be dispatched.
po
.observe({type: 'resource', buffered: true});

Navigateurs pris en charge

  • Chrome: 57
  • Edge: 12.
  • Firefox: 58.
  • Safari: 15.

Source

L'API Navigation Timing est semblable à l'API Resource Timing, mais elle ne signale que les requêtes de navigation. Le type d'entrée navigation est également semblable au type d'entrée resource, mais il contient des informations supplémentaires spécifiques uniquement aux requêtes de navigation (par exemple, lorsque les événements DOMContentLoaded et load se déclenchent).

Une métrique que de nombreux développeurs suivent pour comprendre le temps de réponse du serveur (délai avant le premier octet (TTFB)) est disponible à l'aide de l'API Navigation Timing. Plus précisément, il s'agit du code temporel responseStart de l'entrée.

// Create the performance observer.
const po = new PerformanceObserver((list) => {
 
for (const entry of list.getEntries()) {
   
// If transferSize is 0, the resource was fulfilled using the cache.
    console
.log('Time to first byte', entry.responseStart);
 
}
});

// Start listening for `navigation` entries to be dispatched.
po
.observe({type: 'navigation', buffered: true});

Les développeurs qui utilisent un service worker peuvent également s'intéresser au temps de démarrage du service worker pour les requêtes de navigation. Il s'agit du temps nécessaire au navigateur pour démarrer le thread du service worker avant qu'il ne puisse commencer à intercepter les événements de récupération.

Le temps de démarrage du service worker pour une requête de navigation spécifique peut être déterminé à partir du delta entre entry.responseStart et entry.workerStart.

// Create the performance observer.
const po = new PerformanceObserver((list) => {
 
for (const entry of list.getEntries()) {
    console
.log('Service Worker startup time:',
        entry
.responseStart - entry.workerStart);
 
}
});

// Start listening for `navigation` entries to be dispatched.
po
.observe({type: 'navigation', buffered: true});

API Server Timing

Navigateurs pris en charge

  • Chrome: 65.
  • Edge: 79.
  • Firefox: 61.
  • Safari: 16.4.

Source

L'API Server Timing vous permet de transmettre des données temporelles spécifiques à la requête de votre serveur au navigateur via des en-têtes de réponse. Par exemple, vous pouvez indiquer le temps nécessaire pour rechercher des données dans une base de données pour une requête particulière. Cela peut être utile pour déboguer les problèmes de performances causés par la lenteur du serveur.

Pour les développeurs qui utilisent des fournisseurs d'analyse tiers, l'API Server Timing est le seul moyen de mettre en corrélation les données de performances du serveur avec d'autres métriques métier que ces outils d'analyse peuvent mesurer.

Pour spécifier des données de temporisation du serveur dans vos réponses, vous pouvez utiliser l'en-tête de réponse Server-Timing. Voici un exemple.

HTTP/1.1 200 OK

Server-Timing: miss, db;dur=53, app;dur=47.2

Ensuite, depuis vos pages, vous pouvez lire ces données sur les entrées resource ou navigation des API Resource Timing et Navigation Timing.

// Create the performance observer.
const po = new PerformanceObserver((list) => {
 
for (const entry of list.getEntries()) {
   
// Logs all server timing data for this response
    console
.log('Server Timing', entry.serverTiming);
 
}
});

// Start listening for `navigation` entries to be dispatched.
po
.observe({type: 'navigation', buffered: true});