Remarketing — Sistema first-party
A plataforma Cactus tem um sistema first-party de remarketing baseado em UUID estável + audience tags do funil. Esta página explica o que é, como funciona, como ativar pra brand nova e quais são as opções futuras de granularidade.
O que é
Uma identidade first-party persistente (UUID v4) salva em cookie próprio do domínio da brand (rmkvera, rmk7k, rmkst77, etc). Funciona como external_id pra:
- Meta Conversions API (CAPI) — server-side
- Google Enhanced Conversions — server-side
- TikTok Events API — server-side
- GTM custom tags — qualquer tag pode ler
window.__rmk.id - dataLayer events —
rmk_ready,rmk_audience_tag
E carrega audience tags do funil (cookie sibling rmkvera_aud):
viewed_casino,viewed_live_casino,viewed_game_detailviewed_sports,viewed_promotionsclicked_register,registered,abandoned_registerviewed_deposit_modal,abandoned_depositftd_completed,multi_deposit
Por que NÃO é só cookie_tracking
cookie_tracking é session-scoped attribution snapshot (7 dias default, decai pra last-touch ficar recente). rmkvera é stable per-browser ID (365 dias sliding) pra cross-session matching.
Mixar os dois num cookie só daria atribuição com TTL de 1 ano (errado) OU remarketing ID com TTL de 7 dias (errado também). Dois conceitos, dois cookies.
Arquitetura
Cookies
rmkvera (UUID estável)
{
"id": "8f2c1a4b-3d3e-4b6c-9c1f-2d6c1f2d6c1f",
"ts": 1731000000000,
"src": "google"
}
| Atributo | Valor |
|---|---|
| TTL | 365 dias sliding (renova a cada visita) |
| Domain | .vera.bet.br (cross-subdomain) |
| SameSite | None em HTTPS |
| HttpOnly | não (CAPI/Pixel client-side leem) |
rmkvera_aud (audience tags)
{
"tags": {
"viewed_casino": 1731000200000,
"viewed_sports": 1731000400000,
"clicked_register": 1731000600000,
"ftd_completed": 1731002000000
},
"updated": 1731002000000
}
| Atributo | Valor |
|---|---|
| TTL | 90 dias sliding |
| Cap | 40 tags totais (eviction de oldest quando estoura) |
| Categoria LGPD | Outros / marketing |
Tags são set-once — re-tagging não atualiza timestamp (evita cookie churn).
Audience tags ativos
Source of truth: lista canônica em Catálogo de eventos. Esta seção é uma cópia resumida — quando divergir, o catálogo vence.
Tags emitidas automaticamente via pushMetricEvent (que delega pra matriz em app/analytics/destinations.ts → canal audience_cookie):
Path-based (via useLocation())
| Tag | Disparada quando user entra em |
|---|---|
viewed_casino | qualquer rota sob casino (lobby, categoria, providers list/detail) |
viewed_live_casino | casino.live (ex: /cassino/ao-vivo) |
viewed_game_detail | casino.play (ex: /cassino/jogar/playtech/abc) |
viewed_sports | qualquer rota sob sports (ex: /esportes/futebol/brasil) |
viewed_promotions | qualquer rota sob promotions |
Brand-aware via Route Registry — funciona automaticamente em cada brand independente do path (/cassino, /casino, /games, etc) graças ao isRouteActive() do ~/utils/routes.
Modal-based (via store subscription)
| Tag | Disparada quando |
|---|---|
clicked_register | openAuthModal("register") |
registered | modal de register fecha + isAuthenticated === true |
abandoned_register | modal de register fecha + isAuthenticated === false |
viewed_deposit_modal | openPaymentModal("deposit") |
abandoned_deposit | modal de deposit fecha (sempre — set-once) |
FTD-based (via useAnalytics)
| Tag | Disparada quando |
|---|---|
ftd_completed | trackDepositConfirmed({ isFirstDeposit: true }) |
multi_deposit | trackDepositConfirmed({ isFirstDeposit: false }) |
abandoned_deposit + ftd_completed podem coexistir no mesmo user — analytics consumer decide como pesar (tipicamente ftd_completed suprime audiences que incluem abandoned_deposit).
MVP novo (Etapa A do brainstorm — adicionado em 2026-05)
| Tag | Disparada quando |
|---|---|
played_demo | clique no botão "Demo" no GameIframe (intent forte de "cadastre e ganhe") |
started_register | user digitou email/document no RegisterModal (engajamento real, mais forte que clicked_register) |
viewed_app_install_banner | banner PWA/APK aparece na tela (surface: footer/topbar/sidebar/floating) |
scrolled_to_payment_seals | viewport hit nos seals do footer após scroll (sinal de avaliação de credibilidade) |
Surfaces de exposição
1. window.__rmk (script custom global)
window.__rmk = {
id: "8f2c1a4b-...",
ts: 1731000000000,
src: "google", // optional
tags: ["viewed_casino", "ftd_completed"],
cookieName: "rmkvera"
}
Qualquer script (parceiro CRM, Hotjar dashboard, etc) lê via window.__rmk?.id.
2. dataLayer events (GTM)
dataLayer.push({
event: "rmk_ready",
external_id: "8f2c1a4b-...",
rmk_first_seen: 1731000000000,
rmk_first_source: "google",
rmk_tags: ["viewed_casino"],
rmk_cookie_name: "rmkvera"
});
dataLayer.push({
event: "rmk_audience_tag",
external_id: "8f2c1a4b-...",
rmk_tag: "ftd_completed",
rmk_audience_count: 5
});
GTM dispara qualquer tag (Meta CAPI, Google Ads Enhanced Conversions, TikTok Events API) usando external_id como identidade primária.
3. Cookie cru
document.cookie mostra rmkvera={JSON} — lido por scripts que não confiam no window.__rmk.
4. Hook React
const { externalId, audienceTags, hasTag, addTag } = useRemarketingId();
if (hasTag("ftd_completed")) {
// mostrar oferta de re-deposit
}
Como ativar pra brand nova
Único arquivo necessário em overrides/<brand>/app/config/features/remarketing.ts:
import type { RemarketingFeatureFlags } from "~/types/remarketing-features";
export const remarketingFeaturesConfig: RemarketingFeatureFlags = {
enabled: true,
cookieName: "rmk7k", // único, brand-neutro
cookieDomain: ".7k.bet.br", // cross-subdomain
pushToDataLayer: true,
exposeOnWindow: true,
sendToBff: false, // ainda não implementado no BFF
};
Pronto. Path tags funcionam automaticamente porque dependem só do route registry brand-aware. Mesma config funciona pra qualquer brand — só muda cookieName e cookieDomain.
Naming convention
| Convenção | Exemplo |
|---|---|
rmk<brand> (camelCase) | rmkvera, rmk7k, rmkbetpontobet |
rmk-<brand> (kebab) | rmk-state77, rmk-pb |
Proibido: nomes contendo cactus ou bluetec. Front rejeita em runtime e desativa o flag.
Brands ativas hoje
| Brand | cookieName | cookieDomain |
|---|---|---|
| Vera | rmkvera | .vera.bet.br |
| Demais | (não ativadas ainda) | — |
Granularidade — opções
Atual: viewed_game_detail agregado
Hoje o cookie marca uma única tag viewed_game_detail quando user abre qualquer game. Audiência: "já abriu algum jogo".
Opção A — viewed_game_<slug> granular
Cardinalidade altíssima (2.000-5.000 games por brand). Cookie eviction tira funnel tags (ftd_completed, etc) pra dar lugar a games. Não recomendado.
Opção B — viewed_provider_<slug> (provider-level)
~30 providers por brand. Cookie controlado. Audience útil ("Pragmatic fans"). Sweet spot.
Opção C — Top-N whitelist
Marketing curate 5-15 games signature (Fortune Tiger, Aviator). Só esses geram tag. Cookie pequeno + high-signal.
Opção D — dataLayer-only
Cada game view dispara dataLayer.push({ event: "rmk_game_view", game_slug, provider_slug }). GTM forwarda pra Meta CAPI / Google Ads / TikTok. Audience criada no painel do ad platform sem precisar enumerar slugs no front. Padrão de mercado pra dynamic remarketing.
Status: nenhuma das opções A-D implementada hoje. Decisão depende de use case real do marketing — discutido em [issue futura].
CAPI / Enhanced Conversions — Roadmap
sendToBff: true na config liga forwarding de external_id no payload de signup/deposit. Requer backend support primeiro:
- BFF aceitar campo
external_idno body - BFF chamar Meta CAPI / Google Enhanced Conversions / TikTok Events API server-side com hashed PII +
external_id - Configurar Dataset/Pixel/Token nas plataformas de ads
Quando back priorizar, brand liga sendToBff: true. Hoje todas as brands têm sendToBff: false — funciona client-side via window.__rmk + dataLayer apenas.
Como debuggar
Cookie inspection
DevTools → Application → Cookies → procura por rmkvera (ou nome da brand) e rmkvera_aud.
window.__rmk
Console:
window.__rmk
// → { id: "...", ts: ..., tags: [...], ... }
dataLayer events
window.dataLayer.filter(e => e.event === "rmk_ready" || e.event === "rmk_audience_tag")
Forçar regeneração
DevTools → Cookies → delete rmkvera. Reload. Server gera novo UUID. Cookie reaparece com id diferente.
Anti-patterns
- Persistir
viewed_game_<slug>granular sem cap-prioritário. Eviction tiraftd_completedda audiência — mata o sinal mais valioso. - Confiar no
external_idantes de o BFF aceitar.sendToBff: truesem backend igual afalse(nada acontece). - Renomear cookie em produção sem migration one-shot. Existing users perdem ID estável.
- Setar
cookieName: "rmkcactus". Vaza plataforma white-label. Front loga warning e desativa. - Não setar
cookieDomainem brand com subdomain (m.brand.com). Cookie fica host-only —m.brand.comewww.brand.comviram users diferentes.