Pular para o conteúdo principal

Google Tag Manager (GTM)

GTM é o container central que orquestra todos os pixels client-side (Meta, Google, TikTok, Kwai, Taboola, Clarity, Webtrends, etc) sem precisar deploy de front. Esta página cobre como o front carrega o GTM e como ele é configurado por brand.

Modelo de carregamento

GTM não é carregado eagerly. O front usa um scheduleThirdParty que aguarda:

  • Real users: primeira interação OU requestIdleCallback após LCP
  • Lighthouse / Page Speed: delay fixo de 25 segundos (preserva score sintético sem afetar UX real)

Configuração por brand

Brand-specific via overrides/<brand>/app/config/analytics/analytics.ts:

export const analyticsConfig: AnalyticsConfig = {
gtmId: undefined, // ← undefined = fallback API (brand.settings.analytics.gtmId)
gtmProxyUrl: null, // ← null = standard CDN
gtmScriptUrl: null, // ← null = build URL from gtmId + proxy
disableGtm: false, // ← kill switch local
// ...
};

Resolução de prioridade

1. analyticsConfig (override de brand)
- gtmId definido (string) → usa esse valor, sobrescreve API
- gtmId === undefined → cai no API fallback
- gtmId === null → desativa GTM explicitamente

2. brand.settings.analytics (vindo do BFF/backoffice)
- usado quando o local é undefined

3. null → tracker desativado

Hoje a maioria das brands usa gtmId: undefined e deixa o backoffice resolver via API. Permite trocar GTM container sem deploy de front.

Modos de carregamento (3 cenários)

Modo 1 — CDN padrão Google (default)

{ gtmId: "GTM-XXXXXXX" }

Carrega de https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX. Funciona pra ~98% dos cenários.

Modo 2 — GTM Server-Side via Stape (proxy URL)

{
gtmId: "GTM-XXXXXXX",
gtmProxyUrl: "https://stape.brand.com",
}

Carrega de https://stape.brand.com/gtm.js?id=GTM-XXXXXXX. First-party tracking parcial — o pixel passa pelo seu domínio antes de ir pra Google. Mitiga ad blockers e ITP.

Setup do Stape no Cloudflare Workers ou outro provider similar — fora do escopo desta doc (consulte time DevOps).

Modo 3 — Path custom (gtmScriptUrl override)

{
gtmId: "GTM-XXXXXXX", // ainda obrigatório pro noscript fallback
gtmScriptUrl: "https://stape.brand.com/custom-path.js?id=...",
}

Quando o path do script não segue /gtm.js?id=XXX (Stape com renomeio, etc).

disableGtm

Kill switch local. Quando true, o GTM não carrega independente do gtmId resolvido. Usado em:

  • Dev local: todas as brands setam disableGtm: isDev() ? true : false por padrão pra evitar tracking durante desenvolvimento.
  • Brands sem GTM: disableGtm: true em prod desativa pra brands que ainda não têm container configurado.

Configuração nas brands ativas

Resumo (snapshot — verifique Por Brand → Config Map pra estado atual):

BrandgtmIdStape proxydisableGtm prod
VeraAPI fallbackNãofalse
7kAPI fallbackNãofalse
CassinoAPI fallbackNãofalse
pb-betAPI fallbackNãofalse
betpontobetAPI fallbackNãofalse
state77 family(varia)Nãofalse

Pra modificar GTM ID de uma brand:

  • Sem deploy: muda brand.settings.analytics.gtmId no backoffice da brand (BFF). Próxima request lê o valor novo.
  • Com deploy: edita overrides/<brand>/app/config/analytics/analytics.ts → ajusta gtmId → PR + merge + deploy.

fetch protection

O front aplica uma proteção global em window.fetch ao carregar o GTM. Razão:

GTM containers frequentemente carregam scripts de analytics (SmartTrack, Webtrends e outros) que monkey-patcham window.fetch com interceptors. Esses interceptors tipicamente assumem que o primeiro argumento é uma string URL, mas React Router internamente chama fetch(Request) com objeto Request — quebrando o interceptor com erros como Cannot read properties of undefined (reading 'includes').

A proteção (em app/utils/metrics/gtm.ts):

  • Interceptа qualquer assignment futuro de window.fetch
  • Wrapeia o patched fetch num try/catch
  • Em caso de erro (sync ou async), faz fallback pro nativo

Resultado: GTM e seus scripts continuam funcionando, mas fetch quebrado não derruba navegação.

Eventos disparados

Lista canonical de eventos GTM em Catálogo de eventos. Resumo:

  • page_view — toda navegação SPA
  • sign_up — signup bem-sucedido
  • login — login bem-sucedido
  • pix_generated / astropayDeposit / creditCardDeposit / etc — quando user inicia depósito
  • pix_confirmado_ftd / pix_confirmado — quando depósito é confirmado (FTD ou rebill)
  • first_deposit, purchase — replicas de FTD pra GA4 ecommerce
  • withdraw (event name saque) — saque solicitado
  • view_game_page, view_promotion, select_promotion, search, view_item_list — eventos de UI

Cada evento dispara também via outros canais (Meta Pixel, Kwai, Taboola, etc) — ver tabela completa em Catálogo de eventos.

GTM honra GCM v2 automaticamente quando consent defaults são injetados no dataLayer antes dele carregar. Detalhes em Consent LGPD.

Stape / GTM Server-Side

Stape é uma alternativa terceirizada que hospeda o GTM Server-Side num domínio próprio. Configurada via gtmProxyUrl (já documentado acima). Permite:

  • Pixel da Meta passar pelo seu domínio (mitiga iOS 14 ITP)
  • Tags server-side com lower latency
  • First-party cookies pra alguns trackers

Setup: time de DevOps + marketing operacional juntos. Não é setup de front.

Como debuggar

GTM Preview Mode

GTM tem o "Preview Mode" — abre num site real com debug overlay.

  1. Acessa o container GTM (https://tagmanager.google.com)
  2. Clica em Preview (canto superior direito)
  3. Cole a URL https://localhost:5173/ (ou prod)
  4. Browser abre em modo debug — toda tag que dispara aparece no painel

dataLayer manual

DevTools Console:

window.dataLayer
// → array com todos os eventos pushados

Inspecionar último evento:

window.dataLayer[window.dataLayer.length - 1]

Network tab

Procura por googletagmanager.com ou (seu Stape proxy) na coluna Domain. Cada evento dispara um request — Network mostra payload, status, latência.

Anti-patterns

  1. Carregar GTM eagerly (sem scheduleThirdParty). Quebra LCP e Lighthouse score.
  2. Adicionar pixel novo direto via tag GTM quando o front já tem util pra ele (ex: Kwai). Duplica tracking.
  3. Mudar gtmId em prod sem testar em staging. Tag mal configurada pode disparar evento errado e poluir dashboards.
  4. Setar disableGtm: true em brand com Webtrends opt-in ativo. Webtrends carrega via GTM em algumas brands — quebrar GTM quebra Webtrends.