Si crede che il data layer sia lo snippet da incollare sopra il container GTM: un blocco di codice copiato dalla documentazione, un paio di eventi di test e via. Quello che succede davvero è diverso. Nei progetti che si rompono, il codice c’è quasi sempre: manca l’accordo su come si chiamano gli eventi, su quali parametri sono obbligatori, su quando esattamente il push deve partire e su chi è responsabile se cambia il tema del sito.
Il risultato lo vedi nei report: ricavi che non tornano con il gestionale, carrelli con prodotti sbagliati, purchase doppi, campagne Google Ads che ottimizzano su conversioni gonfiate. E se hai un container server, il problema si moltiplica, perché lo stesso dato sbagliato parte verso GA4, Ads e gli altri endpoint nello stesso istante. Questa guida segue l’ordine reale delle operazioni: prima la specifica, poi lo schema evento per evento, poi il collaudo.
Il data layer è un contratto, non uno script
Definizione operativa: il data layer è un array JavaScript che espone al tag manager lo stato della pagina e le azioni dell’utente, in una forma stabile e indipendente dal tema grafico. Lo sviluppo lo popola, il tag manager lo legge. Questa separazione è tutto il valore del meccanismo.
L’alternativa è leggere i dati dal DOM: prendere il prezzo dal selettore CSS .price span, il nome prodotto dall’H1. Funziona fino al primo restyling, poi smette senza avvisare nessuno. Se oggi stai raschiando il DOM per alimentare GA4, hai un tracciamento a scadenza.
L’opinione netta, visto che il tema è ricorrente: aggiustare in GTM quello che manca a monte è debito tecnico, non una soluzione. Le variabili custom JavaScript che ricostruiscono un item_id a partire dall’URL, le regex sui breadcrumb, i lookup table che mappano nomi di categoria sono tutte patch che nessuno documenta e che si sgretolano al primo rilascio. Costa meno una riunione con chi sviluppa che sei mesi di manutenzione di quelle variabili.
Un dettaglio di ordine che fa perdere giorni: window.dataLayer = window.dataLayer || []; e il push delle informazioni di pagina devono stare prima dello snippet di Google Tag Manager. Se il push arriva dopo, i tag che si attivano su Pageview non trovano i valori e tu vedi parametri vuoti senza capire perché.
Sul perché questa struttura regga l’intera catena di misurazione trovi un approfondimento nell’articolo su cos’è il Data Layer e perché è così importante.
Cosa ti serve prima di scrivere codice
Prerequisiti concreti: accesso al repository o a chi lo gestisce, un ambiente di staging navigabile, l’export del feed prodotti (Merchant Center o il file che lo genera), l’elenco dei metodi di pagamento attivi e la mappa degli step di checkout. Senza feed e senza staging non iniziare: finiresti a testare in produzione.
Il tagging plan minimo
Un foglio con una riga per evento e queste colonne: nome evento, trigger di business (descritto a parole, non in codice), parametri obbligatori, parametri facoltativi, tipo di dato, esempio di payload, destinazione (GA4, Ads, altro). È il documento che firmi insieme allo sviluppo. Se una cosa non è in quel foglio, non esiste.
Aggiungi una colonna "responsabile" e una "versione". Ogni modifica allo schema passa da una revisione e da un rilascio su staging prima della produzione. Senza versionamento, dopo otto mesi nessuno sa più se item_category contiene la categoria padre o la foglia.
Naming e tipi di dato
Regole da fissare subito, senza eccezioni:
snake_caseovunque, nomi di evento GA4 ufficiali dove esistono (view_item,add_to_cart,begin_checkout,purchase). Gli eventi tradotti in italiano o riscritti a mano lasciano vuoti i report standard di GA4.- Prefisso riconoscibile per gli eventi custom, ad esempio
cx_filter_applied. Così distingui a colpo d’occhio cosa è standard e cosa è tuo. - Stessi nomi su desktop e mobile, stessi nomi su tutte le lingue del sito.
- Prezzi come numeri, non stringhe:
29.9, mai"29,90 €". Quantità intere. Valuta in formato ISO 4217 (EUR). item_ididentico all’ID del feed Merchant Center. Se nel feed c’è la variante e nel data layer il prodotto padre, le conversioni non si agganceranno mai alle schede prodotto.
Ultima scelta di progettazione: cosa è page-scope (pubblicato una volta per caricamento: tipo pagina, lingua, stato login, ID utente) e cosa è event-scope (pubblicato al momento dell’azione).
Lo schema evento per evento
Catalogo e scheda prodotto
view_item_list e select_item sono gli eventi che quasi tutti saltano, e sono quelli che ti dicono quali liste e quali categorie portano davvero al carrello. Servono item_list_id, item_list_name e index dentro ogni item.
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'view_item',
ecommerce: {
currency: 'EUR',
value: 59.90,
items: [{
item_id: 'SKU-1234-M-BLU',
item_name: 'Felpa cappuccio',
price: 59.90,
quantity: 1,
item_brand: 'Marca',
item_category: 'Abbigliamento',
item_category2: 'Felpe',
item_variant: 'M / Blu'
}]
}
});
Quella prima riga, ecommerce: null, è il reset dell’oggetto. Senza, i vecchi items restano in memoria e si fondono con i nuovi: è l’origine dei carrelli fantasma con prodotti che l’utente non ha mai visto.
Carrello e checkout
add_to_cart, remove_from_cart, view_cart, begin_checkout, add_shipping_info, add_payment_info. Gli ultimi due sono quelli con più buchi, perché nei checkout multi-step il passaggio avviene spesso in AJAX senza cambio URL. Regola: il push si lega alla risposta positiva del server, non al click. Se lo agganci al click, conti anche gli aggiunte al carrello fallite per prodotto esaurito.
Purchase e refund
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: 'ORD-2024-00987',
value: 119.80,
tax: 21.60,
shipping: 5.90,
currency: 'EUR',
coupon: 'SPRING10',
items: [ /* stessa struttura di view_item */ ]
}
});
Su IVA e spedizione dentro value non c’è una risposta universale: c’è una scelta da fare e da scrivere nel tagging plan. La coerenza conta più della regola. Se in Google Ads ottimizzi sul valore, valuta un value al netto di IVA e spedizione, più vicino al ricavo effettivo. Quello che non puoi fare è avere un criterio in GA4 e un altro in Ads.
Il refund è l’evento che quasi nessuno implementa, e la sua assenza è la causa più comune di ROAS gonfiato nei settori con resi alti. Implementalo almeno nella forma parziale, con transaction_id e gli items restituiti, generandolo dal gestionale o dal backend al momento dello storno.
Accanto agli eventi ecommerce, pianifica subito: ricerca interna con termine e numero di risultati, filtri applicati, errori di validazione form, errori di pagamento con il relativo metodo, login e registrazione. Sono gli eventi che spiegano i buchi del funnel.
Identità, consenso e dati sensibili
client_id lo gestisce GA4, non metterlo nel data layer. user_id sì, se hai un identificativo stabile e pseudonimo dell’utente loggato: pubblicalo in page-scope, mai l’email come identificativo.
Per le Enhanced Conversions e per le API di conversione serve un oggetto user_data con email e telefono normalizzati (minuscolo, spazi rimossi, telefono in formato E.164). Hashing SHA-256 lato browser o delega al container server? Se hai il container, delega: il server fa l’hash prima dell’inoltro e tu eviti di eseguire crittografia nel browser a ogni pagina. Metti comunque in chiaro solo ciò che il tuo DPO ha approvato e solo dietro consenso valido.
Non devono mai entrare nel data layer: dati di pagamento, dati particolari, PII in chiaro negli URL, indirizzi completi. Se il tuo checkout espone l’email in query string, risolvi quello prima di parlare di tracciamento.
Con il Consent Mode, il data layer continua a popolarsi: quello che cambia è il comportamento dei tag. Evita i push condizionati al consenso, perché perdi lo stato della pagina; condiziona semmai l’attivazione dei tag. Per gli eventi che avvengono prima della scelta dell’utente, mantieni la coda nell’array e lascia che i tag si attivino quando lo stato del consenso si aggiorna.
Punto che molti scoprono tardi: il container server recupera gli hit bloccati da ad-blocker e accorcia il problema della durata dei cookie, però non inventa i dati che il browser non ha mai prodotto. Se add_to_cart non viene pubblicato, nessun server lo farà apparire. Gli altri aspetti di qualità del dato li trovi raccolti nella sezione dedicata a Data Layer, consenso e ad-blocker.
Dove si perdono gli eventi: timing, SPA e deduplica
Single Page Application e checkout headless
Senza caricamenti di pagina fisici, servono eventi di virtual page view pubblicati dopo il cambio di route, con reset esplicito dello stato precedente. Il bug classico: il componente monta due volte in fase di sviluppo e il push parte doppio anche in produzione. Si verifica contando gli eventi in GTM Preview durante una navigazione completa.
Rientro dal gateway di pagamento e deduplica
Quando l’utente torna dal PSP, la thank you page a volte viene saltata o ricaricata. Due difese: transaction_id sempre valorizzato con l’ID ordine reale (GA4 deduplica sulla base di quello) e un flag lato backend che marchi l’ordine come già tracciato, così un refresh non produce un secondo push.
Se invii il purchase anche dal backend verso il container server, usa un event_id condiviso tra browser e server per la deduplica lato piattaforma pubblicitaria. Nei casi con alta perdita al ritorno dal PSP, la strada più solida è generare il purchase da un webhook dell’ordine, lato server, e usare l’evento browser solo come segnale secondario.
Piattaforme: plugin o specifica su misura
Shopify espone i Customer Events (Web Pixels), che funzionano in un contesto isolato: il data layer classico del tema non arriva nel checkout. Devi pianificare due sorgenti e verificare che i nomi coincidano.
WooCommerce ha plugin che generano un data layer completo. Vanno bene se il tema è standard. Il rischio concreto è la doppia implementazione: il plugin invia già a GA4 e tu aggiungi i tag in GTM, con conversioni raddoppiate.
PrestaShop e Magento hanno moduli maturi; i punti critici sono le varianti (SKU padre contro SKU figlio) e i prezzi IVA inclusa o esclusa, che spesso differiscono tra listino e carrello.
Su siti custom e headless, i push vanno inseriti nel ciclo di vita del framework, accanto alla logica che aggiorna lo stato, non in componenti di presentazione.
Criterio di scelta semplice: se vendi prodotti semplici, usi un tema standard e non fai campagne con offerte automatiche basate sul valore, un plugin configurato bene è sufficiente. Se hai varianti, bundle, abbonamenti, checkout personalizzato, resi frequenti o un budget pubblicitario che si muove sulle conversioni, ti serve una specifica su misura.
Dal data layer al container server
Il container server sposta l’invio, non la raccolta: la fonte resta il browser. Quello che cambia nella progettazione sono tre cose.
Prima: aggiungi parametri utili solo in presenza di un server, come event_id per la deduplica e chiavi tecniche (ID ordine del gestionale, ID cliente interno) che servono al lookup lato server.
Seconda: tutto ciò che è dato di business sensibile resta fuori dal browser. Margine di prodotto, costo di spedizione reale, flag cliente nuovo o di ritorno si aggiungono nel container server leggendoli da una fonte interna. Non li esponi a chi apre la console e li invii solo dove servono.
Terza: la riconciliazione. Se item_id e transaction_id sono identici a quelli del gestionale, i dati esportati in BigQuery si uniscono agli ordini senza acrobazie e puoi calcolare ROAS su margine invece che su fatturato. È il passaggio descritto in come migliorare il ROAS dell’ecommerce con GTM server-side.
Sul recupero di eventi: dipende dal traffico, dal settore e dalla diffusione degli ad-blocker nella tua base utenti, quindi misuralo nel tuo caso confrontando il periodo prima e dopo. L’effetto sui bid lo trovi spiegato nell’articolo su GTM server-side e Google Ads, mentre le differenze architetturali tra i due approcci sono riassunte nel confronto tra tracciamento client-side e server-side.
Collaudo e sintomi tipici
Checklist da ripetere su staging e poi in produzione:
- GTM Preview: percorri un acquisto completo e conta gli eventi. Nessun doppione, nessun
ecommerceresiduo. - DebugView di GA4: verifica che i parametri arrivino con i tipi giusti (prezzi numerici, valuta corretta).
- Confronta dieci
item_idpresi a caso con il feed prodotti. - Somma
price × quantitydegli items e confrontala convalueal netto delle regole che hai documentato. - Ricarica la thank you page: il
purchasenon deve raddoppiare. - Ripeti il test con ad-blocker attivo e con consenso negato. Definisci in anticipo cosa deve succedere nei due scenari.
- Ogni settimana, confronta gli ordini del gestionale con i
purchasein GA4. Uno scostamento piccolo e stabile è fisiologico; uno scostamento che cresce indica un problema di implementazione. - Imposta un alert su crollo di eventi e ricontrolla dopo ogni rilascio del sito o cambio tema.
| Sintomo | Causa probabile | Verifica |
|---|---|---|
| Ricavi più alti del gestionale | Purchase duplicato al reload o doppia sorgente | Conta i transaction_id distinti in BigQuery |
| Carrelli con prodotti sbagliati | Manca ecommerce: null prima del push |
Ispeziona l’array in console |
| Report standard GA4 vuoti | Nomi evento custom o tradotti | Confronta con l’elenco ufficiale GA4 |
| Prodotti senza nome | items incompleto nelle liste |
Controlla view_item_list |
| Dati solo desktop | Push legato a un componente non montato su mobile | Test su dispositivo reale |
| ROAS alto ma margine basso | refund non implementato |
Confronta resi e storni con GA4 |
Ultimo errore, banale e frequentissimo: dataLayer = [{...}] al posto di dataLayer.push({...}). Il primo sovrascrive l’array e cancella tutto quello che c’era prima, GTM compreso.
Domande frequenti
Il data layer serve ancora se uso il tracciamento server-side con GTM?
Sì, e conta anche di più. Il container server sposta l’invio dei dati, non la loro raccolta: continua a essere il browser a dichiarare quale prodotto è stato visto, aggiunto al carrello o acquistato. Se il data layer non pubblica l’evento, il server non ha nulla da inoltrare. L’unica eccezione sono gli eventi generati direttamente dal backend, come un purchase inviato da un webhook dell’ordine.
Il valore del purchase deve includere IVA e spedizione?
Non esiste un obbligo tecnico: esiste l’obbligo di scegliere una volta e documentarlo nel tagging plan. Se usi offerte automatiche basate sul valore in Google Ads, un value al netto di IVA e spedizione rappresenta meglio il ricavo reale ed evita di sovrastimare gli ordini con spedizione costosa. La cosa da non fare è usare criteri diversi tra GA4, Google Ads e gestionale: lo scostamento diventa impossibile da spiegare.
Posso usare un plugin per il data layer o serve uno sviluppo su misura?
Un plugin è sufficiente se usi un tema standard, hai prodotti semplici e non ottimizzi le campagne sul valore delle conversioni. Serve una specifica su misura quando hai varianti, bundle, abbonamenti, checkout personalizzato, percentuali di reso significative o un budget pubblicitario che si muove sui dati di conversione. Attenzione alla doppia implementazione: molti plugin inviano già a GA4 e, se aggiungi i tag in GTM, le conversioni si raddoppiano.
Come evito che un ordine venga contato due volte se l'utente ricarica la pagina di conferma?
Valorizza sempre transaction_id con l’ID ordine reale: GA4 deduplica le transazioni su quella chiave. In più, fai marcare dal backend l’ordine come già tracciato, così un refresh della thank you page non produce un secondo push. Se invii il purchase anche lato server verso le piattaforme pubblicitarie, usa un event_id condiviso tra browser e server per la deduplica.