Fix de colisão de pixel Twitter/X vs Google Ads em Shopify

Pixel do X sobrescrevia UTMs e gclid via history.replaceState(), quebrando atribuição do Google Ads. Guard script recuperou 100% da atribuição.

Cliente
Marca DTC de vestuário performance
Setor
E-commerce
Categoria
Papel
Debug e implementação
Duração
2025
Stack
ShopifyGTMJavaScriptPixel XPixel MetaGoogle Ads
S01

Contexto

O que é: debug e fix de colisão entre o pixel do Twitter/X e o rastreamento do Google Ads numa loja Shopify. O pixel do X reescrevia a URL via history.replaceState(), engolindo UTMs e gclid, e quebrando a atribuição no checkout. Guard script recuperou 100% da atribuição.

Contexto: loja DTC com Meta Ads, Google Ads e X Ads simultâneos. Atribuição no Google Ads começou a cair sem mudança nas campanhas, sintoma clássico de conflito entre tags cliente.

S02

Problema

Pixel do X injetava parâmetros tw_source, tw_adid e similares via history.replaceState(), sobrescrevendo a URL e engolindo UTMs e gclid originais. O Google Ads perdia a atribuição no checkout.

S03

Abordagem

Interceptar e proteger os parâmetros críticos antes que qualquer tag os modifique. Persistir em sessionStorage. Monitorar mutações na URL e re-aplicar se sobrescritas.

S04

Execução

Script carregado no início do <head> via GTM, antes de qualquer outro pixel. Observer em history.pushState e history.replaceState.

javascriptsnippets/attribution-guard.js
(function attributionGuard() {
  const CRITICAL = ['utm_source', 'utm_medium', 'utm_campaign',
                    'utm_content', 'utm_term', 'gclid', 'fbclid'];

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

  if (Object.keys(saved).length) {
    sessionStorage.setItem('sp_attribution', JSON.stringify(saved));
  }

  const restore = () => {
    const current = new URLSearchParams(window.location.search);
    let dirty = false;
    Object.entries(saved).forEach(([k, v]) => {
      if (!current.has(k)) {
        current.set(k, v);
        dirty = true;
      }
    });
    if (dirty) {
      const clean = `${window.location.pathname}?${current}`;
      window.history.replaceState({}, '', clean);
    }
  };

  // Intercepta mudanças de URL feitas por outros scripts
  const originalReplace = history.replaceState;
  history.replaceState = function (...args) {
    originalReplace.apply(this, args);
    restore();
  };

  window.addEventListener('DOMContentLoaded', restore);
})();
Guard script carregado antes de qualquer pixel.
S05

Resultados

100%
Atribuição Google Ads recuperada
Medido via comparação antes/depois
0
Conflitos remanescentes
Meta, X e Google coexistem
S06

Output reutilizável

Documentação técnica do conflito (nível de browser), checklist de validação cross-pixel, snippet reaplicável em qualquer Shopify com stack similar.