Como Criar Eventos Personalizados no GTM Sem Precisar Alterar o Código do Site

Element Visibility, cliques com Matches CSS Selector e DOM scraping no GTM — autonomia para mídia sem PR de frontend, e quando isso vira dívida técnica.

Contexto

A campanha sobe amanhã. Você precisa de um evento de clique no CTA, impressão do popup de saída e download do PDF. Engenharia está no backlog do sprint. O ticket de dataLayer.push não sai esta semana.

O Google Tag Manager existe exatamente para esse gap: triggers nativos, seletores CSS e variáveis que leem o DOM sem alterar o repositório do site. Funciona. Também é frágil. Uma troca de classe no redesign e o evento some em silêncio — o Ads continua otimizando como se nada tivesse acontecido.

Este guia é o kit de autonomia para mídia. O padrão de longo prazo continua sendo o contrato de Data Layer. Aqui você aprende o que dá para fazer sozinho — e quando parar.

Problema

Sintoma Causa típica
Clique no botão “não conta” Clique caiu no ícone/span dentro do link; trigger só olhava o texto
Form envia, GTM calado AJAX / preventDefault — Form Submission nativo morto
Popup de sucesso invisível para analytics Sem thank-you page; elemento injetado depois do load
Evento dispara em lugar errado Click Classes + contains (falso positivo / ordem de classes)
Evento sumiu após redesign Schema drift: seletor CSS ou ID mudou

Autonomia sem critério vira dívida: você ganha velocidade agora e perde confiabilidade no próximo deploy de front.

Triggers nativos (sem código do site)

Clique: Just Links vs All Elements

  • Just Links — escuta cliques em <a>. Use Wait for Tags quando a navegação é rápida demais e a tag não chega a disparar.
  • All Elements — qualquer nó (botão, imagem, SVG, div). Mais amplo; combine com condição forte de seletor.

Ative as variáveis built-in de clique: Click Text, Click Classes, Click ID, Click URL, Click Element.

Element Visibility

Para banners, popups, mensagem de “obrigado” sem redirect, cards em carrossel:

  1. Trigger Element Visibility — ID ou CSS Selector.
  2. Ajuste % mínimo visível (ex.: 50–100%) e tempo mínimo on-screen (ms) para filtrar scroll acidental.
  3. Frequência: uma vez por página, uma vez por elemento, ou sempre que aparecer.
  4. Marque Observe DOM changes se o elemento é injetado depois do load (modal, erro de form, toast).

O GTM preenche percent visible e duração — útil como parâmetro do evento no GA4.

Formulário

Form Submission nativo só ajuda quando o submit sobe até o window. Em form AJAX, a ponte sem eng costuma ser: clique no botão de enviar + Element Visibility na mensagem de sucesso. Se o form vive em iFrame ou a resposta é só de rede, vá ao guia Formulários Complexos e iFrames — aí DIY puro não basta.

Matches CSS Selector (não Click Classes contains)

Click Classes devolve uma string ("btn primary cta"). Condicionar com contains “btn” gera falso positivo (nav-button-container) e quebra se a ordem das classes mudar.

O padrão certo: variável Click Element + condição Matches CSS Selector. Isso chama element.matches() no nó real do DOM.

Seletor O que faz Uso típico
button.cta-primary Tag button e classe cta-primary CTA principal sem pegar link estilizado igual
#nav-menu a, #nav-menu a * Link do menu ou qualquer filho (ícone, span) Clique no ícone ainda conta como navegação
a[href$=".pdf"] href termina em .pdf Download sem listar cada URL
div#cart > a Link filho direto de #cart Ação do mini-carrinho, não link dentro da descrição
[data-product-id] Tem atributo data-product-id Card de produto com metadado estável
input[type="checkbox"]:checked Checkbox marcado no momento do evento Aceite de termos / opt-in

Regra prática: prefira data-* estáveis a classes geradas por CSS-in-JS (css-1a2b3c). Se o front só expõe classe ofuscada, você já está no limite do DIY.

DOM scraping: extrair preço, título, atributo

Só registrar o clique às vezes não basta — você quer item_name ou preço ao lado do botão.

DOM Element Variable

Método: ID ou CSS Selector. Sem nome de atributo → texto (innerText). Com atributo → src, href, data-value, etc.

Custom JavaScript (mínimo)

A variável deve ser uma função anônima com return:

function() {
  var el = document.querySelector('h1.product-title');
  if (!el) return undefined;
  return el.innerText.trim();
}

Para pegar o preço do card clicado (não o primeiro da página), suba a partir do {{Click Element}}:

function() {
  var clickEl = {{Click Element}};
  if (!clickEl || !clickEl.closest) return undefined;
  var card = clickEl.closest('[data-product-id]');
  if (!card) return undefined;
  var priceEl = card.querySelector('.price, [data-price]');
  if (!priceEl) return undefined;
  var raw = (priceEl.getAttribute('data-price') || priceEl.innerText || '')
    .replace(/[^\d.,]/g, '')
    .replace(',', '.');
  var n = parseFloat(raw);
  return isNaN(n) ? undefined : n;
}

Aviso: isso é tática de campanha, não arquitetura. Trocar .price por .product-cost zera o parâmetro sem alarme. Não trate scrape como fonte da verdade no dataLayer — use só como parâmetro da tag GA4 enquanto o contrato com eng não existe (Data Layer para Devs).

Limites que o DIY não resolve bem

SPA (React/Vue/Angular): um único load → um pageview clássico. O trigger History Change simula pageviews virtuais; no GA4, desative a parte de histórico do Enhanced Measurement se você for medir SPA pelo GTM, senão duplica. Timing: History Change pode disparar antes do DOM novo — título/scrape saem stale. Guia completo de SPA fica para um post dedicado; aqui o ponto é: autonomia tem teto.

Shadow DOM: cliques dentro de Web Components muitas vezes não aparecem em Click Text/Classes/Selector. Se o CTA “não existe” no Preview, pode ser shadow. Aí o caminho é eng expor evento ou dataLayer — não mais um seletor milagroso.

Do trigger ao evento no GA4

  1. Trigger (Click / Visibility / Custom Event interno).
  2. Tag GA4 Event — nome em snake_case estável (cta_click, file_download, exit_intent_view). Evite ctaClick / nomes de campanha da semana.
  3. Parâmetros: link_url, file_name, element_text, form_id — o que for estável o bastante para reportar.
  4. Preview (Tag Assistant) → DebugView → só então publicar o container.

Enhanced Measurement já cobre scroll, outbound e file download em muitos sites. Antes de criar tag paralela, confira se você não está duplicando o que o GA4 já coleta.

Checklist de QA

# Verificação Feito quando...
1 Condição Click Element + Matches CSS Selector (não Classes contains)
2 Filho do link Seletor inclui a * quando o clique cai no ícone
3 Visibility Observe DOM changes ligado se o elemento é dinâmico
4 Form AJAX Clique + Visibility de sucesso — ou fluxo do guia de formulários
5 Parâmetros Scrape sanitizado; Number onde for valor; sem PII
6 Nome GA4 Evento snake_case reutilizável entre campanhas
7 Preview Tag dispara no elemento certo; zero falso positivo na nav
8 Pós-deploy front Revalidar seletores após release de UI

Próximo passo

Use GTM sem código para destravar campanha. Não construa o funil inteiro da empresa em cima de div.css-xyz.

Baixe o guia PDF gratuito (triggers, CSS selectors, checklist de QA): Guia GTM sem alterar o código.

Quando o evento paga mídia ou alimenta Smart Bidding, o próximo passo é um mapa de eventos App/Web: o que o front publica no dataLayer, ownership e QA — para o redesign não apagar sua conversão. Se quiser, partimos do que você já tem no container (CTAs, forms, downloads) e separamos o que pode continuar DIY do que precisa de contrato com engenharia.