Voltar ao blog

Soft Navigations: Medindo a Performance de SPAs do Jeito do Navegador

As heurísticas de soft navigation do Chrome finalmente permitem que os Core Web Vitals acompanhem mudanças de rota no cliente. Veja como a API funciona e como medi-la sem vigilância.

Por uma década, os Core Web Vitals descreviam apenas a primeira página que o visitante carregava. Toda mudança de rota depois disso em uma single-page application ficava invisível para as métricas. O experimento de soft navigations do Chrome fecha essa lacuna, e isso muda a forma como uma analytics focada em privacidade deve medir a performance real do usuário.

O ponto cego que as soft navigations resolvem

Uma hard navigation tradicional descarrega o documento e carrega outro. O navegador reinicia sua linha do tempo de performance, dispara um novo LCP e começa a contar CLS e INP do zero. Ferramentas de campo como o CrUX atribuem tudo àquela única URL.

SPAs não funcionam assim. Após o carregamento inicial, o React Router, o App Router do Next.js ou o SvelteKit trocam o conteúdo no lugar usando a History API. Nenhum documento é descarregado, então nenhuma nova linha do tempo de performance começa. Um usuário pode navegar por dez "páginas" enquanto cada Core Web Vital permanece preso à URL de entrada.

O resultado é conhecido por qualquer um que já auditou uma SPA: a rota inicial parece rápida, e as interações lentas no fundo do app nunca aparecem nos dados.

Como o Chrome detecta uma soft navigation

A heurística do Chrome exige que três coisas aconteçam em ordem antes de registrar uma soft navigation:

  1. A navegação é iniciada por uma interação do usuário — um clique ou pressionar de tecla.
  2. A URL é modificada pela History API ou pela Navigation API.
  3. Uma modificação no DOM segue a interação, alterando um elemento do DOM que já existia.

Essa sequência é deliberadamente rígida. Um pushState em segundo plano para analytics, um carrossel que avança sozinho ou uma mudança de URL sem interação não se qualificam. Essa precisão importa: significa que uma soft navigation mapeia para algo que um humano de fato fez, e não para atividade incidental de script.

A superfície da API

As soft navigations aparecem pelo PerformanceObserver padrão usando um tipo de entrada dedicado. Você habilita por observer:

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log(entry.name, entry.startTime);
  }
}).observe({ type: "soft-navigation", buffered: true });

Mais importante: outras entradas de performance ganham um navigationId. Entradas de LCP, layout-shift e event-timing emitidas após uma soft navigation carregam o novo ID, então você pode reatribuir cada Core Web Vital à rota em que o usuário realmente estava:

new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // entry.navigationId liga este LCP a uma soft navigation específica
    send({ metric: "LCP", value: entry.startTime, navId: entry.navigationId });
  }
}).observe({ type: "largest-contentful-paint", buffered: true });

Hoje isso vive atrás de chrome://flags/#soft-navigation-heuristics e de um origin trial, com exposição limitada no CrUX. Ainda não é padrão no Chrome estável, então trate os números de campo como direcionais, não autoritativos. A biblioteca web-vitals expõe os mesmos dados pela opção reportSoftNavs, que é a forma prática de conectar tudo sem escrever observers à mão.

Por que isso pertence a uma analytics focada em privacidade

Os dados de soft navigation são puro timing. Não contêm identificador, nem cookie, nem nada que sobreviva à sessão da página — uma duração, um tipo de elemento aproximado, um caminho de rota. É exatamente o tipo de sinal que uma ferramenta sem cookies pode coletar sem mexer na maquinaria de consentimento.

O tracker já engancha o history.pushState para contar mudanças de rota em SPAs. As soft navigations refinam esse mesmo gancho: em vez de perguntar apenas a rota mudou?, você pode perguntar isso foi uma navegação movida por interação, e como ela performou?. As entradas de performance viajam junto com o beacon de pageview existente para /collect, adicionando medição de campo sem adicionar peso ao script de menos de 2 KB e sem quebrar o modelo de identidade por hash diário.

A armadilha a evitar é tratar as soft navigations como motivo para coletar mais. Alguns fornecedores de RUM vão usar a nova atribuição para costurar jornadas de navegação por usuário ao longo de uma sessão — exatamente o padrão de vigilância que a analytics sem cookies existe para rejeitar. A métrica é valiosa justamente porque pode permanecer agregada: INP mediano por rota, distribuição de LCP por rota, sem caminho de volta a uma pessoa.

As soft navigations tornam as partes mais profundas e lentas do seu app mensuráveis pela primeira vez. Colete o timing, descarte o resto, e você obtém o retrato de performance sem o perfil.