Match quality su Meta. Quando il dataLayer dice una cosa al checkout e un'altra al carrello.
Il catalog match rate era basso e nessuno capiva perché. Il problema era un dataLayer incoerente tra eventi. L'item_id stava in posti diversi a seconda dello step del funnel. Ecco come l'ho trovato e risolto.
Settimana scorsa stavo lavorando sulla match quality di Meta per un brand di orologi svizzero. Il catalog match rate era basso. Non bassissimo, ma abbastanza da compromettere le Dynamic Product Ads. I prodotti non venivano riconosciuti correttamente e Meta mostrava fallback generici invece delle schede prodotto giuste.
Il primo istinto, come sempre, è stato controllare il Pixel e il feed del catalogo. Tutto sembrava a posto. Gli eventi partivano, il catalogo era aggiornato, i product ID nel feed erano corretti. Eppure Meta continuava a non matchare.
Il problema era nel dataLayer
Quando ho aperto il dataLayer con il debugger di GTM, ho visto subito qualcosa di strano. Nell'evento add_to_cart l'ID reale del prodotto era nel campo item_variant. Non in item_id, dove dovrebbe stare. Fin qui, niente di assurdo. Succede spesso con certe piattaforme e-commerce che mappano i campi in modo creativo.
Il problema vero è emerso quando ho controllato gli eventi successivi. Nel begin_checkout e nel purchase, lo stesso ID prodotto era finito dentro item_category. Non più in item_variant. Non in item_id. In item_category.
Quindi avevamo un dataLayer che spostava l'identificativo del prodotto da un campo all'altro a seconda dello step del funnel. Per GA4 non era un problema enorme perché usavamo già una variabile GTM custom che andava a pescare il valore giusto. Ma per Meta, che riceveva i dati tramite CAPI con un mapping diverso, il content_id arrivava vuoto o sbagliato in alcuni eventi.
Meta usa il content_id degli eventi (ViewContent, AddToCart, Purchase) per collegare l'azione dell'utente al prodotto nel catalogo. Se l'ID non corrisponde, il prodotto non viene riconosciuto. Le Dynamic Product Ads mostrano immagini generiche, il retargeting perde precisione, e il ROAS delle campagne scende senza una ragione apparente.
Il fix. Una variabile Facebook separata.
La soluzione non è stata toccare il dataLayer. Non potevo, perché veniva generato dalla piattaforma e-commerce e modificarlo avrebbe richiesto intervento lato sviluppo con tempi lunghi. Ho creato invece una variabile GTM dedicata esclusivamente a Facebook.
Questa variabile faceva una cosa semplice. Per gli eventi view_item e add_to_cart andava a leggere item_variant. Per begin_checkout e purchase leggeva item_category. In entrambi i casi restituiva l'ID corretto del prodotto, quello che matchava con il catalogo Meta.
// Logica della variabile custom in GTM
function() {
var items = {{DL - ecommerce.items}};
if (!items || !items.length) return [];
var eventName = {{Event}};
return items.map(function(item) {
// L'ID reale cambia posizione in base all'evento
if (eventName === 'begin_checkout' || eventName === 'purchase') {
return item.item_category || item.item_id;
}
return item.item_variant || item.item_id;
});
}
Dopo aver pubblicato il container aggiornato, ho monitorato l'Event Manager di Meta per qualche giorno. Il catalog match rate è salito. Non immediatamente, perché Meta ha bisogno di tempo per ricalcolare, ma nel giro di 48 ore la situazione era visibilmente migliorata.
Stesso periodo, altro cliente, altro problema
Mentre lavoravo su questo, mi sono trovato a controllare la match quality anche per un e-commerce di cosmetici. Qui la situazione era diversa. Il match rate sull'evento purchase era calato rispetto a qualche mese prima, nonostante non avessimo toccato nulla nella configurazione di tracking.
Ho fatto un acquisto di test e ho guardato il dataLayer della thank you page. Mancavano completamente i dati utente. Email, telefono, nome. Tutto sparito dall'evento purchase.
Quei dati li usavamo per l'Advanced Matching di Meta. Li hashavamo lato server seguendo le specifiche di Meta e Google, e li inviavamo insieme all'evento purchase tramite CAPI. Senza quei dati, Meta non poteva fare il match tra l'utente che aveva visto l'ad e l'utente che aveva comprato. Il match rate scendeva.
La causa era un aggiornamento del sito. Il mese prima c'erano stati dei problemi tecnici sulla piattaforma e lo sviluppatore aveva dovuto rifare alcune parti del checkout. Nel processo, il codice che iniettava i dati utente nel dataLayer era saltato.
Cosa ho fatto
Ho preparato la documentazione con gli screenshot del dataLayer prima e dopo il problema, ho allegato il documento di specifica originale che avevamo condiviso con lo sviluppatore mesi fa, e ho mandato tutto chiedendo di ripristinare i campi utente nell'evento purchase.
Non è un lavoro spettacolare. Non c'è nessun trick geniale. Ma è il tipo di intervento che fa la differenza tra una campagna Meta che funziona e una che brucia budget senza spiegazione.
Ogni volta che un sito viene aggiornato, c'è il rischio che il dataLayer perda pezzi. Gli sviluppatori non pensano al tracking quando modificano il checkout. E nessuno se ne accorge finché le performance delle campagne non calano. A quel punto sono già passate settimane.
Cosa mi porto via da queste due situazioni
La prima cosa è che il dataLayer non è mai un dato affidabile al 100%. Le piattaforme e-commerce lo generano come vogliono, e ogni aggiornamento può cambiare la struttura senza preavviso. Non basta configurare il tracking una volta. Va monitorato.
La seconda è che GA4 e Meta hanno bisogno di mapping diversi. Quello che funziona per Google non funziona necessariamente per Facebook. Usare la stessa variabile GTM per entrambi è comodo ma pericoloso. Meglio avere variabili separate, anche se significa più lavoro di manutenzione.
La terza, forse la più importante, è che la match quality non si controlla solo quando qualcuno si lamenta. Andrebbe verificata regolarmente, magari con un check mensile sull'Event Manager. Il catalog match rate è un numero che trovi facilmente, e quando scende sotto una certa soglia è quasi sempre un problema di dataLayer, non di catalogo.
Nel nostro caso abbiamo iniziato ad aggiungere un controllo automatico. Il nostro sistema di monitoring su n8n già verifica ogni giorno che i dati di transazione arrivino correttamente in BigQuery. Stiamo pensando di estenderlo per controllare anche la coerenza tra gli item_id nei diversi step del funnel. Se add_to_cart e purchase mandano ID diversi per lo stesso prodotto, il sistema segnala l'anomalia su Slack prima che Meta se ne accorga.
Questi non sono problemi da manuale. Nessun corso di tracking ti insegna a gestire un dataLayer che cambia struttura tra un evento e l'altro. Li trovi solo lavorandoci sopra, facendo test purchase, aprendo il debugger, e confrontando quello che vedi con quello che dovrebbe esserci. È lavoro sporco, ma è quello che tiene in piedi le campagne.