Erros Mais Comuns na Configuração do E-commerce Avançado no GA4
Receita zero, funil quebrado, purchase duplicado e atribuição no gateway: os erros de dataLayer e GA4 que destroem ROAS — e como corrigir.
Contexto
O DebugView mostra purchase. O CRM bateu a venda. No relatório de monetização, receita = 0. Ou o funil de checkout está vazio. Ou o Google Ads comemora ROAS 800% com conversões que não existem no OMS.
No Universal Analytics muita coisa “quase certa” ainda preenchia relatório. No GA4, e-commerce avançado é esquema rígido: nome do evento, tipagem de value/price, currency, transaction_id e array items. Desvio pequeno = falha silenciosa. O Smart Bidding não avisa que o sinal está podre — ele otimiza em cima do lixo.
Este post é a auditoria de sintomas para mídia e e-commerce. O contrato mínimo para engenharia está no Guia de Data Layer para Devs. Aqui o foco é: o que você vê no GA4/Ads, por que acontece e o que checar antes de culpar a campanha.
Problema
| Sintoma no relatório | Causa típica |
|---|---|
purchase existe, receita 0 |
value/price como string ("89.99") ou sem currency ISO |
| Funil ecommerce vazio / drop-off cego | addToCart, checkout_start ou schema UA em vez de snake_case GA4 |
| Produto “fantasma” no carrinho | SPA/listagens sem ecommerce: null entre pushes |
| Conversões > pedidos reais | Thank-you no F5/back sem transaction_id |
| Compra atribuída a paypal.com / stripe.com | Gateway fora da lista de exclusão de referrals |
| Canal Unassigned / (not set) em massa | Consent Mode sem modelagem / CMP bloqueando IDs |
| Pedido B2B some | Array items > 200 sem split |
Se GA4 e faturamento nunca fecham, separe gap estrutural de buraco de implementação — ver GA4 vs CRM. Abaixo: os erros que mais aparecem em auditoria de loja.
Data Layer: estado, nomes e funil
Sem ecommerce: null
O GTM funde chaves entre pushes. Sem limpar o nó ecommerce, um view_item herda items do view_item_list anterior — produto fantasma, métricas inchadas, BigQuery contaminado depois.
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'view_item',
ecommerce: {
currency: 'BRL',
value: 149.9,
items: [{ item_id: 'SKU-100', item_name: 'Camiseta', price: 149.9, quantity: 1 }]
}
});
Regra: todo evento ecommerce (lista, item, cart, checkout, purchase) começa com { ecommerce: null }.
Schema UA colado no GA4
Reaproveitar Enhanced Ecommerce do UA sem migrar parâmetros quebra monetização e Merchant:
| UA (legado) | GA4 (obrigatório) | Se errar |
|---|---|---|
id (pedido) |
transaction_id |
Sem dedup; refresh duplica venda |
id (produto) |
item_id |
SKU solto; Merchant/relatórios quebram |
name |
item_name |
Produto vira (not set) |
revenue |
value |
Receita 0 |
category |
item_category |
Sem drill-down de categoria |
“Use GA4 schema” no GTM é muleta de migração — não arquitetura permanente. Eventos event_category / event_action / event_label não substituem o Event Name canónico.
Funil com nome errado
O funil de comportamento de compra só fecha com nomes exatos (case-sensitive), entre outros:
view_item → add_to_cart → begin_checkout → add_shipping_info → add_payment_info → purchase
checkout_start ou addToCart = etapa zerada na UI. Sem begin_checkout canónico, taxa de abandono do carrinho vira chute. Em checkout headless / pagamento off-site, a sessão pode morrer no retorno — o purchase precisa chegar com identidade costurada (client/session), não só um hit órfão.
Dinheiro: tipagem, moeda e desconto
String vs Number
value, price e quantity precisam ser números. "89.99" ou "89,99" passam no Tag Assistant como “evento ok” e morrem na agregação: purchase contado, Ecommerce revenue = 0. Ads em tROAS perde o sinal monetário e otimiza volume vazio.
Mitigação no GTM (enquanto eng não corrige a origem): Custom JavaScript com parseFloat limpo — mas a correção certa é Number no dataLayer (contrato em Data Layer).
currency no nível do evento
GA4 exige currency ISO 4217 (BRL, USD, EUR) em eventos com valor. Não use $ ou R$. Colocar moeda só dentro de items[] e omitir na raiz do evento = receita global zerada. Vale mesmo em loja 100% Brasil.
value, desconto, tax e shipping
O GA4 não calcula sozinho “price cheio − discount”. Regras práticas:
| Campo | Envio correto | Erro comum |
|---|---|---|
value (evento) |
Soma (price × qty) dos itens após descontos; sem tax/shipping |
Meter IVA/frete no value → ROAS inflado |
price (item) |
Unitário já com desconto daquele item | Price cheio + discount → Item revenue distorcida |
discount (item) |
Monetário por unidade (2.00), não 20% |
Percentual anula métrica de desconto |
tax / shipping |
Parâmetros próprios do evento, fora do value de itens |
— |
transaction_id só com dígitos
IDs puramente numéricos (123456789) já causaram drop / “Transaction ID is not set” no pipeline. Prefira string com prefixo estável: T-123456789. Sem transaction_id, não há deduplicação confiável.
Exemplo mínimo de purchase saudável:
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: 'T-1002741',
currency: 'BRL',
value: 279.8,
shipping: 20,
tax: 0,
items: [
{ item_id: 'SKU-100', item_name: 'Camiseta', price: 129.9, quantity: 1 },
{ item_id: 'SKU-200', item_name: 'Calça', price: 149.9, quantity: 1 }
]
}
});
Duplicação e atribuição
Thank-you que dispara de novo
Tag de purchase ligada só a pageview da página de obrigado: F5, back-forward ou reabrir o link = nova conversão. O GA4 deduplica pelo mesmo transaction_id + cliente numa janela curta — se o ID existir. Sem ID, ROAS de Ads pode inflar dezenas de pontos percentuais.
Corrija na origem (flag em sessionStorage / disparo único no backend) e confirme transaction_id em todo hit de compra.
Self-referral do gateway
Stripe, PayPal, PagSeguro, Mercado Pago, Adyen: o retorno do pagamento vira “nova sessão” com source = domínio do gateway se esses hosts não estiverem na lista de exclusão de referrals do GA4. Resultado clássico: last-click no processador; Google Ads / Meta perdem a conversão; “novos usuários” incham.
Admin → Data streams → Configure tag settings → List unwanted referrals (ou equivalente na UI atual): inclua os domínios dos gateways que você usa.
Unassigned e consentimento
Pico de Unassigned / (not set) depois do CMP muitas vezes não é “GTM quebrado” — é Consent Mode sem IDs até o aceite, com modelagem comportamental só se Advanced Consent estiver bem ligado. Antes de caçar tag, leia o estado do banner: Consent Mode v2.
PII vs UTM
Ao limpar e-mail/telefone da URL no GTM, não sobrescreva page_location nativo removendo a query inteira. Você apaga gclid, utm_*, fbclid e enterra mídia paga em organic. Limpe PII num parâmetro custom (ex. page_uri_clean); deixe a URL canônica intacta para o GA4.
Limite de 200 items (B2B)
O GA4 limita o array items a 200 por evento. Pedido atacado acima disso pode ser descartado. Listas (view_item_list) podem ser fatiadas em vários pushes. Em purchase, repetir o mesmo transaction_id nas fatias faz o GA4 deduplicar e anular pedaços — use sufixos (T-100-1, T-100-2) e reconcilie no warehouse.
O que fica fora deste checklist
Client-side puro perde fatia relevante com blockers e ITP — ver impacto de AdBlockers. Measurement Protocol / server-side sem client_id + session_id gera purchase órfão (Direct). BigQuery exige UNNEST em items/event_params; somar items.price no SQL errado multiplica receita. Isso é projeto de resiliência e dados — não o primeiro passo quando a loja ainda manda value como string.
Checklist de QA
| # | Verificação | Feito quando... |
|---|---|---|
| 1 | Limpeza de estado | Todo push ecommerce precedido de { ecommerce: null } |
| 2 | Nomes GA4 | Funil em snake_case canónico; sem schema UA em parâmetros |
| 3 | Tipagem | value/price Number; quantity Integer |
| 4 | Moeda | currency ISO na raiz do evento |
| 5 | Receita | value = itens pós-desconto; tax/shipping separados |
| 6 | Dedup | transaction_id string estável; refresh não reenvia |
| 7 | Gateway | Domínios de pagamento na exclusão de referrals |
| 8 | Consent / PII | Banner ok; page_location não come gclid/UTM |
| 9 | DebugView | Purchase com value > 0 e items coerentes com o pedido |
| 10 | Ads | Conversão importada reflete value real (amostra vs OMS) |
Próximo passo
Se monetização, funil e atribuição não batem com o que a loja fatura, o problema raramente é “só o lance”. É implementação: dataLayer, tipagem, dedup e exclusões.
Peça uma auditoria de tracking focada em e-commerce: mapeamos eventos do funil, validamos purchase ponta a ponta (Tag Assistant → DebugView → amostra vs OMS) e listamos o que é correção de schema versus o que já pede arquitetura server-side. Antes de mais um teste A/B de criativo, feche o buraco que alimenta o algoritmo.