Aprenda a encontrar interações lentas nos dados de campo do seu site para identificar oportunidades de melhorar a métrica "Interação com a próxima exibição".
Os dados de campo mostram como os usuários reais estão interagindo com seu site. Ele identifica problemas que não podem ser encontrados apenas nos dados de laboratório. No caso da Interaction to Next Paint (INP), os dados de campo são essenciais para identificar interações lentas e fornecem pistas importantes para ajudar você a corrigir esses problemas.
Neste guia, você vai aprender a avaliar rapidamente o INP do seu site usando dados de campo do Chrome User Experience Report (CrUX) para verificar se há problemas com o INP. Em seguida, você vai aprender a usar o build de atribuição da biblioteca JavaScript web-vitals e os novos insights que ela oferece da API Long Animation Frames (LoAF) para coletar e interpretar dados de campo de interações lentas no seu site.
Comece com a CrUX para avaliar o INP do seu site
Se você não estiver coletando dados de campo dos usuários do seu site, o CrUX pode ser um bom ponto de partida. O CrUX coleta dados de campo de usuários reais do Chrome que ativaram o envio de dados de telemetria.
Os dados da CrUX aparecem em várias áreas diferentes, dependendo do escopo das informações que você está procurando. O CrUX pode fornecer dados sobre INP e outras Core Web Vitals para:
- Páginas individuais e origens inteiras usando o PageSpeed Insights.
- Tipos de páginas. Por exemplo, muitos sites de e-commerce têm os tipos "Página de detalhes do produto" e "Página de listagem de produtos". É possível acessar os dados da CrUX para tipos de página exclusivos no Search Console.
Para começar, insira o URL do seu site no PageSpeed Insights. Depois de inserir o URL, os dados de campo dele, se disponíveis, serão mostrados para várias métricas, incluindo o INP. Você também pode usar os botões de alternância para verificar os valores de INP em dimensões para dispositivos móveis e computadores.

Esses dados são úteis porque informam se há um problema. No entanto, a CrUX não pode informar o que está causando problemas. Há muitas soluções de Real User Monitoring (RUM) disponíveis que ajudam a coletar seus próprios dados de campo dos usuários do site para responder a essa pergunta. Uma opção é coletar esses dados de campo usando a biblioteca JavaScript web-vitals.
Coletar dados de campo com a biblioteca JavaScript web-vitals
A biblioteca JavaScript web-vitals
é um script que você pode carregar no seu site para coletar dados de campo dos usuários. Você pode usar essa API para registrar várias métricas, incluindo INP em navegadores compatíveis.
A build padrão da biblioteca web-vitals pode ser usada para receber dados básicos de INP de usuários no campo:
import {onINP} from 'web-vitals';
onINP(({name, value, rating}) => {
console.log(name); // 'INP'
console.log(value); // 512
console.log(rating); // 'poor'
});
Para analisar os dados de campo dos seus usuários, envie essas informações para algum lugar:
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);
});
No entanto, esses dados por si só não informam muito mais do que a CrUX. É aí que entra a versão de atribuição da biblioteca web-vitals.
Vá mais longe com o build de atribuição da biblioteca web-vitals
O build de atribuição da biblioteca web-vitals mostra outros dados que você pode receber dos usuários no campo para ajudar a resolver melhor interações problemáticas que estão afetando o INP do seu site. Esses dados podem ser acessados pelo objeto attribution
apresentado no método onINP()
da biblioteca:
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
});

Além do INP da página, a criação de atribuição fornece muitos dados que podem ajudar a entender os motivos das interações lentas, incluindo em qual parte da interação você deve se concentrar. Ele pode ajudar você a responder a perguntas importantes, como:
- "O usuário interagiu com a página enquanto ela estava carregando?"
- "Os manipuladores de eventos da interação foram executados por muito tempo?"
- "O código do manipulador de eventos de interação teve o início atrasado? Se sim, o que mais estava acontecendo na linha de execução principal naquele momento?"
- "A interação causou muito trabalho de renderização que atrasou a exibição do próximo frame?"
A tabela a seguir mostra alguns dos dados básicos de atribuição que você pode receber da biblioteca e que ajudam a descobrir algumas causas de alto nível de interações lentas no seu site:
Chave do objeto attribution
|
Dados |
---|---|
interactionTarget
|
Um seletor de CSS que aponta para o elemento que produziu o valor de INP da página, por exemplo, button#save .
|
interactionType
|
O tipo de interação, seja de cliques, toques ou entradas de teclado. |
inputDelay *
|
O atraso na entrada da interação. |
processingDuration *
|
O tempo desde o início da execução do primeiro listener de eventos em resposta à interação do usuário até a conclusão do processamento de todos os listeners de eventos. |
presentationDelay *
|
O atraso de apresentação da interação, que ocorre desde o momento em que os manipuladores de eventos terminam até o momento em que o próximo frame é renderizado. |
longAnimationFrameEntries *
|
Entradas do LoAF associadas à interação. Confira a próxima seção para mais informações. |
A partir da versão 4 da biblioteca web-vitals, você pode ter insights ainda mais detalhados sobre interações problemáticas com os dados fornecidos com detalhamentos da fase INP (atraso de entrada, duração do processamento e atraso de apresentação) e a API Long Animation Frames (LoAF).
API Long Animation Frames (LoAF)
Depurar interações usando dados de campo é uma tarefa difícil. Com os dados do LoAF, agora é possível ter insights melhores sobre as causas das interações lentas. O LoAF expõe vários tempos detalhados e outros dados que podem ser usados para identificar causas precisas e, mais importante, onde está a origem do problema no código do seu site.
A build de atribuição da biblioteca web-vitals expõe uma matriz de entradas LoAF na chave longAnimationFrameEntries
do objeto attribution
. A tabela a seguir lista alguns dados importantes que você pode encontrar em cada entrada de LoAF:
Chave do objeto de entrada LoAF | Dados |
---|---|
duration
|
A duração do frame longo de animação, até a conclusão do layout, mas excluindo pintura e composição. |
blockingDuration
|
O tempo total no frame em que o navegador não conseguiu responder rapidamente devido a tarefas longas. Esse tempo de bloqueio pode incluir tarefas longas que executam JavaScript, bem como qualquer tarefa longa de renderização subsequente no frame. |
firstUIEventTimestamp
|
O carimbo de data/hora de quando o evento foi enfileirado durante o frame. Útil para descobrir o início do atraso de entrada de uma interação. |
startTime
|
O carimbo de data/hora de início do frame. |
renderStart
|
Quando o trabalho de renderização do frame começou. Isso inclui todos os callbacks requestAnimationFrame (e ResizeObserver , se aplicável), mas potencialmente antes do início de qualquer trabalho de estilo/layout.
|
styleAndLayoutStart
|
Quando o estilo/layout funciona no frame. Pode ser útil para descobrir a duração do trabalho de estilo/layout ao considerar outros carimbos de data/hora disponíveis. |
scripts
|
Uma matriz de itens que contém informações de atribuição de script que contribuem para o INP da página. |

blockingDuration
).
Todas essas informações podem dizer muito sobre o que torna uma interação lenta, mas a matriz scripts
que as entradas do LoAF mostram é de interesse especial:
Chave do objeto de atribuição de script | Dados |
---|---|
invoker
|
O invocador. Isso pode variar de acordo com o tipo de invocador descrito na próxima linha. Exemplos de invocadores podem ser valores como 'IMG#id.onload' , 'Window.requestAnimationFrame' ou 'Response.json.then' . |
invokerType
|
O tipo do invocador. Pode ser 'user-callback' , 'event-listener' , 'resolve-promise' , 'reject-promise' , 'classic-script' ou 'module-script' .
|
sourceURL
|
O URL do script em que o frame de animação longa foi originado. |
sourceCharPosition
|
A posição do caractere no script identificado por sourceURL .
|
sourceFunctionName
|
O nome da função no script identificado. |
Cada entrada nessa matriz contém os dados mostrados nesta tabela, que fornece informações sobre o script responsável pela interação lenta e como ele foi responsável.
Medir e identificar causas comuns de interações lentas
Para dar uma ideia de como usar essas informações, este guia vai mostrar como usar os dados do LoAF apresentados na biblioteca web-vitals
para determinar algumas causas de interações lentas.
Longas durações de processamento
A duração do processamento de uma interação é o tempo necessário para que os callbacks do gerenciador de eventos registrados da interação sejam executados até a conclusão e qualquer outra coisa que possa acontecer entre eles. A biblioteca web-vitals mostra durações de processamento longas:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {processingDuration} = attribution; // 512.5
});
É natural pensar que a principal causa de uma interação lenta é que o código do manipulador de eventos demorou muito para ser executado, mas nem sempre é assim. Depois de confirmar que esse é o problema, você pode analisar mais a fundo com os dados de 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'
}
});
Como você pode ver no snippet de código anterior, é possível trabalhar com dados de LoAF para rastrear a causa exata de uma interação com valores de duração de processamento altos, incluindo:
- O elemento e o listener de eventos registrado.
- O arquivo de script e a posição do caractere nele que contém o código do manipulador de eventos de longa duração.
- O nome da função.
Esse tipo de dado é muito valioso. Agora você não precisa mais descobrir exatamente qual interação ou qual dos processadores de eventos dela foi responsável pelos altos valores de duração do processamento. Além disso, como os scripts de terceiros geralmente registram seus próprios manipuladores de eventos, você pode determinar se foi seu código o responsável. Para o código que você controla, confira como otimizar tarefas longas.
Longos atrasos na entrada
Embora os manipuladores de eventos de longa duração sejam comuns, há outras partes da interação a serem consideradas. Uma parte ocorre antes da duração do processamento, que é conhecida como atraso de entrada. É o tempo decorrido entre o momento em que o usuário inicia a interação e o momento em que os callbacks do manipulador de eventos começam a ser executados. Isso acontece quando a linha de execução principal já está processando outra tarefa. A criação de atribuição da biblioteca web-vitals pode informar a duração do atraso de entrada de uma interação:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {inputDelay} = attribution; // 125.59439536
});
Se você notar que algumas interações têm atrasos de entrada altos, será necessário descobrir o que estava acontecendo na página no momento da interação que causou o atraso longo. Isso geralmente se resume a saber se a interação ocorreu durante ou após o carregamento da página.
Foi durante o carregamento da página?
A linha de execução principal costuma ficar mais ocupada quando uma página está sendo carregada. Durante esse período, todos os tipos de tarefas são enfileirados e processados. Se o usuário tentar interagir com a página enquanto todo esse trabalho está sendo feito, a interação pode ser atrasada. Páginas que carregam muito JavaScript podem iniciar o trabalho de compilação e avaliação de scripts, além de executar funções que preparam uma página para interações do usuário. Esse trabalho pode atrapalhar se o usuário interagir enquanto essa atividade ocorre. Para saber se esse é o caso dos usuários do seu site:
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'
}
});
Se você registrar esses dados no campo e notar atrasos de entrada altos e tipos de invocador 'classic-script'
ou 'module-script'
, é justo dizer que os scripts no seu site estão demorando muito para serem avaliados e bloqueando a linha de execução principal por tempo suficiente para atrasar as interações. Para reduzir esse tempo de bloqueio, divida os scripts em pacotes menores, adie o carregamento do código inicialmente não utilizado para um momento posterior e audite seu site para remover o código não utilizado.
Foi depois do carregamento da página?
Embora os atrasos de entrada geralmente ocorram durante o carregamento de uma página, também é possível que eles aconteçam depois que uma página é carregada, por um motivo totalmente diferente. Causas comuns de atrasos de entrada após o carregamento da página podem ser código executado periodicamente devido a uma chamada setInterval
anterior ou até mesmo callbacks de eventos que foram enfileirados para serem executados antes e ainda estão sendo processados.
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'
}
});
Assim como acontece com a solução de problemas de valores altos de duração do processamento, atrasos de entrada altos devido às causas mencionadas anteriormente fornecem dados detalhados de atribuição de script. No entanto, o que muda é que o tipo de invocador vai variar de acordo com a natureza do trabalho que atrasou a interação:
'user-callback'
indica se a tarefa de bloqueio era desetInterval
,setTimeout
ou até mesmorequestAnimationFrame
.'event-listener'
indica que a tarefa de bloqueio era de uma entrada anterior que foi enfileirada e ainda está sendo processada.'resolve-promise'
e'reject-promise'
significam que a tarefa de bloqueio era de algum trabalho assíncrono iniciado anteriormente e resolvido ou rejeitado quando o usuário tentou interagir com a página, atrasando a interação.
Em qualquer caso, os dados de atribuição de script vão dar uma ideia de onde começar a procurar e se o atraso de entrada foi devido ao seu próprio código ou ao de um script de terceiros.
Atrasos longos na apresentação
Os atrasos na apresentação são a última etapa de uma interação e começam quando os manipuladores de eventos da interação terminam, até o ponto em que o próximo frame é renderizado. Elas ocorrem quando o trabalho em um manipulador de eventos devido a uma interação muda o estado visual da interface do usuário. Assim como com durações de processamento e atrasos de entrada, a biblioteca web-vitals pode informar quanto tempo durou o atraso de apresentação de uma interação:
import {onINP} from 'web-vitals/attribution';
onINP(({name, value, attribution}) => {
const {presentationDelay} = attribution; // 113.32307691
});
Se você registrar esses dados e notar atrasos altos na apresentação de interações que contribuem para o INP do seu site, os culpados podem variar. No entanto, confira algumas causas que podem estar relacionadas.
Trabalho caro de estilo e layout
Atrasos longos na apresentação podem ser recálculos de estilo e layout caros, que surgem por vários motivos, incluindo seletores de CSS complexos e tamanhos grandes do DOM. Você pode medir a duração desse trabalho com os tempos de LoAF exibidos na biblioteca 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'
}
});
O LoAF não informa a duração do trabalho de estilo e layout de um frame, mas informa quando ele começou. Com esse carimbo de data/hora inicial, você pode usar outros dados do LoAF para calcular uma duração precisa desse trabalho, determinando o horário de término do frame e subtraindo o carimbo de data/hora inicial do trabalho de estilo e layout.
Callbacks de longa duração requestAnimationFrame
Uma possível causa de longos atrasos na apresentação é o trabalho excessivo feito em um callback requestAnimationFrame
. O conteúdo desse callback é executado depois que os manipuladores de eventos terminam de ser executados, mas antes do recálculo de estilo e do trabalho de layout.
Esses callbacks podem levar um tempo considerável para serem concluídos se o trabalho realizado neles for complexo. Se você suspeitar que os valores altos de atraso na apresentação são devido ao trabalho que está fazendo com requestAnimationFrame
, use os dados de LoAF apresentados pela biblioteca web-vitals para identificar esses cenários:
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'
}
});
Se você notar que uma parte significativa do tempo de atraso da apresentação é gasto em um callback requestAnimationFrame
, limite o trabalho realizado nesses callbacks à execução de tarefas que resultem em uma atualização real da interface do usuário. Qualquer outro trabalho que não toque no DOM ou atualize estilos vai atrasar desnecessariamente a renderização do próximo frame. Portanto, tenha cuidado!
Conclusão
Os dados de campo são a melhor fonte de informações para entender quais interações são problemáticas para usuários reais no campo. Ao usar ferramentas de coleta de dados de campo, como a biblioteca JavaScript web-vitals (ou um provedor de RUM), você pode ter mais confiança sobre quais interações são mais problemáticas e, em seguida, reproduzir interações problemáticas no laboratório e corrigi-las.
Imagem principal do Unsplash, de Federico Respini.