Instalação no Google Tag Manager
Quatro passos: tag base em todas as páginas, tag de conversões, tag de cliques e os pushes no dataLayer do site.
Endpoint de tracking
https://tracking.partnersafirion.com/api/trackEm produção, defina PUBLIC_BASE_URL no .env para o snippet já sair com o domínio certo. O site é HTTPS, então o endpoint também precisa ser HTTPS.
Caminho rápido: importar tudo de uma vez
Baixe o arquivo e, no Tag Manager, vá em Administrador → Importar contêiner, escolha o arquivo, o espaço de trabalho atual e a opção Mesclar. Ele cria as três tags, os dois acionadores e as sete variáveis abaixo, já apontando para https://tracking.partnersafirion.com/api/track. Depois é só Enviar → Publicar.
1. Tag base (HTML personalizado · acionador: All Pages)
Captura
utm_source, utm_medium e utm_campaign da URL, guarda por 90 dias no navegador e registra um evento pageview (contado como clique) sempre que alguém chega com UTM. Nas páginas seguintes de quem veio por link, envia pagina, que monta o caminho de navegação na ficha da pessoa. Também cria a função global sfrTrack.<script>
(function () {
var ENDPOINT = "https://tracking.partnersafirion.com/api/track";
var KEY = "sfr_utm", CID_KEY = "sfr_cid", DAYS = 90;
// utm_source que o próprio site injeta (fluxo OAuth etc.). Não é campanha.
var IGNORE = ["external_app_oauth"];
function qs(name) {
var m = new RegExp("[?&]" + name + "=([^&#]*)").exec(window.location.search);
return m ? decodeURIComponent(m[1].replace(/\+/g, " ")) : "";
}
function store(k, v) { try { localStorage.setItem(k, v); } catch (e) {} }
function load(k) { try { return localStorage.getItem(k); } catch (e) { return null; } }
function uid() {
return Date.now().toString(36) + "-" + Math.random().toString(36).slice(2, 10);
}
// 1) client_id persistente por navegador
var cid = load(CID_KEY);
if (!cid) { cid = uid(); store(CID_KEY, cid); }
// 2) captura UTMs da URL e guarda por 90 dias (última interação vence)
var fromUrl = {
utm_source: qs("utm_source"), utm_medium: qs("utm_medium"), utm_campaign: qs("utm_campaign"),
utm_content: qs("utm_content"), utm_term: qs("utm_term")
};
var landed = !!(fromUrl.utm_source || fromUrl.utm_medium || fromUrl.utm_campaign) && IGNORE.indexOf((fromUrl.utm_source || "").toLowerCase()) === -1;
var utm = null;
if (landed) {
fromUrl.exp = Date.now() + DAYS * 864e5;
store(KEY, JSON.stringify(fromUrl));
utm = fromUrl;
} else {
try { utm = JSON.parse(load(KEY) || "null"); } catch (e) { utm = null; }
if (utm && utm.exp && utm.exp < Date.now()) { utm = null; }
}
// 3) função global usada pelas outras tags (sfrHasUtm diz se a pessoa veio por link)
window.sfrHasUtm = !!utm;
window.sfrTrack = function (event, data) {
data = data || {};
// Sem uma campanha atribuída, não polui o dashboard com navegação orgânica.
if (!utm) return;
var payload = {
event: event,
client_id: cid,
event_id: data.event_id || (cid + "-" + uid()),
page_url: window.location.href,
referrer: document.referrer || null
};
if (utm) {
payload.utm_source = utm.utm_source || null;
payload.utm_medium = utm.utm_medium || null;
payload.utm_campaign = utm.utm_campaign || null;
payload.utm_content = utm.utm_content || null;
payload.utm_term = utm.utm_term || null;
}
for (var k in data) { if (data[k] !== undefined && data[k] !== null && data[k] !== "") payload[k] = data[k]; }
var body = JSON.stringify(payload);
// text/plain evita preflight de CORS. Se o navegador recusar o beacon,
// usa XHR como fallback para não perder a chegada durante redirecionamentos.
var queued = false;
try {
if (navigator.sendBeacon) queued = navigator.sendBeacon(ENDPOINT, new Blob([body], { type: "text/plain" }));
} catch (e) {}
if (!queued) {
var x = new XMLHttpRequest();
x.open("POST", ENDPOINT, true);
x.setRequestHeader("Content-Type", "text/plain");
x.send(body);
}
};
// 4) chegada com UTM conta como clique no link; páginas seguintes de quem veio por link viram "pagina"
if (landed) window.sfrTrack("pageview", { label: document.title });
else if (utm) window.sfrTrack("pagina", { label: document.title });
})();
</script>2. Tag de conversões (HTML personalizado · acionador: Evento personalizado)
Crie um acionador do tipo Evento personalizado com o nome
registro|ftd|redeposito e marque Usar correspondência de expressão regular. Crie as variáveis de camada de dados DLV - value, DLV - currency, DLV - user_id e DLV - transaction_id apontando para value, currency, user_id e transaction_id, e também DLV - nome, DLV - email e DLV - telefone para os campos do cadastro. As UTMs guardadas pela tag base vão junto automaticamente.<script>
(function () {
if (!window.sfrTrack) return;
window.sfrTrack({{Event}}, {
value: {{DLV - value}},
currency: {{DLV - currency}},
user_id: {{DLV - user_id}},
event_id: {{DLV - transaction_id}},
dados: {
nome: {{DLV - nome}},
email: {{DLV - email}},
telefone: {{DLV - telefone}}
}
});
})();
</script>3. Tag de cliques (HTML personalizado · acionador: Clique em todos os elementos)
Ative as variáveis integradas Click Text, Click URL e Click ID em Variáveis → Configurar. Crie um acionador do tipo Clique · Todos os elementos e deixe em "Todos os cliques". Cada clique vira um evento
clique com o texto do botão ou link, exibido na linha do tempo da pessoa.<script>
(function () {
// só grava cliques de quem chegou por link com UTM
if (!window.sfrTrack || !window.sfrHasUtm) return;
var text = ({{Click Text}} || "").toString().trim();
var url = {{Click URL}} || "";
var id = {{Click ID}} || "";
var label = text || id || url;
if (!label) return;
window.sfrTrack("clique", { label: label.slice(0, 120), page_url: window.location.href });
})();
</script>4. Pushes no dataLayer (a fazer no código do site)
O site precisa avisar quando as conversões acontecem.
transaction_id vira event_id e impede que o mesmo depósito seja contado duas vezes. nome, email e telefone aparecem na ficha da pessoa. Qualquer outro campo enviado dentro de dados também é guardado. Os eventos que entram nos totais são pageview, registro, ftd e redeposito; pagina e clique alimentam só a jornada.// Logo após o cadastro ser concluído (os campos vão para a ficha da pessoa no dashboard)
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "registro",
user_id: "12345",
nome: "Maria Silva",
email: "maria@exemplo.com",
telefone: "+5511999999999"
});
// Primeiro depósito confirmado (FTD)
window.dataLayer.push({
event: "ftd",
user_id: "12345",
value: 150.00,
currency: "BRL",
transaction_id: "dep_98765" // evita contar duas vezes
});
// Depósitos seguintes
window.dataLayer.push({
event: "redeposito",
user_id: "12345",
value: 300.00,
currency: "BRL",
transaction_id: "dep_98766"
});Teste rápido pelo terminal
Envie um evento manual e confira se ele aparece na página Eventos. Se a trinca de UTM bater com uma campanha cadastrada, ela é associada na hora.
curl -X POST "https://tracking.partnersafirion.com/api/track" \
-H "Content-Type: application/json" \
-d '{"event":"ftd","utm_source":"email","utm_medium":"ftd-chain","utm_campaign":"ftd-email-01","user_id":"12345","value":150,"currency":"BRL","event_id":"dep_98765"}'Como a atribuição funciona
- Última interação: se o usuário chegar por outro link com UTM, a campanha guardada é substituída.
- Conversões sem UTM guardada (usuário chegou direto) aparecem como "(sem UTM)" no dashboard.
- Eventos com UTM de campanha não cadastrada aparecem como "(não cadastrada)" com um atalho para cadastrar. Ao cadastrar, os eventos antigos são associados.
- O
client_idé gerado por navegador e usado para contar visitantes únicos. - A ficha da pessoa junta o navegador (
client_id) ao usuário (user_id) no primeiro evento que traz os dois, normalmente o cadastro.