Découvrez comment identifier les interactions lentes dans les données de champ de votre site Web afin de trouver des opportunités d'améliorer son Interaction to Next Paint.
Les données de terrain vous indiquent comment les utilisateurs réels interagissent avec votre site Web. Il permet de déceler des problèmes que vous ne pouvez pas trouver dans les données de laboratoire seules. En ce qui concerne l'Interaction to Next Paint (INP), les données de terrain sont essentielles pour identifier les interactions lentes et fournir des indices importants pour vous aider à les corriger.
Dans ce guide, vous allez découvrir comment évaluer rapidement l'INP de votre site Web à l'aide des données réelles du rapport d'expérience utilisateur Chrome (CrUX) pour déterminer si votre site Web présente des problèmes d'INP. Vous apprendrez ensuite à utiliser la version d'attribution de la bibliothèque JavaScript web-vitals et les nouveaux insights qu'elle fournit à partir de l'API Long Animation Frames (LoAF) pour collecter et interpréter les données de terrain concernant les interactions lentes sur votre site Web.
Commencez par CrUX pour évaluer l'INP de votre site Web
Si vous ne collectez pas de données d'utilisation réelles auprès des utilisateurs de votre site Web, CrUX peut être un bon point de départ. CrUX collecte des données de champ auprès de vrais utilisateurs de Chrome qui ont accepté d'envoyer des données de télémétrie.
Les données CrUX sont disponibles dans plusieurs zones différentes, en fonction de l'étendue des informations que vous recherchez. CrUX peut fournir des données sur l'INP et d'autres métriques Core Web Vitals pour :
- des pages individuelles et des origines entières à l'aide de PageSpeed Insights.
- Types de pages. Par exemple, de nombreux sites Web d'e-commerce proposent des types de pages "Page d'informations détaillées sur le produit" et "Page de liste de produits". Vous pouvez obtenir des données CrUX pour des types de pages uniques dans la Search Console.
Pour commencer, vous pouvez saisir l'URL de votre site Web dans PageSpeed Insights. Une fois l'URL saisie, les données de champ associées (si disponibles) s'affichent pour plusieurs métriques, y compris l'INP. Vous pouvez également utiliser les boutons bascule pour vérifier vos valeurs INP pour les dimensions mobiles et desktop.

Ces données sont utiles, car elles vous indiquent si vous avez un problème. En revanche, CrUX ne peut pas vous dire ce qui pose problème. De nombreuses solutions de surveillance des utilisateurs réels (RUM) sont disponibles pour vous aider à collecter vos propres données de champ auprès des utilisateurs de votre site Web. Vous pourrez ainsi répondre à cette question. Vous pouvez également collecter ces données de champ vous-même à l'aide de la bibliothèque JavaScript web-vitals.
Collecter des données de champ avec la bibliothèque JavaScript web-vitals
La bibliothèque JavaScript web-vitals
est un script que vous pouvez charger sur votre site Web pour collecter les données de champ des utilisateurs de votre site Web. Vous pouvez l'utiliser pour enregistrer un certain nombre de métriques, y compris l'INP dans les navigateurs compatibles.
La version standard de la bibliothèque web-vitals peut être utilisée pour obtenir des données INP de base auprès des utilisateurs sur le terrain :
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
console.log(name); // 'INP'
console.log(value); // 512
console.log(rating); // 'poor'
});
Pour analyser les données de champ de vos utilisateurs, vous devez les envoyer quelque part :
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
// Prepare JSON to be sent for collection. Note that
// you can add anything else you'd want to collect here:
const body = JSON.stringify({name, value, rating});
// Use `sendBeacon` to send data to an analytics endpoint.
// For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
navigator.sendBeacon('/analytics', body);
});
Toutefois, ces données ne vous en diront pas beaucoup plus que celles de CrUX. C'est là qu'intervient la version d'attribution de la bibliothèque web-vitals.
Aller plus loin avec la version d'attribution de la bibliothèque web-vitals
La version d'attribution de la bibliothèque web-vitals fournit des données supplémentaires que vous pouvez obtenir auprès des utilisateurs sur le terrain. Elles vous aident à mieux résoudre les problèmes d'interactions qui affectent l'INP de votre site Web. Ces données sont accessibles via l'objet attribution
présenté dans la méthode onINP()
de la bibliothèque :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, rating, attribution}) => {
console.log(name); // 'INP'
console.log(value); // 56
console.log(rating); // 'good'
console.log(attribution); // Attribution data object
});

En plus de l'INP de la page elle-même, la création de l'attribution fournit de nombreuses données que vous pouvez utiliser pour comprendre les raisons des interactions lentes, y compris la partie de l'interaction sur laquelle vous devriez vous concentrer. Elle peut vous aider à répondre à des questions importantes, par exemple :
- "L'utilisateur a-t-il interagi avec la page pendant son chargement ?"
- "Les gestionnaires d'événements de l'interaction ont-ils fonctionné pendant une longue période ?"
- "Le code du gestionnaire d'événements d'interaction a-t-il été retardé ? Si oui, que se passait-il d'autre sur le thread principal à ce moment-là ?"
- "L'interaction a-t-elle entraîné un travail de rendu important qui a retardé l'affichage du frame suivant ?"
Le tableau suivant présente certaines des données d'attribution de base que vous pouvez obtenir à partir de la bibliothèque. Elles peuvent vous aider à identifier certaines causes générales des interactions lentes sur votre site Web :
Clé d'objet attribution
|
Données |
---|---|
interactionTarget
|
Sélecteur CSS pointant vers l'élément qui a généré la valeur INP de la page (par exemple, button#save ).
|
interactionType
|
Type d'interaction (clics, appuis ou saisies au clavier). |
inputDelay *
|
Le délai de réponse à l'entrée de l'interaction. |
processingDuration *
|
Délai écoulé entre le moment où le premier écouteur d'événement a commencé à s'exécuter en réponse à l'interaction de l'utilisateur et le moment où le traitement de tous les écouteurs d'événement est terminé. |
presentationDelay *
|
Le délai de présentation de l'interaction, qui se produit entre la fin des gestionnaires d'événements et le moment où le prochain frame est peint. |
longAnimationFrameEntries *
|
Entrées du LoAF associées à l'interaction. Pour en savoir plus, consultez la section suivante. |
À partir de la version 4 de la bibliothèque web-vitals, vous pouvez obtenir des informations encore plus détaillées sur les interactions problématiques grâce aux données qu'elle fournit avec les détails des phases INP (délai d'entrée, durée de traitement et délai de présentation) et l'API Long Animation Frames (LoAF).
API Long Animation Frames (LoAF)
Le débogage des interactions à l'aide des données de champ est une tâche difficile. Toutefois, grâce aux données de LoAF, il est désormais possible de mieux comprendre les causes des interactions lentes. En effet, LoAF expose un certain nombre de données temporelles détaillées et d'autres données que vous pouvez utiliser pour identifier précisément les causes et, plus important encore, l'emplacement du problème dans le code de votre site Web.
La version de compilation de l'attribution de la bibliothèque web-vitals expose un tableau d'entrées LoAF sous la clé longAnimationFrameEntries
de l'objet attribution
. Le tableau suivant répertorie quelques données clés que vous pouvez trouver dans chaque entrée de la liste des annonces à la une :
Clé d'objet d'entrée LoAF | Données |
---|---|
duration
|
Durée du long frame d'animation, jusqu'à la fin de la mise en page, mais sans inclure la peinture ni la composition. |
blockingDuration
|
Temps total pendant lequel le navigateur n'a pas pu répondre rapidement en raison de tâches longues. Ce temps de blocage peut inclure les tâches longues exécutant JavaScript, ainsi que toute tâche de rendu longue ultérieure dans le frame. |
firstUIEventTimestamp
|
Code temporel indiquant le moment où l'événement a été mis en file d'attente pendant le frame. Utile pour déterminer le début du délai d'entrée d'une interaction. |
startTime
|
Code temporel de début du frame. |
renderStart
|
Date de début du rendu du frame. Cela inclut tous les rappels requestAnimationFrame (et les rappels ResizeObserver , le cas échéant), mais potentiellement avant le début de tout travail de style/mise en page.
|
styleAndLayoutStart
|
Lorsque le style/la mise en page dans le frame sont modifiés. Peut être utile pour déterminer la durée du travail de style/mise en page en tenant compte des autres codes temporels disponibles. |
scripts
|
Tableau d'éléments contenant des informations sur l'attribution de script contribuant à l'INP de la page. |

blockingDuration
).
Toutes ces informations peuvent vous en dire long sur ce qui ralentit une interaction, mais le tableau scripts
que les entrées LoAF font apparaître devrait être particulièrement intéressant :
Clé d'objet d'attribution de script | Données |
---|---|
invoker
|
Demandeur. Cela peut varier en fonction du type d'invocateur décrit dans la ligne suivante. Les valeurs 'IMG#id.onload' , 'Window.requestAnimationFrame' ou 'Response.json.then' sont des exemples d'invocateurs. |
invokerType
|
Type de l'invocateur. Il peut s'agir de 'user-callback' , 'event-listener' , 'resolve-promise' , 'reject-promise' , 'classic-script' ou 'module-script' .
|
sourceURL
|
URL du script à partir duquel provient le long frame d'animation. |
sourceCharPosition
|
Position du caractère dans le script identifié par sourceURL .
|
sourceFunctionName
|
Nom de la fonction dans le script identifié. |
Chaque entrée de ce tableau contient les données affichées dans ce tableau, qui vous fournissent des informations sur le script responsable de l'interaction lente et sur la façon dont il en est responsable.
Mesurer et identifier les causes courantes des interactions lentes
Pour vous donner une idée de la façon dont vous pouvez utiliser ces informations, ce guide vous explique comment utiliser les données LoAF affichées dans la bibliothèque web-vitals
pour déterminer certaines causes des interactions lentes.
Longues durées de traitement
La durée de traitement d'une interaction correspond au temps nécessaire pour que les rappels du gestionnaire d'événements enregistrés de l'interaction s'exécutent jusqu'à la fin, ainsi qu'à tout ce qui peut se produire entre eux. La bibliothèque web-vitals indique les durées de traitement élevées :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
});
Il est naturel de penser que la cause première d'une interaction lente est que le code de votre gestionnaire d'événements a mis trop de temps à s'exécuter, mais ce n'est pas toujours le cas. Une fois que vous avez confirmé que c'était le problème, vous pouvez approfondir l'analyse avec les données LoAF :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
// Get the longest script from LoAF covering `processingDuration`:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Get attribution for the long-running event handler:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Comme vous pouvez le voir dans l'extrait de code précédent, vous pouvez utiliser les données LoAF pour identifier la cause précise d'une interaction avec des valeurs de durée de traitement élevées, y compris :
- L'élément et son écouteur d'événements enregistré.
- Fichier de script (et position du caractère dans celui-ci) contenant le code du gestionnaire d'événements de longue durée.
- Nom de la fonction.
Ce type de données est très utile. Vous n'avez plus besoin de chercher exactement quelle interaction (ou lequel de ses gestionnaires d'événements) était responsable des valeurs de durée de traitement élevées. De plus, comme les scripts tiers peuvent souvent enregistrer leurs propres gestionnaires d'événements, vous pouvez déterminer si votre code était responsable ou non. Pour le code sur lequel vous avez le contrôle, vous devez examiner l'optimisation des tâches longues.
Longs délais de réponse à l'entrée utilisateur
Bien que les gestionnaires d'événements de longue durée soient courants, d'autres aspects de l'interaction doivent être pris en compte. Une partie se produit avant la durée de traitement, ce que l'on appelle le délai d'entrée. Il s'agit du temps qui s'écoule entre le moment où l'utilisateur lance l'interaction et celui où les rappels du gestionnaire d'événements commencent à s'exécuter. Cela se produit lorsque le thread principal traite déjà une autre tâche. La version avec attribution de la bibliothèque web-vitals peut vous indiquer la durée du délai d'entrée pour une interaction :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
});
Si vous remarquez que certaines interactions présentent des temps de latence élevés, vous devez déterminer ce qui se passait sur la page au moment de l'interaction qui a entraîné ce temps de latence élevé. Il s'agit souvent de savoir si l'interaction s'est produite pendant ou après le chargement de la page.
Est-ce pendant le chargement de la page ?
Le thread principal est souvent le plus occupé lors du chargement d'une page. Pendant ce temps, toutes sortes de tâches sont mises en file d'attente et traitées. Si l'utilisateur tente d'interagir avec la page pendant tout ce travail, cela peut retarder l'interaction. Les pages qui chargent beaucoup de code JavaScript peuvent déclencher des tâches de compilation et d'évaluation de scripts, ainsi que l'exécution de fonctions qui préparent une page aux interactions des utilisateurs. Ce travail peut être gênant si l'utilisateur interagit pendant que cette activité se produit. Vous pouvez vérifier si c'est le cas pour les utilisateurs de votre site Web :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
// Invoker types can describe if script eval blocked the main thread:
const {invokerType} = script; // 'classic-script' | 'module-script'
const {sourceLocation} = script; // 'https://example.com/app.js'
}
});
Si vous enregistrez ces données sur le terrain et que vous constatez des délais d'entrée élevés et des types d'invocateur 'classic-script'
ou 'module-script'
, vous pouvez affirmer que les scripts de votre site mettent beaucoup de temps à s'exécuter et bloquent le thread principal suffisamment longtemps pour retarder les interactions. Vous pouvez réduire ce temps de blocage en divisant vos scripts en plus petits bundles, en différant le chargement du code initialement inutilisé à un moment ultérieur et en auditant votre site pour identifier le code inutilisé que vous pouvez supprimer complètement.
Est-ce après le chargement de la page ?
Bien que les délais d'entrée se produisent souvent pendant le chargement d'une page, il est tout à fait possible qu'ils se produisent après le chargement d'une page, pour une raison tout à fait différente. Les causes courantes de retards d'entrée après le chargement de la page peuvent être un code qui s'exécute périodiquement en raison d'un appel setInterval
antérieur, ou même des rappels d'événements qui ont été mis en file d'attente pour s'exécuter plus tôt et qui sont toujours en cours de traitement.
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
// Get the longest script from the first LoAF entry:
const loaf = attribution.longAnimationFrameEntries[0];
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
if (script) {
const {invokerType} = script; // 'user-callback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Comme pour le dépannage des valeurs de durée de traitement élevées, les délais d'entrée élevés dus aux causes mentionnées précédemment vous fourniront des données détaillées sur l'attribution des scripts. Cependant, le type d'invocateur change en fonction de la nature du travail qui a retardé l'interaction :
'user-callback'
indique que la tâche bloquante provenait desetInterval
,setTimeout
ou mêmerequestAnimationFrame
.'event-listener'
indique que la tâche bloquante provenait d'une entrée précédente qui avait été mise en file d'attente et qui était toujours en cours de traitement.'resolve-promise'
et'reject-promise'
signifient que la tâche de blocage provenait d'un travail asynchrone lancé plus tôt, et résolu ou refusé au moment où l'utilisateur a tenté d'interagir avec la page, ce qui a retardé l'interaction.
Dans tous les cas, les données d'attribution de script vous donneront une idée de l'endroit où commencer à chercher et vous indiqueront si le délai d'entrée était dû à votre propre code ou à celui d'un script tiers.
Retards importants de présentation
Les délais de présentation constituent le dernier kilomètre d'une interaction. Ils commencent lorsque les gestionnaires d'événements de l'interaction se terminent et se poursuivent jusqu'à ce que le prochain frame soit peint. Ils se produisent lorsque le travail dans un gestionnaire d'événements en raison d'une interaction modifie l'état visuel de l'interface utilisateur. Comme pour les durées de traitement et les délais d'entrée, la bibliothèque web-vitals peut vous indiquer la durée du délai de présentation pour une interaction :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
});
Si vous enregistrez ces données et que vous constatez des délais de présentation élevés pour les interactions contribuant à l'INP de votre site Web, les causes peuvent varier. Voici toutefois quelques pistes à explorer.
Travaux de style et de mise en page coûteux
Les longs retards de présentation peuvent entraîner des recalculs de style et des mises en page coûteux, qui sont dus à plusieurs causes, y compris des sélecteurs CSS complexes et des DOM de grande taille. Vous pouvez mesurer la durée de ce travail avec les timings LoAF affichés dans la bibliothèque web-vitals :
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get necessary timings:
const {startTime} = loaf; // 2120.5
const {duration} = loaf; // 1002
// Figure out the ending timestamp of the frame (approximate):
const endTime = startTime + duration; // 3122.5
// Get the start timestamp of the frame's style/layout work:
const {styleAndLayoutStart} = loaf; // 3011.17692309
// Calculate the total style/layout duration:
const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691
if (script) {
// Get attribution for the event handler that triggered
// the long-running style and layout operation:
const {invokerType} = script; // 'event-listener'
const {invoker} = script; // 'BUTTON#update.onclick'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
LoAF ne vous indiquera pas la durée du travail de style et de mise en page pour un frame, mais il vous indiquera quand il a commencé. À partir de ce code temporel de début, vous pouvez utiliser d'autres données de LoAF pour calculer la durée exacte de ce travail en déterminant l'heure de fin du frame et en soustrayant le code temporel de début du travail de style et de mise en page.
Rappels requestAnimationFrame
de longue durée
Une cause potentielle des longs retards de présentation est le travail excessif effectué dans un rappel requestAnimationFrame
. Le contenu de ce rappel est exécuté après l'exécution des gestionnaires d'événements, mais juste avant le recalcul du style et le travail de mise en page.
Ces rappels peuvent prendre beaucoup de temps si le travail effectué est complexe. Si vous pensez que les valeurs de délai de présentation élevées sont dues à votre travail avec requestAnimationFrame
, vous pouvez utiliser les données LoAF fournies par la bibliothèque web-vitals pour identifier ces scénarios :
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 543.1999999880791
// Get the longest script from the last LoAF entry:
const loaf = attribution.longAnimationFrameEntries.at(-1);
const script = loaf?.scripts.toSorted((a, b) => b.duration - a.duration)[0];
// Get the render start time and when style and layout began:
const {renderStart} = loaf; // 2489
const {styleAndLayoutStart} = loaf; // 2989.5999999940395
// Calculate the `requestAnimationFrame` callback's duration:
const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954
if (script) {
// Get attribution for the event handler that triggered
// the long-running requestAnimationFrame callback:
const {invokerType} = script; // 'user-callback'
const {invoker} = script; // 'FrameRequestCallback'
const {sourceURL} = script; // 'https://example.com/app.js'
const {sourceCharPosition} = script; // 83
const {sourceFunctionName} = script; // 'update'
}
});
Si vous constatez qu'une partie importante du temps de latence de présentation est consacrée à un rappel requestAnimationFrame
, assurez-vous que le travail que vous effectuez dans ces rappels se limite à celui qui entraîne une mise à jour réelle de l'interface utilisateur. Toute autre tâche qui ne touche pas le DOM ni ne met à jour les styles retardera inutilement l'affichage du prochain frame. Soyez donc prudent !
Conclusion
Les données de terrain sont la meilleure source d'informations pour comprendre quelles interactions posent problème aux utilisateurs réels sur le terrain. En vous appuyant sur des outils de collecte de données sur le terrain tels que la bibliothèque JavaScript web-vitals (ou un fournisseur RUM), vous pouvez identifier plus facilement les interactions les plus problématiques, puis passer à la reproduction des interactions problématiques en laboratoire et les corriger.
Image principale d'Unsplash, par Federico Respini.