Pular para o conteúdo principal

Atribuição — Visão geral

A atribuição é a coluna vertebral do tracking de marketing. Decide qual canal recebe o crédito por uma conversão e alimenta os relatórios de BI. Esta página explica como o front-end Cactus captura, persiste e propaga os dados de atribuição.

Princípio central: last-touch

Cada vez que o usuário entra em uma URL com qualquer parâmetro de tracking, o sistema sobrescreve seletivamente os dados antigos: cada campo que veio na URL nova vence o anterior; campos ausentes na URL nova são preservados.

Mudar essa política altera silenciosamente todos os dashboards de BI (calibrados em last-touch desde o legado Vue). Qualquer discussão de first-touch precisa de alinhamento com BI antes.

Exemplo prático de sobrescrita

Usuário entra em:

https://vera.bet.br/?utm_source=facebook&utm_campaign=black-friday&ref=AFIL1

Cookie cookie_tracking fica:

{
"utm_source": "facebook",
"utm_campaign": "black-friday",
"affiliation_code": "AFIL1"
}

Mais tarde, mesmo usuário clica em:

https://vera.bet.br/?utm_campaign=cyber-monday&utm_medium=cpc

Cookie agora:

{
"utm_source": "facebook", // ← preservado (não veio na URL nova)
"utm_campaign": "cyber-monday", // ← sobrescrito
"utm_medium": "cpc", // ← novo, adicionado
"affiliation_code": "AFIL1" // ← preservado
}

:::warning Atenção operacional Se uma campanha NÃO passar utm_source, ela herda silenciosamente o utm_source da campanha anterior. Sempre passe o set completo de UTMs em cada link de campanha. :::

As 3 camadas de captura

A captura acontece em três pontos coordenados pra garantir que nenhum redirect server-side perca atribuição:

Camada 1 — Server loader (app/root.tsx)

Roda em todo request, antes de qualquer redirect. Lê os params da URL, faz merge com o cookie atual e emite Set-Cookie na response.

Por que server-side? A versão anterior só fazia captura client-side em useEffect. Cenário que falha:

  1. User clica em link de afiliado: /?utm_source=afiliado&ref=AFIL1
  2. Algum loader filho inspeciona ?ref= e faz redirect(302) pra outra rota
  3. Browser segue o 302; URL final já não tem UTMs
  4. Client hidrata; useEffect monta mas window.location.search está limpo
  5. Cookie nunca é escrito; signup/deposit submete sem atribuição

Captura no root loader resolve isso: o Set-Cookie é emitido no mesmo response que carrega o redirect — quando o browser hidrata na rota destino, o cookie já existe.

Camada 2 — Client component (TrackingCapture.tsx)

Roda em toda navegação SPA (via useLocation()). Re-aplica a captura quando a URL muda sem full reload — replica o middleware global do Nuxt legado.

Também responsável por:

  • Detecção de PWA (matchMedia('(display-mode: standalone)')) → preenche app_source: "pwa" quando ausente
  • Captura de document.referrer (one-shot, persiste em cookie_referrer)
  • Auto-open de modal quando ?ref=CODE aparece (register pra deslogado, deposit pra logado)

Camada 3 — Submit final (RegisterModal + DepositModal)

No submit do form, lê o cookie e injeta os campos no body do POST pro BFF. Detalhes do payload em UTMs.

Política de sanitização

Cada valor passa por sanitizeTrackingValue() antes de persistir:

  • HTML entities (<, >, ", ', `) — strippadas
  • Substrings perigosas (document, createElement, appendChild) — strippadas
  • Tags inline (<script>...</script>, <img ... src=...>) — strippadas
  • Placeholders não-substituídos ({fbclid}, {{campaign.id}}, __CLICKID__, __CAMPAIGN_ID__) — descartados completamente
  • Valores acima de 500 chars — truncados
  • PII conhecida (user_phone, user_email, user_name, pixel, currency) — nunca capturada, mesmo se a URL trouxer

Evita que UTMs maliciosas/quebradas cheguem em dashboards de analytics.

Cookie cookie_tracking tem cap de 20 chaves (proteção contra abuse de URL stuffing). Quando o cap é atingido, chaves canonical são preservadas e extras são descartadas:

Sempre preservadas (canonical priority):

  • utm_source, utm_campaign, utm_medium, utm_content, src
  • media_source, media_clid
  • affiliation_code, subid, app_source
  • Todos os clicked-IDs (gclid, fbclid, ttclid, etc)

Descartadas primeiro: utm_* extras (custom tags como utm_oferta, utm_term, utm_creative).

Pra continuar