← Todos os artigos

Blog

Rastreamento de Conversão em SPA: Por Que Suas Tags Quebram em React, Next.js e Vue

rastreamento de conversão sparastreamento de conversão reactrastreamento single page apprastreamento de conversão next.js

"A tag funciona em todas as outras páginas — mas na tela de agradecimento, nada dispara." Se o seu site é construído com React, Next.js, Vue ou qualquer outro framework SPA, essa é uma das falhas de rastreamento de conversão mais comuns. E ela é invisível no preview do seu gerenciador de tags, porque o preview funciona de forma diferente da navegação real do usuário.

A causa raiz é simples: SPAs não fazem carregamentos reais de página. O navegador carrega o shell uma única vez, e cada "página" subsequente é uma troca de DOM controlada por JavaScript. Tags que dependem do carregamento de página — que é a maioria delas — nunca percebem que a navegação aconteceu.

Este guia explica por que o rastreamento em SPAs quebra, como corrigir isso para cada framework principal, e como verificar se está funcionando em produção.

1. Por que o disparo tradicional de tags não funciona em SPAs

Em um site multi-página tradicional, cada navegação dispara um carregamento completo de página no navegador. O sistema de gerenciamento de tags (GTM, gtag hardcoded, Meta Pixel, etc.) dispara a cada evento DOMContentLoaded ou window.onload. Uma tag configurada para disparar em "Todas as Páginas" literalmente dispara em todas as páginas.

Em uma SPA:

Site multi-página SPA
Clica em um link → navegador solicita novo HTML → carregamento completo de página Clica em um link → JavaScript troca o DOM → URL muda via History API
Cada página dispara DOMContentLoaded DOMContentLoaded dispara uma única vez (apenas no carregamento inicial)
Trigger "Todas as Páginas" do GTM dispara em cada navegação Trigger "Todas as Páginas" do GTM dispara apenas no primeiro carregamento
Tag de conversão em /thank-you dispara quando a página carrega Tag de conversão em /thank-you nunca dispara (nenhum carregamento de página ocorre)

Isso significa que uma tag de conversão configurada para disparar "quando a página de agradecimento carregar" dispara exatamente zero vezes — porque a página de agradecimento nunca "carrega" no sentido que o navegador entende. O usuário navega até lá, a URL muda, o conteúdo aparece, mas nenhum evento de carregamento de página ocorre.

2. As três abordagens para corrigir isso

Abordagem A: Enviar um pageview virtual para a data layer

O método mais confiável para configurações baseadas em GTM. Quando a rota da SPA muda, envie um evento para a data layer. Os triggers do GTM disparam nesse evento em vez do trigger nativo "Page View".

// A cada mudança de rota, envie para o dataLayer
dataLayer.push({
  event: 'virtual_pageview',
  page_path: '/thank-you',
  page_title: 'Thank You'
});

No GTM:

  1. Crie um trigger de Evento Personalizado com o nome de evento virtual_pageview
  2. Configure suas tags de conversão para disparar nesse trigger, com uma condição em page_path (ex.: page_path equals /thank-you)

Essa abordagem separa a decisão de "quando disparar" do framework — o código da sua aplicação envia o evento, e o GTM cuida da lógica das tags.

Abordagem B: Usar o trigger History Change do GTM

O GTM tem um trigger nativo chamado "History Change" que dispara sempre que a History API do navegador é usada (que é como as SPAs mudam a URL). Isso pode funcionar sem nenhuma alteração de código na sua aplicação.

Configuração:

  1. No GTM, crie um trigger do tipo History Change
  2. Adicione condições baseadas em {{Page Path}} (ex.: Page Path equals /thank-you)
  3. Vincule suas tags de conversão a esse trigger

Ressalva: O trigger History Change dispara em toda mudança de URL, incluindo navegação de voltar/avançar. Sem condições bem pensadas, sua tag de conversão pode disparar quando um usuário navega de volta passando pela página de agradecimento sem realmente converter de novo. Essa é uma causa comum de conversões duplicadas em SPAs. Se suas tags do GTM não estão disparando de forma alguma, veja por que as tags do GTM às vezes não rastreiam para uma solução de problemas mais ampla.

Abordagem C: Disparar a tag diretamente no código da aplicação

Para tags hardcoded (sem usar o GTM), chame a função de rastreamento diretamente no seu componente ou route handler.

// React: dispara no useEffect quando o componente monta
useEffect(() => {
  gtag('event', 'conversion', {
    'send_to': 'AW-XXXXXXX/YYYYYYY',
    'value': 100,
    'currency': 'USD'
  });
}, []);
// Next.js App Router: dispara em um client component na página de agradecimento
'use client'
import { useEffect } from 'react'

export default function ThankYou() {
  useEffect(() => {
    gtag('event', 'conversion', {
      'send_to': 'AW-XXXXXXX/YYYYYYY',
      'value': 100,
      'currency': 'USD'
    });
  }, []);

  return <h1>Obrigado pela sua compra</h1>
}

Vantagem: Sem a complexidade do GTM; a conversão dispara exatamente quando e onde você quer.

Risco: Misturar código de rastreamento com código de aplicação pode dificultar a manutenção. Se você tem muitas tags em muitas páginas, o GTM geralmente é mais fácil de manter.

Suporte nativo do GA4 para SPAs (Enhanced Measurement)

Antes de construir um rastreamento de SPA personalizado, verifique se o recurso nativo do GA4 já cobre suas necessidades. O GA4 tem a opção "Page changes based on browser history events" no Enhanced Measurement:

Para ativar: Admin → Data Streams → Web → Enhanced Measurement → Page Views → Show advanced settings → ative "Page changes based on browser history events."

Quando ativado, o GA4 dispara automaticamente um evento page_view sempre que a History API do navegador atualiza a URL — exatamente o que acontece em SPAs. Isso funciona sem nenhuma alteração de código ou configuração no GTM.

Aviso crítico: não conte em dobro. Se você usa o GTM para enviar eventos page_view nas mudanças de rota E também tem essa configuração do GA4 ativada, cada navegação da SPA é contada duas vezes. Escolha um: ou o Enhanced Measurement do GA4 cuida dos pageviews automaticamente, ou a sua configuração no GTM cuida — não ambos. Essa é uma das configurações incorretas mais comuns no rastreamento de SPAs.

Limitação: Isso cuida do rastreamento de pageview, não do rastreamento de eventos de conversão. Você ainda precisa disparar eventos específicos de conversão (purchase, sign_up, etc.) via GTM ou código da aplicação no momento certo.

3. Pegadinhas específicas de cada framework

React (Create React App, Vite)

  • O problema: O React Router muda a URL via History API. Nenhum carregamento de página dispara.
  • Correção: Use useEffect no componente de destino, ou escute as mudanças de rota no seu router e envie para a data layer.
  • Cuidado: useEffect executa depois da renderização, o que significa que a conversão dispara um pouco depois da atualização do DOM. Isso geralmente não é problema, mas se o usuário navegar para outro lugar muito rapidamente (ex.: um redirecionamento instantâneo), a tag pode não completar o disparo.

Next.js

  • App Router: Páginas podem ser renderizadas no servidor (RSC) ou no cliente. Tags de conversão precisam rodar no cliente. Use um componente 'use client' com useEffect, ou use o componente next/script com a estratégia afterInteractive.
  • Pages Router: Use a API router.events para escutar routeChangeComplete e enviar para a data layer.
  • Static export vs. servidor: Se você está usando output: 'export', o comportamento é semelhante ao de uma SPA padrão. Se você está usando renderização no servidor, os carregamentos iniciais de página disparam as tags normalmente — apenas as navegações do lado cliente são afetadas.
  • Cuidado: O Next.js faz prefetch de links. O prefetch não dispara uma mudança de rota, mas se sua tag disparar no evento errado, atividade de DOM relacionada ao prefetch pode causar disparos fantasma.

Vue (Nuxt)

  • Vue Router: Escute router.afterEach() para enviar pageviews virtuais para a data layer.
  • Nuxt: Use o hook page:finish ou um plugin que dispare nas mudanças de rota.
  • Cuidado: O sistema de transições do Vue pode atrasar as atualizações do DOM. Se sua tag verificar a existência de um elemento do DOM na página de destino, ele pode ainda não existir quando o evento de mudança de rota disparar.

Angular

  • Angular Router: Inscreva-se em Router.events e filtre por eventos NavigationEnd. Envie para a data layer a cada NavigationEnd.
  • Cuidado: O Zone.js do Angular pode interferir em scripts de terceiros. Se uma tag carrega de forma assíncrona e roda fora da zona do Angular, ela pode se comportar de forma imprevisível.

4. A armadilha da conversão duplicada

SPAs tornam conversões duplicadas mais prováveis do que sites multi-página, por dois motivos:

  1. Navegação por histórico: Um usuário completa uma compra, chega em /thank-you, depois pressiona o botão de voltar e o de avançar — o trigger History Change dispara novamente, e a conversão é contada duas vezes.

  2. Remontagem de componente: No React, se o componente da página de agradecimento desmontar e remontar (por causa de uma nova renderização do componente pai ou uma oscilação de rota), o useEffect executa novamente e dispara a tag uma segunda vez.

Correções:

  • Use uma flag de disparo único: defina uma variável (session storage, um React ref, ou uma variável da data layer) depois do primeiro disparo, e verifique-a antes de disparar de novo
  • No GTM, use a opção "trigger dispara uma vez por página" — mas note que, em uma SPA, "por página" significa por carregamento inicial de página, não por mudança de rota
  • Deduplique do lado da plataforma: use o parâmetro transaction_id (Google Ads) ou eventID (Meta) para deixar a plataforma ignorar sinais duplicados

5. Higiene da data layer entre navegações de SPA

Em um site multi-página, cada navegação reseta a data layer — ela começa do zero a cada carregamento de página. Em uma SPA, a data layer persiste entre as mudanças de rota. Isso cria um problema sutil, mas prejudicial: valores obsoletos de uma página anterior contaminam eventos na página atual.

Como valores obsoletos geram dados de conversão errados

Um usuário visualiza o Produto A (R$ 199), adiciona ao carrinho, depois navega para o Produto B (R$ 49) e compra. Se a data layer ainda mantiver os valores do Produto A quando o evento de compra disparar, a conversão pode reportar R$ 199 em vez de R$ 49 — ou pior, incluir os dados de item do Produto A junto com os do Produto B.

A correção: limpar antes de cada pageview virtual

Reinicie as variáveis relevantes da data layer a cada mudança de rota, antes de enviar o novo pageview:

// Na mudança de rota — limpa, depois envia
dataLayer.push({
  event: 'spa_cleanup',
  ecommerce: null  // limpa os dados de ecommerce do GA4
});

dataLayer.push({
  event: 'spa_pageview',
  spa_page_path: newPath,
  spa_page_title: newTitle
});

Definir ecommerce: null é especificamente recomendado pelo Google para limpar dados obsoletos de ecommerce entre eventos (veja nosso guia sobre eventos de compra ecommerce do GA4 para a estrutura completa da data layer). Para variáveis que não são de ecommerce, defina-as explicitamente como undefined ou envie um novo objeto que sobrescreva os valores anteriores.

O que observar

  • O transaction_id de uma compra anterior persistindo — faz o próximo evento carregar um transaction_id antigo, o que pode deduplicar uma conversão nova e real
  • Incompatibilidade de moeda — um usuário navegando em um produto em USD e depois trocando para um produto em JPY; se a currency não for reenviada, o valor antigo persiste
  • Versão da variável de Data Layer do GTM — variáveis da Versão 1 persistem até serem explicitamente limpas; variáveis da Versão 2 têm escopo de evento, mas ainda podem vazar se lidas no momento errado

6. Como verificar o rastreamento de conversão em SPA

Passo 1: Verifique com a aba Network do DevTools

Navegue até a página de conversão dentro da SPA (não recarregue — navegue a partir de outra página). Na aba Network, filtre pela requisição de conversão:

  • Google Ads: googleadservices.com/pagead/conversion/
  • GA4: google-analytics.com/g/collect
  • Meta: facebook.com/tr

Se a requisição aparecer após a navegação, a tag está disparando corretamente. Se ela só aparecer em um recarregamento completo de página, a tag está configurada apenas para carregamento de página e não está capturando a navegação da SPA.

Passo 2: Teste o cenário do botão voltar

Depois de disparar a conversão, pressione o botão voltar, depois o botão avançar. Verifique a aba Network novamente — a requisição de conversão disparou uma segunda vez? Se sim, você tem um problema de conversão duplicada.

Passo 3: Limitações do modo Preview do GTM

O modo Preview do GTM pode ser pouco confiável para testar SPAs. O painel de Preview às vezes mostra tags como "disparadas" mesmo quando a requisição de rede real não saiu, ou pode não refletir corretamente os eventos History Change. Sempre faça uma checagem cruzada com a aba Network, não apenas com o GTM Preview.

Passo 4: Teste em um ambiente limpo

SPAs podem se comportar de forma diferente dependendo de:

  • Se a página foi acessada por entrada direta de URL (carregamento completo de página) vs. navegação interna (mudança de rota da SPA)
  • Se service workers estão fazendo cache da página
  • Se o usuário tem bloqueadores de anúncios que interferem na tag

Teste ambos os caminhos: um carregamento direto por URL da página de agradecimento, e uma navegação até ela de dentro da aplicação.

7. Server-side tagging para SPAs

SPAs são particularmente vulneráveis a falhas de rastreamento no lado cliente: bloqueadores de anúncios interceptam requisições para googleadservices.com, facebook.com/tr e outros endpoints de rastreamento; plataformas de gerenciamento de consentimento podem bloquear tags antes que disparem; e JavaScript pesado do lado cliente pode atrasar ou impedir a execução das tags.

O Google Tag Manager server-side (sGTM) resolve esses problemas roteando as requisições de rastreamento através do seu próprio domínio:

Problema Apenas client-side Com GTM server-side
Bloqueador de anúncios bloqueando requisições de conversão Requisição bloqueada, conversão perdida Requisição vai primeiro para o seu domínio, depois é encaminhada no server-side — não é bloqueada
Consent Mode v2 em SPAs O estado de consentimento precisa ser reverificado a cada pageview virtual (sem recarregamento de página para reinicializar) O container server-side pode aplicar o estado de consentimento de forma consistente
Velocidade de execução das tags Múltiplos scripts de terceiros carregam no cliente, deixando a SPA mais lenta Apenas uma requisição para o seu servidor; o servidor cuida da distribuição para múltiplas plataformas

Quando considerar server-side tagging para sua SPA:

  • As taxas de bloqueadores de anúncios entre sua audiência excedem 20–30%
  • Você está vendo uma diferença grande entre a contagem de pedidos do lado servidor e as conversões reportadas
  • Você precisa cumprir regulamentações de privacidade da UE e quer um controle mais rígido sobre quais dados saem do navegador

Nota prática: O GTM server-side não substitui o rastreamento client-side da SPA — ele o complementa. Você ainda precisa disparar os eventos certos no momento certo no código da sua SPA; o server-side tagging muda onde esses eventos são processados, não quando eles disparam.

8. Configuração do GTM para SPAs: um exemplo funcional

Aqui está uma configuração completa do GTM para rastrear conversões em uma SPA:

Envio para a data layer (no código da sua aplicação):

// Dispare isso a cada mudança de rota
function onRouteChange(path, title) {
  window.dataLayer = window.dataLayer || [];
  dataLayer.push({
    event: 'spa_pageview',
    spa_page_path: path,
    spa_page_title: title
  });
}

Trigger do GTM:

  • Tipo: Evento Personalizado
  • Nome do evento: spa_pageview
  • Este trigger dispara em: Alguns Eventos Personalizados
  • Condição: spa_page_path equals /thank-you

Tag do GTM:

  • Tipo: Google Ads Conversion Tracking (ou GA4 Event, Meta Pixel, etc.)
  • Trigger: o trigger de conversão da SPA acima

Isso mantém a lógica de rastreamento no GTM (fácil de gerenciar) enquanto depende da sua aplicação para sinalizar quando as navegações ocorrem (confiável em SPAs).

Perguntas frequentes

P. Preciso mudar minha configuração do GTM se migrar de um site multi-página para uma SPA? R. Sim. Qualquer tag que dispara no trigger nativo "Todas as Páginas" ou "Page View" vai parar de disparar nas navegações da SPA. Você precisa adicionar triggers History Change ou triggers de evento da data layer para cada tag que deveria disparar nas mudanças de rota.

P. Minha conversão de envio de formulário não é rastreada na minha SPA. O que é diferente? R. Em SPAs, envios de formulário costumam acontecer via JavaScript (AJAX/fetch) sem nenhuma navegação de página, então nem um trigger de carregamento de página nem um trigger History Change vão capturá-los. Você precisa disparar o evento de conversão diretamente no handler de sucesso do formulário ou enviar um evento para a data layer quando o envio for concluído. Para mais sobre esse padrão, veja por que envios de formulário não estão sendo rastreados.

P. Minha tag de conversão dispara em um recarregamento completo de página, mas não na navegação da SPA. Existe uma correção rápida? R. A correção mais rápida é o trigger History Change do GTM — sem necessidade de mudanças no código. Mas para maior confiabilidade, enviar um evento personalizado para a data layer a partir do código da sua aplicação é melhor, porque você controla exatamente quando o evento dispara.

P. O gtag.js do Google vai lidar com a navegação da SPA automaticamente? R. A tag do Google (gtag.js) tem sim algum suporte a SPA — ela consegue detectar mudanças na History API e enviar eventos de pageview. Mas eventos de conversão (como gtag('event', 'conversion', ...)) ainda precisam ser chamados explicitamente no momento certo. Não confie na detecção automática para o rastreamento de conversão.

P. Usamos renderização no servidor (SSR). Isso ainda se aplica? R. Parcialmente. O carregamento inicial da página é um carregamento de página real (o SSR envia o HTML completo), então as tags disparam normalmente na primeira visita. Mas navegações subsequentes dentro da aplicação continuam sendo navegações de SPA do lado cliente — essas precisam do tratamento de SPA. No Next.js, isso significa que o primeiro carregamento de página funciona bem, mas clicar em um <Link> para outra página é uma transição de SPA.

Conclusão: a tag não está quebrada — ela simplesmente nunca viu o carregamento da página

Falhas de rastreamento de conversão em SPAs não são causadas por tags quebradas. As tags estão bem; elas apenas estão esperando por um evento (carregamento de página) que nunca acontece depois do carregamento inicial. A correção segue sempre o mesmo padrão: avisar a tag quando uma navegação ocorreu, seja via envio para a data layer, um listener de History Change, ou uma chamada de função direta no código do seu componente.

O problema mais sutil é a verificação. Use nossa checklist de verificação de rastreamento de conversão como ponto de partida, mas adicione verificações específicas para SPAs. Como SPAs se comportam de forma diferente dependendo de como o usuário chegou até a página, uma conversão pode funcionar em um cenário e falhar em outro — e o GTM Preview nem sempre capta essa diferença. Sempre verifique com a aba Network, e sempre teste tanto o acesso direto por URL quanto a navegação dentro da aplicação.

O ConversionOK testa suas páginas ao vivo em um navegador independente e verifica se os sinais de conversão estão realmente sendo enviados, independentemente de como a página foi construída. Para SPAs, isso captura os casos em que uma tag está instalada mas nunca dispara na página de conversão — um problema invisível até você olhar no nível de rede.