E no, non è colpa degli ad blocker.
Ogni volta che un cliente ci chiama perché “le conversioni non tornano”, la prima cosa che facciamo è la più stupida possibile: apriamo il pannello ordini di WooCommerce, apriamo Meta Events Manager, e contiamo. Stesso intervallo di date, stessi due numeri messi uno accanto all’altro.
Nella maggior parte dei casi il numero di WooCommerce è più alto. A volte del 10%, a volte del 40%.
A quel punto il cliente dice sempre la stessa cosa: “eh, gli ad blocker”. E gli ad blocker c’entrano, ma sono raramente il colpevole principale. Il colpevole principale è molto più banale e molto più facile da sistemare: il tuo evento di acquisto vive sulla pagina di ringraziamento, e una parte dei tuoi clienti su quella pagina non ci arriva mai.
Vediamo come si rompe, perché nessun plugin te lo risolve, e come si sistema davvero.
Come funziona solitamente il tracking su WooCommerce?
Il 99% delle installazioni WooCommerce traccia l’acquisto così: il cliente completa l’ordine, WooCommerce lo manda sulla pagina `order-received`, e su quella pagina parte uno script che dice a Meta, a GA4 e a Google Ads “è arrivata una vendita da 84 euro”.
Funziona. Finché il cliente arriva su quella pagina.
Il problema è che il tuo evento di acquisto non è agganciato all’ordine. È agganciato a una visualizzazione di pagina. Sono due cose diverse, e nel momento in cui si scollano tu perdi il dato.
I cinque punti dove si creano i problemi
1. Il pagamento avviene fuori dal tuo sito. PayPal, Stripe con redirect, Nexi, Satispay, MyBank. Il cliente paga su un dominio che non è il tuo, e poi *dovrebbe* tornare indietro. Se chiude la scheda, se la connessione salta, se il redirect di ritorno va in timeout: l’ordine viene registrato come pagato tramite webhook lato server, ma il browser non ha mai visto la thank you page. Ordine sì, evento no.
2. Il 3DS su mobile. Il cliente viene sbalzato nell’app della banca per confermare il pagamento. Conferma. Poi però non torna nel browser: chiude l’app della banca e va avanti con la sua vita. Pagamento incassato, evento perso. Questo scenario, sul traffico mobile italiano, pesa più di quanto immagini.
3. Il bonifico e il contrassegno. Qui il problema è opposto e più insidioso. Il cliente arriva sulla thank you page, l’evento parte, tu registri una conversione da 300 euro. Poi il bonifico non arriva mai. Hai appena insegnato all’algoritmo di Meta a cercare altre persone come quella che non paga.
4. L’ordine che cambia stato dopo. Ordine in attesa, poi verificato manualmente, poi completato tre giorni dopo. Il pagamento è reale, la vendita è reale, l’evento è partito nel momento sbagliato o non è partito affatto.
5. E sì, anche gli ad blocker. Che però bloccano lo script sulla thank you page, non l’ordine. Che è esattamente il punto di tutto questo articolo.
“Ma ho già installato un plugin…”
Quasi tutti i plugin di tracking per WooCommerce fanno la stessa cosa che facevi tu a mano: sparano l’evento dalla pagina `order-received`. Alcuni lo mandano anche via Conversion API, e sembra una soluzione, ma se l’innesco è sempre la visualizzazione della pagina hai solo cambiato il mezzo di trasporto, non il momento in cui parte il dato.
Server-side non significa “passo dal server invece che dal browser”.
Significa cambiare cosa scatena l’evento: non più una pagina vista, ma un ordine che diventa pagato.

L’evento deve seguire l’ordine
WooCommerce sa perfettamente quando un ordine è stato pagato. Lo sa perché il gateway gli manda un webhook, e lo sa indipendentemente da dove sia il browser del cliente in quel momento, anche se quel browser è chiuso da venti minuti.
Quindi l’evento di acquisto va agganciato lì, in due distinte fasi:
– Al checkout salvi sull’ordine gli identificatori che ti servono per dire alle piattaforme *chi* è questa persona.
– Al pagamento confermato invii l’evento, una volta sola, usando quegli identificatori.
Sembra ovvio. Non lo fa quasi nessuno.
Fase 1: salvare gli identificatori mentre ci sono ancora
Questo è il passaggio che spesso le persone sbagliano. Puoi mandare tutti gli eventi server-side che vuoi, ma se dentro non c’è nulla che identifichi l’utente, Meta e GA4 li ricevono e non sanno a chi attribuirli.
Risultato: conversioni che finiscono in “diretto”, Event Match Quality a terra, campagne che ottimizzano su niente.
I cookie di tracciamento esistono nel browser al momento del checkout. Quello è il tuo unico momento utile per fotografarli.
add_action( 'woocommerce_checkout_create_order', 'gh_salva_identificatori', 10, 2 );
add_action( 'woocommerce_store_api_checkout_update_order_from_request', 'gh_salva_identificatori', 10, 2 );
function gh_salva_identificatori( $order, $data ) {
$cookie_map = [
'_fbp' => '_gh_fbp', // browser id Meta
'_fbc' => '_gh_fbc', // click id Meta (derivato da fbclid)
'_ga' => '_gh_ga', // client_id GA4
];
foreach ( $cookie_map as $cookie => $meta_key ) {
if ( ! empty( $_COOKIE[ $cookie ] ) ) {
$order->update_meta_data(
$meta_key,
sanitize_text_field( wp_unslash( $_COOKIE[ $cookie ] ) )
);
}
}
// Meta richiede IP e user agent per fare il match: senza questi la qualità dell'evento crolla
$order->update_meta_data( '_gh_client_ip', WC_Geolocation::get_ip_address() );
$order->update_meta_data( '_gh_user_agent', substr( wc_get_user_agent(), 0, 255 ) );
}
Fase 2: inviare l’evento quando l’ordine diventa pagato
add_action( 'woocommerce_payment_complete', 'gh_invia_purchase', 20 );
add_action( 'woocommerce_order_status_processing', 'gh_invia_purchase', 20 );
add_action( 'woocommerce_order_status_completed', 'gh_invia_purchase', 20 );
function gh_invia_purchase( $order_id ) {
$order = wc_get_order( $order_id );
if ( ! $order ) {
return;
}
// semaforo: se l'abbiamo già mandato, si esce. Senza questo controllo
// i due hook sopra ti raddoppiano gli acquisti.
if ( $order->get_meta( '_gh_purchase_inviato' ) ) {
return;
}
$h = function ( $v ) {
$v = preg_replace( '/\s+/', '', mb_strtolower( trim( (string) $v ), 'UTF-8' ) );
return '' === $v ? null : hash( 'sha256', $v );
};
// telefono in E.164 senza "+": 333 123 4567 -> 393331234567
$phone = preg_replace( '/\D/', '', $order->get_billing_phone() );
if ( $phone && 0 !== strpos( $phone, '39' ) ) {
$phone = '39' . ltrim( $phone, '0' );
}
$payload = [
'event_name' => 'Purchase',
'event_id' => 'wc_' . $order->get_id(), // deterministico: serve per la deduplica
'event_time' => $order->get_date_paid() ? $order->get_date_paid()->getTimestamp() : time(),
'action_source' => 'website',
'event_source_url' => $order->get_checkout_order_received_url(),
'value' => (float) $order->get_total(),
'currency' => $order->get_currency(),
'fbp' => $order->get_meta( '_gh_fbp' ),
'fbc' => $order->get_meta( '_gh_fbc' ),
'client_ip' => $order->get_meta( '_gh_client_ip' ),
'user_agent' => $order->get_meta( '_gh_user_agent' ),
'em' => $h( $order->get_billing_email() ),
'ph' => $h( $phone ),
'fn' => $h( $order->get_billing_first_name() ),
'ln' => $h( $order->get_billing_last_name() ),
'email_hash' => hash( 'sha256', strtolower( trim( $order->get_billing_email() ) ) ),
];
// Mandalo al tuo container server-side, non direttamente a Meta:
// così un solo invio alimenta Meta, GA4, Google Ads e quello che aggiungerai domani.
wp_remote_post( 'https://gtm.tuodominio.it/wc-purchase', [
'timeout' => 5,
'blocking' => false,
'headers' => [ 'Content-Type' => 'application/json' ],
'body' => wp_json_encode( $payload ),
] );
$order->update_meta_data( '_gh_purchase_inviato', current_time( 'mysql' ) );
$order->save();
}
Perché due hook? Perché `woocommerce_payment_complete` non scatta per i metodi che mettono l’ordine in attesa, tipo il bonifico. Con `order_status_completed` copri anche quelli, e il flag semaforo evita che un ordine passi due volte.
Ora potresti avere eventi di acquisto doppi
Adesso hai due potenziali sorgenti per lo stesso acquisto: il pixel sulla thank you page e il tuo evento server-side.
Meta considera duplicati due eventi con stesso `event_name` e stesso `event_id` ricevuti a distanza ravvicinata (la finestra dichiarata è di 48 ore). Se usi `wc_{order_id}` da entrambe le parti, nella maggior parte dei casi la deduplica funziona.
Nella maggior parte. Non sempre. Un ordine pagato con bonifico che tu completi dopo quattro giorni genera un evento server-side fuori dalla finestra: il pixel l’ha già contato al checkout, tu lo conti di nuovo, e adesso hai un ROAS che ti fa prendere decisioni sbagliate in senso opposto.
Il consiglio secco: scegli una sola fonte di verità per l’acquisto.
Se implementi il server-side per bene, l’evento `Purchase` sulla thank you page puoi anche spegnerlo. Tutti gli altri eventi del funnel (`view_content`, `add_to_cart`, `begin_checkout`) restano dove sono.
È l’acquisto che ha bisogno di un solo padrone.
Ultimo passo: la verifica del tutto
Non fidarti della sensazione. Fai queste quattro cose:
1. Conta. Ordini WooCommerce vs acquisti in Meta vs acquisti in GA4, stesso intervallo. Prima e dopo. Se la forbice non si stringe, non hai risolto niente.
2. Fai un ordine di prova con bonifico e chiudi la scheda subito dopo aver premuto il pulsante. Poi segna l’ordine come completato dal backend. L’evento deve arrivare.
3. Controlla l’Event Match Quality in Events Manager sull’evento Purchase. Se il server-side è fatto bene sale, perché stai passando email hashata, IP e user agent. Se scende, i tuoi identificatori sono vuoti e qualcosa non è stato implementato correttamente.
4. Guarda il meta `_gh_purchase_inviato`. Deve esserci su tutti quelli pagati, una volta sola.
Ricorda
Se spendi meno di 1.000 euro al mese in advertising, il costo di implementazione e mantenimento non si giustifica. Sistema prima le basi: eventi e-commerce mappati, GA4 configurato, conversioni importate correttamente in Google Ads.
Noi questa cosa la facciamo per lavoro, siamo Stape Partner certificati e sviluppiamo in WordPress da prima che il server-side diventasse una parola da vendere in slide.






