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 (rmk7k, rmkbpb, 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 rmk7k_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 é snapshot de atribuição com janela finita (30 dias default) — ele precisa
decair pra que o last-touch continue recente. O cookie de remarketing é ID estável por browser
(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 30 dias (errado também). Dois conceitos, dois cookies.
Arquitetura
Cookies
rmk7k (UUID estável)
{
"id": "8f2c1a4b-3d3e-4b6c-9c1f-2d6c1f2d6c1f",
"ts": 1731000000000,
"src": "google"
}
| Atributo | Valor |
|---|---|
| TTL | 365 dias sliding (renova a cada visita) |
| Domain | .7k.bet.br (cross-subdomain) |
| SameSite | None em HTTPS |
| HttpOnly | não (CAPI/Pixel client-side leem) |
rmk7k_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: "rmk7k"
}
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: "rmk7k"
});
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 rmk7k={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, // inerte hoje — nenhum código lê este flag
};
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
O padrão em uso nas 13 brands é rmk<abreviação-da-brand>, minúsculo e sem separador —
rmk7k, rmkbpb, rmkcl7k, rmkst77, rmkphst77. Mantenha curto: o nome viaja em todo
Set-Cookie.
Proibido: nomes contendo cactus ou bluetec. A validação é em runtime —
FORBIDDEN_PLATFORM_NAMES = /cactus|bluetec/i em app/utils/remarketing-id.ts rejeita o nome e
desativa o flag.
Brands ativas hoje
Todas as 13 brands do base têm enabled: true, cada uma com cookie e domínio próprios. O
default do base é { enabled: false, cookieName: "" } — não há brand nessa situação hoje.
| Brand | cookieName | cookieDomain |
|---|---|---|
7k-bet-br | rmk7k | .7k.bet.br |
betpontobet-bet-br | rmkbpb | .betpontobet.bet.br |
casateste-com | rmkcasateste | .casateste.com |
cl-bet7k-com | rmkcl7k | .cl.bet7k.com |
donald-bet-br | rmkdnb | .donald.bet.br |
fi-7k-bet | rmkfi7k | .fi.7k.bet |
ng-7k-bet | rmkng7k | .ng.7k.bet |
pb-bet | rmkpb | .pb.bet |
ph-state77-com | rmkphst77 | .ph.state77.com |
pt-state77-com | rmkptst77 | .pt.state77.com |
rj-bet | rmkrj | .rj.bet |
state77-com | rmkst77 | .state77.com |
x2b-bet | rmkx2b | .x2b.bet |
Todas com pushToDataLayer: true, exposeOnWindow: true e sendToBff: false.
Fonte viva:
grep -rn "cookieName\|cookieDomain" overrides/*/app/config/features/remarketing.ts.
Nos exemplos desta página o cookie usado é o do 7k-bet-br (rmk7k / rmk7k_aud); substitua pelo
cookieName da sua brand.
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
A intenção é que sendToBff: true ligue o forwarding do external_id no payload de
signup/deposit, pro BFF encaminhar server-side.
:::caution sendToBff é inerte hoje — inclusive no front
O campo existe no tipo (RemarketingFeatureFlags.sendToBff) e as 13 brands o declaram como
false, mas nenhum código o lê. O helper que consultaria a matriz
(shouldForwardToBffCapi()) não tem consumidor, e nenhum payload de signup/deposit inclui
external_id. Ligar o flag hoje não muda nada.
:::
Pra sair do papel, falta em três frentes:
- Front: consumir
shouldForwardToBffCapi()na montagem dos payloads de signup/deposit e anexarexternal_idquandosendToBffestiver ligado. - BFF: aceitar o campo
external_idno body e chamar Meta CAPI / Google Enhanced Conversions / TikTok Events API server-side, com PII hasheada +external_id. - Plataformas de ads: configurar Dataset / Pixel / Token.
Enquanto isso, o remarketing funciona client-side: window.__rmk + eventos de dataLayer, com o
GTM encaminhando pras plataformas. Ver Contract BFF.
Como debuggar
Cookie inspection
DevTools → Application → Cookies → procura por rmk7k (ou nome da brand) e rmk7k_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 rmk7k. 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_idserver-side.sendToBff: truehoje não tem efeito nenhum — nem o front monta o payload, nem o BFF recebe. Usewindow.__rmk/ dataLayer. - 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.