Depurar o desempenho no campo

Saiba como atribuir seus dados de performance com informações de depuração para ajudar a identificar e corrigir problemas de usuários reais com a análise.

O Google oferece duas categorias de ferramentas para medir e depurar a performance:

  • Ferramentas de laboratório:ferramentas como o Lighthouse, em que a página é carregada em um ambiente simulado que pode imitar várias condições (por exemplo, uma rede lenta e um dispositivo móvel de baixo custo).
  • Ferramentas de campo:ferramentas como o Chrome User Experience Report (CrUX), que se baseia em dados agregados de usuários reais do Chrome. Os dados de campo informados por ferramentas como PageSpeed Insights e Search Console são provenientes do CrUX.

Embora as ferramentas de campo ofereçam dados mais precisos, que representam o que os usuários reais vivenciam, as ferramentas de laboratório geralmente são melhores para ajudar a identificar e corrigir problemas.

Os dados do CrUX são mais representativos da performance real da sua página, mas saber as pontuações do CrUX provavelmente não vai ajudar você a descobrir como melhorar a performance.

O Lighthouse, por outro lado, identifica problemas e faz sugestões específicas de melhoria. No entanto, o Lighthouse só faz sugestões para problemas de desempenho descobertos durante o tempo de carregamento da página. Ele não detecta problemas que só se manifestam como resultado da interação do usuário, como rolar ou clicar em botões na página.

Isso levanta uma questão importante: como capturar informações de depuração para Core Web Vitals ou outras métricas de performance de usuários reais no campo?

Nesta postagem, explicamos em detalhes quais APIs você pode usar para coletar mais informações de depuração para cada uma das métricas atuais das Core Web Vitals e damos ideias de como capturar esses dados na sua ferramenta de análise atual.

APIs para atribuição e depuração

Cumulative Layout Shift (CLS)

De todas as métricas das Core Web Vitals, a CLS é talvez aquela em que a coleta de informações de depuração no campo é mais importante. O CLS é medido durante todo o ciclo de vida da página. Portanto, a forma como um usuário interage com ela (até onde ele rola, em que clica etc.) pode ter um impacto significativo na ocorrência de mudanças de layout e em quais elementos estão mudando.

Considere o seguinte relatório do PageSpeed Insights:

Um relatório do PageSpeed Insights com diferentes valores de CLS
O PageSpeed Insights mostra dados de campo e de laboratório quando disponíveis, e eles podem ser diferentes

O valor informado para CLS do laboratório (Lighthouse) em comparação com o CLS do campo (dados do CrUX) é bastante diferente. Isso faz sentido se você considerar que a página pode ter muito conteúdo interativo que não está sendo usado quando testado no Lighthouse.

Mas mesmo que você entenda que a interação do usuário afeta os dados de campo, ainda precisa saber quais elementos da página estão mudando para resultar em uma pontuação de 0,28 no 75º percentil. A interface LayoutShiftAttribution torna isso possível.

Receber atribuição de troca de layout

A interface LayoutShiftAttribution é exposta em cada entrada layout-shift emitida pela API Layout Instability.

Para uma explicação detalhada das duas interfaces, consulte Depurar mudanças de layout. Para fins deste post, o mais importante é saber que, como desenvolvedor, você pode observar todas as mudanças de layout que acontecem na página, bem como os elementos que estão mudando.

Confira um exemplo de código que registra cada mudança de layout, bem como os elementos que foram movidos:

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});

Provavelmente não é prático medir e enviar dados para sua ferramenta de análise de cada mudança de layout que ocorre. No entanto, ao monitorar todas as mudanças, você pode acompanhar as piores e informar apenas sobre elas.

O objetivo não é identificar e corrigir todas as mudanças de layout que ocorrem para cada usuário, mas sim identificar as mudanças que afetam o maior número de usuários e, portanto, contribuem mais para a CLS da página no 75º percentil.

Além disso, não é necessário calcular o maior elemento de origem sempre que houver uma mudança. Isso só precisa ser feito quando você estiver pronto para enviar o valor de CLS à sua ferramenta de análise.

O código a seguir usa uma lista de entradas layout-shift que contribuíram para a CLS e retorna o maior elemento de origem da maior mudança:

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;
    }
  }
}

Depois de identificar o maior elemento que contribui para a maior mudança, você pode informar isso à sua ferramenta de análise.

O elemento que mais contribui para a CLS de uma determinada página provavelmente varia de usuário para usuário, mas, se você agregar esses elementos em todos os usuários, poderá gerar uma lista de elementos instáveis que afetam o maior número de usuários.

Depois de identificar e corrigir a causa raiz das mudanças nesses elementos, seu código de análise vai começar a informar mudanças menores como as "piores" para suas páginas. Com o tempo, todas as mudanças informadas serão pequenas o suficiente para que suas páginas fiquem bem dentro do limiar "bom" de 0,1.

Outros metadados que podem ser úteis para capturar junto com o maior elemento de origem de mudança são:

  • O momento da maior mudança
  • O caminho do URL no momento da maior mudança (para sites que atualizam o URL de forma dinâmica, como aplicativos de página única).

Maior exibição de conteúdo (LCP)

Para depurar a LCP no campo, a principal informação necessária é qual elemento específico foi o maior (o elemento candidato da LCP) para aquele carregamento de página específico.

É totalmente possível, e até comum, que o elemento candidato a LCP seja diferente de usuário para usuário, mesmo na mesma página.

Esse problema pode ocorrer por vários motivos:

  • Os dispositivos dos usuários têm resoluções de tela diferentes, o que resulta em layouts de página diferentes e, portanto, elementos diferentes visíveis na janela de visualização.
  • Os usuários nem sempre carregam páginas roladas até o topo. Muitas vezes, os links contêm identificadores de fragmentos ou até mesmo fragmentos de texto. Isso significa que é possível carregar e mostrar suas páginas em qualquer posição de rolagem.
  • O conteúdo pode ser personalizado para o usuário atual, então o elemento candidato a LCP pode variar muito de usuário para usuário.

Isso significa que não é possível presumir qual elemento ou conjunto de elementos será o candidato a LCP mais comum para uma página específica. Você precisa medir com base no comportamento real do usuário.

Identificar o elemento candidato a LCP

Para determinar o elemento candidato a LCP em JavaScript, use a API Largest Contentful Paint, a mesma que você usa para determinar o valor de tempo do LCP.

Ao observar entradas largest-contentful-paint, é possível determinar o elemento candidato a LCP atual analisando a propriedade element da última entrada:

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});

Depois de identificar o elemento candidato a LCP, envie-o para sua ferramenta de análise com o valor da métrica. Assim como acontece com o CLS, isso ajuda a identificar quais elementos são mais importantes para otimizar primeiro.

Além do elemento candidato a LCP, também pode ser útil medir os tempos de subparte da LCP, que podem ajudar a determinar quais etapas de otimização específicas são relevantes para seu site.

Interaction to Next Paint (INP)

As informações mais importantes a serem capturadas no campo para INP são:

  1. Com qual elemento houve interação
  2. Por que tipo de interação foi
  3. Quando essa interação ocorreu

Uma das principais causas de interações lentas é o bloqueio da linha de execução principal, o que pode ser comum durante o carregamento do JavaScript. Saber se a maioria das interações lentas ocorre durante o carregamento de página ajuda a determinar o que precisa ser feito para corrigir o problema.

A métrica INP considera a latência total de uma interação, incluindo o tempo necessário para executar todos os listeners de eventos registrados, bem como o tempo necessário para renderizar o próximo frame depois que todos os listeners de eventos forem executados. Isso significa que, para a INP, é muito útil saber quais elementos de destino tendem a resultar em interações lentas e quais tipos de interações são essas.

O código abaixo registra o elemento de destino e o tempo da entrada INP.

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

Este código não mostra como determinar qual entrada de event é a entrada INP, já que essa lógica é mais complexa. No entanto, a seção a seguir explica como receber essas informações usando a biblioteca JavaScript web-vitals.

Uso com a biblioteca JavaScript web-vitals

As seções anteriores oferecem algumas sugestões gerais e exemplos de código para capturar informações de depuração e incluir nos dados enviados à sua ferramenta de análise.

Desde a versão 3, a biblioteca JavaScript web-vitals inclui um build de atribuição que mostra todas essas informações, além de alguns outros indicadores.

O exemplo de código a seguir mostra como definir um parâmetro de evento (ou uma dimensão personalizada) adicional que contém uma string de depuração útil para ajudar a identificar a causa principal dos problemas de desempenho.

import {onCLS, 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 'INP':
      eventParams.debug_target = attribution.interactionTarget;
      break;
  }

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

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

Esse código é específico do Google Analytics, mas a ideia geral também se aplica a outras ferramentas de análise.

Esse código também mostra como gerar relatórios sobre um único indicador de depuração, mas é útil coletar e gerar relatórios sobre vários indicadores diferentes por métrica.

Por exemplo, para depurar o INP, talvez seja necessário coletar o elemento com que o usuário está interagindo, o tipo de interação, o tempo, o loadState, as fases da interação e mais (como dados de frame de animação longa).

A build de atribuição web-vitals expõe mais informações de atribuição, como mostrado no exemplo a seguir para INP:

import {onCLS, 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.interactionTarget;
      eventParams.debug_type = attribution.interactionType;
      eventParams.debug_time = attribution.interactionTime;
      eventParams.debug_load_state = attribution.loadState;
      eventParams.debug_interaction_delay = Math.round(attribution.inputDelay);
      eventParams.debug_processing_duration = Math.round(attribution.processingDuration);
      eventParams.debug_presentation_delay =  Math.round(attribution.presentationDelay);
      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);
onINP(sendToGoogleAnalytics);

Consulte a documentação de atribuição do web-vitals para conferir a lista completa de indicadores de depuração expostos.

Gerar relatórios e visualizar os dados

Depois de começar a coletar informações de depuração com os valores das métricas, a próxima etapa é agregar os dados de todos os usuários para começar a procurar padrões e tendências.

Como mencionado anteriormente, não é necessário resolver todos os problemas que os usuários estão enfrentando. No início, é melhor focar nos que afetam o maior número de pessoas e têm o maior impacto negativo nas suas pontuações de Core Web Vitals.

Para o GA4, consulte o artigo dedicado sobre como consultar e visualizar os dados usando o BigQuery.

Resumo

Esperamos que esta postagem tenha ajudado a descrever as maneiras específicas de usar as APIs de performance atuais e a biblioteca web-vitals para receber informações de depuração que ajudam a diagnosticar a performance com base nas visitas de usuários reais no campo. Embora este guia se concentre nas Core Web Vitals, os conceitos também se aplicam à depuração de qualquer métrica de performance mensurável em JavaScript.

Se você é um fornecedor de análises e quer melhorar seus produtos e fornecer mais informações de depuração aos usuários, considere algumas das técnicas descritas aqui, mas não se limite apenas às ideias apresentadas. Esta postagem foi criada para ser aplicável a todas as ferramentas de análise. No entanto, cada uma delas provavelmente pode (e deve) capturar e gerar relatórios com ainda mais informações de depuração.

Por fim, se você achar que há lacunas na sua capacidade de depurar essas métricas devido a recursos ou informações ausentes nas próprias APIs, envie seu feedback para web-vitals-feedback@googlegroups.com.