UTM persistence script e arquitetura martech em 3 BUs

Governança única de UTM, persistência via sessionStorage e propagação automática em links internos. Atribuição 100% coberta ponta a ponta.

Cliente
Grupo de educação com 3 unidades de negócio
Setor
Educação
Categoria
Papel
Lead de arquitetura martech
Duração
2025-2026
Stack
JavaScript vanillaGTMHubSpotGA4WordPress
S01

Contexto

O que é: governança unificada de UTM e arquitetura martech cross-BU num grupo de educação com 3 unidades de negócio. Script de persistência via sessionStorage + propagação automática em links internos + push no dataLayer para HubSpot e GA4 consumirem. Resultado: 100% de cobertura de atribuição ponta a ponta.

Contexto: 3 BUs com nomenclaturas de UTM distintas, implementações parciais de HubSpot e atribuição fragmentada. Era impossível responder "essa lead veio de onde" com confiança.

S02

Problema

UTMs se perdiam em navegações internas entre sites das 3 BUs. Formulários capturavam apenas o último referrer. Atribuição ficava incompleta no HubSpot.

S03

Abordagem

Governança unificada de UTM nomenclature + script de persistência via sessionStorage + injeção automática em links internos + push para dataLayer para HubSpot e GA4 consumirem.

S04

Execução

Script único carregado em todas as 3 BUs via GTM. Captura entry point, persiste na sessão, propaga em navegação interna, expõe no dataLayer.

javascriptassets/js/utm-governance.js
const SESSION_KEY = 'sp_session_attribution';
const UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign',
                  'utm_content', 'utm_term'];

function captureEntryPoint() {
  const stored = sessionStorage.getItem(SESSION_KEY);
  if (stored) return JSON.parse(stored);

  const params = new URLSearchParams(window.location.search);
  const captured = {};
  UTM_KEYS.forEach((k) => {
    if (params.has(k)) captured[k] = params.get(k);
  });

  if (Object.keys(captured).length) {
    captured.captured_at = new Date().toISOString();
    captured.landing_page = window.location.pathname;
    sessionStorage.setItem(SESSION_KEY, JSON.stringify(captured));
  }
  return captured;
}

function appendToInternalLinks(attribution) {
  if (!Object.keys(attribution).length) return;
  const selector = `a[href^="/"], a[href*="${window.location.hostname}"]`;
  document.querySelectorAll(selector).forEach((a) => {
    const url = new URL(a.href, window.location.origin);
    UTM_KEYS.forEach((k) => {
      if (attribution[k] && !url.searchParams.has(k)) {
        url.searchParams.set(k, attribution[k]);
      }
    });
    a.href = url.toString();
  });
}

const attribution = captureEntryPoint();
appendToInternalLinks(attribution);

window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ event: 'sp_attribution_ready', attribution });
Captura + persistência + propagação em uma função só.
S05

Resultados

3
BUs unificadas
Governança única
100%
Cobertura de atribuição
UTM preservada ponta a ponta
S06

Output reutilizável

Convenção UTM governada em documento, script versionado, plano de teste pré-produção, playbook para replicar em novas BUs.