SafirionSafirion

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/track

Em 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.