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
requestIdleCallbackapó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 : falsepor padrão pra evitar tracking durante desenvolvimento. - Brands sem GTM:
disableGtm: trueem 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):
| Brand | gtmId | Stape proxy | disableGtm prod |
|---|---|---|---|
| Vera | API fallback | Não | false |
| 7k | API fallback | Não | false |
| Cassino | API fallback | Não | false |
| pb-bet | API fallback | Não | false |
| betpontobet | API fallback | Não | false |
| state77 family | (varia) | Não | false |
Pra modificar GTM ID de uma brand:
- Sem deploy: muda
brand.settings.analytics.gtmIdno backoffice da brand (BFF). Próxima request lê o valor novo. - Com deploy: edita
overrides/<brand>/app/config/analytics/analytics.ts→ ajustagtmId→ 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 SPAsign_up— signup bem-sucedidologin— login bem-sucedidopix_generated/astropayDeposit/creditCardDeposit/ etc — quando user inicia depósitopix_confirmado_ftd/pix_confirmado— quando depósito é confirmado (FTD ou rebill)first_deposit,purchase— replicas de FTD pra GA4 ecommercewithdraw(event namesaque) — saque solicitadoview_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.
Google Consent Mode v2
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.
- Acessa o container GTM (https://tagmanager.google.com)
- Clica em Preview (canto superior direito)
- Cole a URL
https://localhost:5173/(ou prod) - 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
- Carregar GTM eagerly (sem
scheduleThirdParty). Quebra LCP e Lighthouse score. - Adicionar pixel novo direto via tag GTM quando o front já tem util pra ele (ex: Kwai). Duplica tracking.
- Mudar
gtmIdem prod sem testar em staging. Tag mal configurada pode disparar evento errado e poluir dashboards. - Setar
disableGtm: trueem brand com Webtrends opt-in ativo. Webtrends carrega via GTM em algumas brands — quebrar GTM quebra Webtrends.