TL;DR, Resposta rápida
9 min de leituraUma single-page application carrega um único documento HTML e troca de tela com JavaScript, então uma tag que só dispara no carregamento da página registra uma pageview para a visita inteira. O tracking de SPA resolve isso com uma pageview virtual a cada mudança de rota, seja a partir de eventos da History API (a configuração "Page changes based on browser history events" do GA4 escuta pushState, popState e replaceState), seja a partir de chamadas page_view manuais. A contagem dupla vem de rodar dois desses mecanismos ao mesmo tempo; as pageviews ausentes vêm de roteadores que não mexem na URL ou de pageviews enviadas antes de a URL ser atualizada.
O que é tracking de SPA?
Em uma single-page application, tracking de SPA significa registrar uma pageview virtual cada vez que o app troca de tela com JavaScript, porque o navegador carrega o documento HTML uma vez e nunca faz um novo carregamento de página nas mudanças de rota seguintes. O Google descreve as SPAs como "websites that load an HTML document once and fetch any additional content using JavaScript APIs," e define o objetivo sem rodeios: "The key to measuring page views from SPAs correctly is to count page views for each screen a user interacts with and get the page referrer right, so you can correctly trace the user journey."
Uma pageview virtual é um evento de pageview que a sua ferramenta de analytics envia sem um carregamento real de página. O navegador nunca pede um novo documento, mas o relatório mostra uma nova página com URL e referrer próprios, como se tivesse pedido.
Por que uma tag de analytics padrão perde as pageviews de uma SPA?
Uma tag de analytics padrão perde as pageviews de uma SPA porque envia a pageview quando o script roda pela primeira vez, e em uma SPA o script roda uma vez por visita. Um visitante que chega em /, abre /pricing e depois /signup por links dentro do app passou por três telas de decisão, enquanto uma tag que só conta o carregamento registra uma pageview para /.
O estrago vai além da contagem de pageviews. O Google observa que, sem pageviews virtuais, "Google Analytics treats the SPA as a single page, leading to skewed metrics," e que "all engagement time is attributed to the initial page load, making it impossible to analyze time spent on individual screens." Cliques e rolagens também ficam registrados sob a URL de entrada. O guia de pageviews vs sessões vs usuários explica por que um número baixo de pageviews por sessão em uma SPA é um sinal de tracking antes de ser um sinal de comportamento.
![]()
Como a History API sinaliza uma mudança de rota?
A History API sinaliza uma mudança de rota por meio de métodos que o seu roteador chama e de eventos que o navegador dispara, e as duas coisas não se correspondem uma a uma. Esse descompasso é o motivo de os rastreadores precisarem escutar em mais de um lugar.
| Mudança | O que a dispara | Evento disparado pelo navegador |
|---|---|---|
history.pushState() | O seu roteador, em um link dentro do app | Nenhum |
history.replaceState() | O seu roteador, quando reescreve a URL atual | Nenhum |
| Botão voltar ou avançar | O visitante | popstate |
history.back(), forward(), go() | O seu código | popstate |
Mudança de hash (#section) | Um link ou código que muda o fragmento | hashchange |
O MDN é explícito sobre as duas primeiras linhas: "just calling history.pushState() or history.replaceState() won't trigger a popstate event." Um rastreador que só escuta popstate vê os cliques em voltar e avançar e perde toda navegação para a frente feita pelos seus próprios links. Os rastreadores resolvem isso envolvendo ou observando pushState e replaceState diretamente.
Como o GA4 rastreia single-page applications?
O GA4 rastreia single-page applications por meio de uma configuração de medição otimizada que envia um page_view quando o histórico do navegador muda. A central de ajuda do Google descreve o gatilho de page_view como "each time the page loads or the browser history state is changed by the active site," e diz que a configuração avançada "listens for pushState, popState, and replaceState." O Google recomenda esse caminho "If your SPA uses the History API, specifically the pushState() and replaceState() method to update screens."
Para ativar:
- No Google Analytics, abra Admin.
- Em Data collection and modification, clique em Data streams e depois no seu fluxo da web.
- Em Enhanced measurement, ative a chave.
- Clique no ícone de configurações e, em Page views, clique em Show advanced settings.
- Ative Page loads e Page changes based on browser history events.
- Salve.
O outro caminho é manual. O Google lista "Custom events" para sites em que as telas são renderizadas sem mudança de URL, como um app que usa objetos DocumentFragment. Nesse caso, você mesmo envia gtag('event', 'page_view', { page_title: '...', page_location: '...' }) a partir do seu roteador.
O que causa contagem dupla no tracking de SPA?
A contagem dupla no tracking de SPA acontece quando dois mecanismos enviam, cada um, uma pageview para a mesma mudança de rota. As configurações comuns que causam isso:
- Google Tag Manager mais os eventos de histórico do GA4. O aviso do Google: "If you configure your tags using Google Tag Manager, don't enable automatic history tracking in Google Analytics, as this can lead to double-counting page views." Um acionador History Change do GTM já dispara "when the URL fragment changes or when a site uses the HTML5 pushstate API."
- Chamadas page_view manuais mais a configuração de histórico.
send_page_view: falsenão impede as pageviews baseadas no histórico. O Google afirma: "If Enhanced Measurement is enabled, Google Analytics will sendpage_viewevents based on browser history changes even if you setsend_page_view: false." Desative Page changes based on browser history events quando o seu roteador envia as próprias pageviews. - replaceState usado para filtros ou abas. O GA4 lista o replaceState entre as mudanças de histórico que escuta, então uma lista de produtos que grava
?sort=pricena URL comreplaceStatepode gerar pageviews a cada mudança de filtro. Teste isso no DebugView antes de confiar na contagem de páginas em telas cheias de filtros. - Duas tags do Google com o mesmo ID. Um snippet gtag fixo no código e uma tag do Google no GTM que apontam para o mesmo ID de medição enviam, cada um, os próprios eventos.
O que causa pageviews ausentes no tracking de SPA?
As pageviews ausentes no tracking de SPA vêm de mudanças de rota que nunca chegam à History API e de pageviews enviadas no momento errado.
- Roteadores que nunca mudam a URL. Um app que troca componentes na memória não dá nada para um listener de histórico ouvir. Use o caminho dos eventos personalizados.
- Roteamento por hash com um rastreador que só escuta o histórico. Mudar
#/pricingdisparahashchange. Verifique se a sua ferramenta conta mudanças de fragmento e configure-a se ela não contar. - Pageviews enviadas antes de a URL ser atualizada. Um
page_viewque dispara antes dopushStateregistra opage_locationantigo. No DebugView, o Google recomenda comparar cadapage_view"with the precedingpage_viewevent to check if the page referrer and page location have been updated correctly." - Referrers desatualizados. O exemplo de evento personalizado do Google guarda a URL antiga e a passa como
page_referrer, porque odocument.referrerdo próprio navegador fica fixo no referrer da entrada original durante toda a visita.
Uma armadilha relacionada fica fora do roteador. O web.dev observa que o back/forward cache "doesn't work for 'soft navigations' within a single-page app," então um clique em voltar dentro do seu app é um evento de histórico, enquanto um clique em voltar que retorna ao seu app a partir de outro site pode restaurar a página inteira da memória sem disparar nenhum evento de histórico.
![]()
Como verificar se o tracking de SPA funciona?
Você verifica o tracking de SPA navegando pelo app com o modo de depuração ativo e conferindo se cada nova tela gera exatamente uma pageview, com a localização e o referrer certos. A checagem do próprio Google é ativar o modo de depuração, "click through your single-page application," e confirmar "a new page_view event in DebugView" para cada tela virtual. Depois, repita com os botões voltar e avançar, uma mudança de filtro e um link com hash, já que são esses os casos que duplicam ou perdem pageviews. O checklist de verificação do analytics aplica a mesma ideia a qualquer rastreador, e o guia de duração média da sessão mostra o que um tracking de SPA quebrado faz com os números de tempo no site.
Painel em tempo real
Rastreamento de metas
Rastreamento sem cookies
Duas correções menores ajudam os números a se sustentarem. Volte a rolagem ao topo a cada mudança de rota com window.scrollTo(0, 0), para que a profundidade de rolagem se aplique à nova tela e não à antiga, e envie a pageview só depois de o roteador atualizar a URL e o título.
Como o Flowsery lida com a navegação em SPAs?
O Flowsery rastreia a navegação em SPAs automaticamente, então uma mudança de rota no React Router ou no Next.js aparece como uma pageview própria, sem código extra. A documentação do SDK npm do Flowsery lista "pageviews, including SPA navigation" no tracking automático, e o FAQ de preços afirma que o Flowsery "counts a pageview each time a visitor loads a page on your site, including single-page app navigations." Para apps que roteiam com fragmentos de URL, o SDK npm tem a opção hashMode, e a documentação do script descreve uma versão do rastreador para SPAs com roteamento por hash. Se o seu app troca de tela sem mudar a URL, o SDK expõe trackPageview() para que você envie uma pageview a partir do seu próprio código. A página de analytics para React mostra como o Flowsery mede rotas client-side, eventos personalizados, funis e receita em apps React.
Perguntas frequentes
O que é uma pageview virtual?
Uma pageview virtual é um evento de pageview enviado sem um carregamento real de página, usado quando uma SPA troca de tela por JavaScript. Ela leva a própria localização de página e o próprio referrer, então os relatórios tratam cada tela como uma página separada. Sem ela, uma visita a uma SPA aparece como uma longa visualização da página de entrada.
O GA4 rastreia as mudanças de rota de uma SPA automaticamente?
Sim, se a medição otimizada estiver ativa e Page changes based on browser history events estiver ativado nas configurações avançadas de Page views. Essa configuração escuta pushState, popState e replaceState. Ela não ajuda apps que trocam de tela sem mudar a URL.
Por que o GA4 está contando cada pageview da SPA duas vezes?
Dois mecanismos estão enviando pageviews para a mesma mudança. Os pares mais comuns são os acionadores de histórico do GTM com os eventos de histórico do GA4, ou chamadas page_view manuais com os eventos de histórico do GA4. Desative um deles; o Google afirma que send_page_view: false não impede as pageviews baseadas no histórico.
O pushState dispara popstate?
Não. O MDN afirma que chamar history.pushState() ou history.replaceState() não dispara um evento popstate. Só ações do navegador, como os botões voltar e avançar, ou chamadas como history.back(), o disparam.
Como o page_referrer deve funcionar em uma SPA?
Cada pageview virtual deve levar a URL da tela anterior como referrer. Guarde a URL antiga antes da mudança de rota e passe-a como page_referrer junto com o novo page_location. Caso contrário, todas as telas reportam o referrer da entrada original.
O back/forward cache afeta o tracking de SPA?
Não nas navegações dentro do app. O web.dev afirma que o bfcache não funciona para soft navigations dentro de uma SPA. Ele vale quando um visitante sai do seu app e volta com o botão voltar, o que pode restaurar a página inteira da memória sem um novo carregamento, se a página for elegível.
Como ativar o tracking de SPA no GA4?
Abra Admin, clique em Data streams, escolha seu fluxo da web e ative Enhanced measurement. Depois clique no ícone de configurações, abra Show advanced settings em Page views e ative tanto Page loads quanto Page changes based on browser history events. Salve. Essa rota funciona quando o router usa pushState e replaceState.
Devo ativar o rastreamento de histórico do GA4 se uso o Google Tag Manager?
Deixe desligado. O Google avisa que usar os dois pode levar à contagem dupla de pageviews. Um acionador History Change do GTM já dispara quando o fragmento da URL muda ou quando o site usa a API pushstate do HTML5.
Como rastrear rotas com hash como #/pricing em uma SPA?
Mudar o fragmento dispara hashchange, então um tracker que só observa a History API pode não registrar a mudança. Verifique se a sua ferramenta conta mudanças de fragmento e configure-a se não contar. O SDK npm do Flowsery tem a opção hashMode, e a documentação do script descreve uma versão do tracker para roteamento com hash.
Como verificar se minha SPA envia uma pageview por tela?
Ative o modo de depuração, navegue pelo app e procure no DebugView um novo evento page_view para cada tela. Compare cada um com o page_view anterior para confirmar que o local da página e o referrer foram atualizados. Repita com os botões de voltar e avançar, uma mudança de filtro e um link com hash.
Este artigo foi útil?
Diga-nos o que pensa!
Veja-nos mais no Google
Um clique marca a Flowsery como fonte preferida e nossos artigos passam a aparecer mais acima nas suas Principais notícias, no modo IA e nas visões gerais com IA.
Antes de ir...
Flowsery
Analytics orientado para receitas para o seu site
Rastreie cada visitante, fonte e conversão em tempo real. Simples, poderoso e sem cookies.
Painel em tempo real
Rastreamento de metas
Rastreamento sem cookies
Termos relacionados do glossário


Por que a taxa de rejeição do GA4 é só a taxa de engajamento invertida
Sua taxa de rejeição do GA4 é a parcela de sessões não engajadas. Como o Google a define, como ela difere do Universal Analytics e onde adicioná-la.


O que o relatório de página de destino do GA4 conta e onde ele fica em branco
Em Reports, o relatório de página de destino do GA4 lista a primeira página de cada sessão. Onde achar, métricas padrão, linhas (not set) e como ver a origem.


Como o rastreamento de pesquisa no site do GA4 registra o que os visitantes digitam
Configure a pesquisa no site do GA4 com a medição aprimorada, adicione seus parâmetros, ache a dimensão Search term e rastreie buscas sem URL.


Como definir propriedades de usuário do GA4 e usá-las em relatórios
Defina propriedades de usuário do GA4 com gtag ou Tag Manager, registre cada uma como dimensão personalizada de usuário e respeite o limite de 25.


Como vincular o Search Console ao GA4 e publicar os relatórios
Veja como vincular o Search Console ao GA4 no Admin, quais papéis você precisa, como publicar os dois relatórios na Library e o que os dados não cruzam.


O que o bfcache faz com a navegação de volta e a sua contagem de pageviews
O bfcache, ou back/forward cache, restaura a página da memória ao voltar ou avançar. Veja quais páginas se qualificam e por que o analytics erra a conta.
Artigos relacionados


Como criar métricas calculadas do GA4 dentro de uma cota de cinco vagas
O Google limita as métricas calculadas do GA4 a 5 por propriedade padrão. Veja a sintaxe da fórmula, as unidades, onde aparecem e o que ela não aceita.


Como configurar o agrupamento de conteúdo do GA4 com um parâmetro
Configure o agrupamento de conteúdo do GA4 com o parâmetro content_group no gtag ou no Tag Manager, leia a dimensão Content group e evite o (not set).


Como adicionar anotações do Google Analytics no GA4 e manter um registro de mudanças
No GA4, as anotações do Google Analytics fixam uma nota datada nos gráficos de linha. Quem cria, limites de 60 e 150 caracteres, teto de 1,000 e uso como log.