Google Consent Mode in un custom pixel di Shopify (gtag.js)
Panoramica
Alcuni store caricano Google Analytics 4 (G-) o Google Ads (AW-) direttamente con gtag.js da un Shopify custom pixel (Settings > Customer events). Questo articolo ti fornisce codice pronto da incollare nel pixel, che applica Google Consent Mode Advanced a queste proprietà, usando il consenso che i visitatori danno sul banner di Pandectes.
Se le tue proprietà Google sono caricate da un container di Google Tag Manager, usa invece Google Consent Mode in un custom pixel di Shopify (Google Tag Manager).
Questa è una guida all'implementazione. Per i fondamenti sui comandi default e update e sulla modalità Advanced, consulta Consent Mode con gtag.js della documentazione di Google.
Prima di iniziare
Prima attiva l'integrazione di Google Consent Mode
Questo pixel è una metà di una configurazione in due parti. Nel Shopify Admin vai su Apps > Pandectes GDPR > Integrations, clicca su Configure nella scheda Google Consent Mode e attiva l'integrazione. Vedi Uso dell'integrazione Google Consent Mode. Google Consent Mode funziona con il piano Plus e superiori.
Un custom pixel di Shopify viene eseguito in un iframe sandbox con il proprio window, il proprio dataLayer e una copia di gtag.js. È separato dalla pagina dello storefront, e il consenso impostato in uno è invisibile all'altro. Quindi ciascuno richiede la propria configurazione:
theme.liquid, il tuo container GTM, tag di altre app | L'integrazione Pandectes Google Consent ModeSandbox del pixel | Il gtag.js che carichi nel pixel e le sue proprietà | Il codice di questo articoloUsi Google Tag Manager?
Se il tuo store ha un container GTM, verifica se le tue proprietà Google sono già caricate lì. Di solito lo sono. Aggiungere un pixel che carica di nuovo la stessa proprietà GA4 o Google Ads duplica visualizzazioni di pagina, sessioni, acquisti e conversioni, e crea due stati di consenso in competizione.
| GA4 o Google Ads caricati da un container GTM | Google Consent Mode in un custom pixel di Shopify (Google Tag Manager) |Senza GTM, proprietà caricate con
gtag.js in un custom pixel | Questo articoloCosa copre questo codice
Il codice imposta solo lo stato del consenso. Invia a Google la policy predefinita dello store, applica la scelta del visitatore, la tiene sincronizzata con il banner e carica il tag Google, così i segnali di consenso hanno una destinazione. Da solo non invia dati di analytics o di conversione.
Le tue iscrizioni agli eventi vanno nello stesso pixel
Inviare a Google gli eventi clienti di Shopify è lo scopo reale del pixel, e quelle iscrizioni devono stare nello stesso pixel, sotto il codice del consenso. Gli esempi in ogni snippet sono commentati di proposito. Decommentali o sostituiscili con i tuoi.
Ogni pixel che carica una proprietà Google ha bisogno della propria copia
Non puoi mettere il codice del consenso in un custom pixel e i tuoi eventi in un altro. Ogni pixel è un sandbox separato. Un pixel che carica GA4 o Google Ads senza il codice del consenso invia tutto con i valori predefiniti di Google, come se la modalità di consenso non esistesse, e Shopify non ti avvisa.
- Un pixel carica le tue proprietà: una copia del codice, con gli eventi di quel pixel sotto.
- Tre pixel caricano ciascuno una proprietà Google: tre copie, una in ogni pixel.
- Se più pixel caricano la stessa proprietà, risolvi prima questa duplicazione.
Modalità Advanced e permesso del pixel
Questo codice ti dà la Google Consent Mode Advanced: il tag Google si carica a ogni visualizzazione di pagina, invia ping senza cookie finché il consenso è negato e passa alla misurazione completa una volta concesso il consenso. È ciò che permette a Google di modellare le conversioni dei visitatori che non acconsentono.
Per questo il pixel deve poter essere eseguito prima del consenso. Nel Shopify Admin vai su Settings > Customer events, apri il tuo custom pixel e, in Customer privacy, imposta Permission su Not required. Se lo imposti su Required, Shopify trattiene il pixel finché il visitatore non accetta: il tag Google non si carica mai prima del consenso e non vengono inviati ping senza cookie.
Se preferisci Basic mode (niente si carica finché non viene dato il consenso), non ti serve questo codice. Imposta Permission su Required, seleziona le categorie che ti servono e lascia che Shopify trattenga il pixel.
Come funziona il codice
Shopify fornisce al pixel il consenso del visitatore in init.customerPrivacy, ma non dice se si tratta del valore predefinito dello store o di una scelta che il visitatore aveva già fatto. Quindi il codice esegue sempre questi passaggi, in quest'ordine:
consentdefault: la policy dello store, scritta nel codice.consentupdate: quello che contieneinit.customerPrivacy. Se era solo il valore predefinito, non cambia nulla. Se era una scelta salvata, viene applicata prima del primo hit.- Carica
gtag.jse configura le tue proprietà Google. - Resta in ascolto di
visitorConsentCollectede invia unupdateogni volta che il visitatore cambia la sua scelta.
In un custom pixel, analytics, browser e init sono disponibili direttamente, ma customerPrivacy si raggiunge tramite api. Chiamare customerPrivacy.subscribe(...) senza api. genera un ReferenceError.
I valori di consenso di Shopify corrispondono ai tipi di consenso di Google così:
|
|
|---|---|
|
|
|
|
| Nessun equivalente in Consent Mode. È un segnale statunitense di vendita o condivisione per stato (vedi |
(sempre) |
|
Quale snippet ti serve?
Entrambi gli snippet supportano GA4, Google Ads o entrambi.
- Nel Shopify Admin vai su Settings > Customer events e clicca su Add custom pixel.
- Dai un nome al pixel e incolla uno degli snippet.
- Inserisci i tuoi ID tra
START_MODIFY_FOR_YOUR_STOREeEND_MODIFY_FOR_YOUR_STORE. - Aggiungi in fondo le tue iscrizioni agli eventi.
- Imposta il permesso come descritto sopra, clicca su Save, poi su Connect.
Snippet 1: un solo comando predefinito
Un comando default senza regione, quindi si applica a ogni visitatore. Tutto è negato tranne security_storage.
/* START_MODIFY_FOR_YOUR_STORE */
const GA4_ID = ""; // e.g. "G-XXXXXXXXXX", leave empty if not used
const AW_ID = ""; // e.g. "AW-XXXXXXXXXX", leave empty if not used
const DEBUG = false; // true sends GA4 hits to DebugView while testing
/* END_MODIFY_FOR_YOUR_STORE */
const GRANTED = "granted";
const DENIED = "denied";
const GOOGLE_URL = "https://www.googletagmanager.com/gtag/js?id=";
const DEVELOPER_ID = "dMTZkMj";
/* Shopify customerPrivacy -> Google consent state */
const toConsentState = (cp) => ({
ad_storage: cp.marketingAllowed ? GRANTED : DENIED,
ad_user_data: cp.marketingAllowed ? GRANTED : DENIED,
ad_personalization: cp.marketingAllowed ? GRANTED : DENIED,
analytics_storage: cp.analyticsProcessingAllowed ? GRANTED : DENIED,
functionality_storage: cp.preferencesProcessingAllowed ? GRANTED : DENIED,
personalization_storage: cp.preferencesProcessingAllowed ? GRANTED : DENIED,
security_storage: GRANTED,
});
/* The pixel sandbox has its own dataLayer. */
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
/* Pandectes developer ID. Identifies the implementation to Google,
* has no effect on your data. Leave it as it is. */
gtag("set", `developer_id.${DEVELOPER_ID}`, true);
/* STEP 1: store policy, before gtag.js loads. Applies to everyone. */
gtag("consent", "default", {
ad_storage: DENIED,
ad_user_data: DENIED,
ad_personalization: DENIED,
analytics_storage: DENIED,
functionality_storage: DENIED,
personalization_storage: DENIED,
security_storage: GRANTED,
});
/* STEP 2: visitor state, always sent. If it is only the default,
* nothing changes. If it is a saved choice, it lands before the first hit. */
gtag("consent", "update", toConsentState(init.customerPrivacy));
/* STEP 3: load the Google tag once and configure each property. */
const TAG_IDS = [GA4_ID, AW_ID].filter(Boolean);
if (TAG_IDS.length) {
gtag("js", new Date());
if (GA4_ID) {
gtag("config", GA4_ID, {
send_page_view: false,
...(DEBUG ? { debug_mode: true } : {}),
});
}
if (AW_ID) {
gtag("config", AW_ID);
}
const script = document.createElement("script");
script.async = true;
script.src = GOOGLE_URL + TAG_IDS[0];
document.head.appendChild(script);
}
/* STEP 4: follow the visitor's choices. Note the api. prefix. */
api.customerPrivacy.subscribe("visitorConsentCollected", (event) => {
gtag("consent", "update", toConsentState(event.customerPrivacy));
});
/* YOUR EVENT SUBSCRIPTIONS GO HERE, IN THIS SAME PIXEL.
* The examples are commented out on purpose. What you send is yours
* to own and verify. */
/* Page view: only if the storefront does not already send page_view
* for the same property, or it is counted twice. */
// analytics.subscribe("page_viewed", (event) => {
// gtag("event", "page_view", {
// page_path: event.context.document.location.pathname,
// page_title: event.context.document.title,
// page_location: event.context.window.location.href,
// });
// });
/* Purchase: if GA4 and Google Ads are linked, import the GA4 purchase
* as a conversion in Google Ads and delete the conversion block below,
* or every order is counted twice. */
// analytics.subscribe("checkout_completed", (event) => {
// const checkout = event.data.checkout;
// const items = checkout.lineItems.map((line) => ({
// item_id: "shopify_" + line.variant.product.id + "_" + line.variant.id,
// item_name: line.title,
// item_variant: line.variant.title,
// price: line.variant.price.amount,
// quantity: line.quantity,
// }));
//
// gtag("event", "purchase", {
// transaction_id: checkout.token,
// currency: checkout.currencyCode,
// value: checkout.totalPrice.amount,
// tax: checkout.totalTax.amount,
// shipping: checkout.shippingLine ? checkout.shippingLine.price.amount : 0,
// items: items,
// });
//
// // Google Ads conversion, ONLY when GA4 and Google Ads are NOT linked.
// // Use the conversion label from your Google Ads conversion action.
// gtag("event", "conversion", {
// send_to: "AW-XXXXXXXXXX/AbC-D_efGhIjKlMnOp",
// transaction_id: checkout.token,
// currency: checkout.currencyCode,
// value: checkout.totalPrice.amount,
// });
// });
Snippet 2: comandi predefiniti per regione
Per gli store che raccolgono il consenso solo dove è richiesto per legge. Ci sono due comandi default: uno globale che concede tutto e uno per le regioni elencate che nega tutto tranne security_storage. Quando entrambi corrispondono a un visitatore, vince la regione più specifica.
Il resto è identico allo Snippet 1.
/* START_MODIFY_FOR_YOUR_STORE */
const GA4_ID = ""; // e.g. "G-XXXXXXXXXX", leave empty if not used
const AW_ID = ""; // e.g. "AW-XXXXXXXXXX", leave empty if not used
/* ISO 3166-2 codes where the store collects consent: EEA + UK below.
* Add US states ("US-CA", "US-CO", ...) if you treat them as opt-in.
* This list MUST match the regions where your banner collects consent. */
const RESTRICTED_REGIONS = [
"AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR",
"DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL",
"PL", "PT", "RO", "SK", "SI", "ES", "SE", "GB", "LI", "NO", "IS",
];
const DEBUG = false; // true sends GA4 hits to DebugView while testing
/* END_MODIFY_FOR_YOUR_STORE */
const GRANTED = "granted";
const DENIED = "denied";
const GOOGLE_URL = "https://www.googletagmanager.com/gtag/js?id=";
const DEVELOPER_ID = "dMTZkMj";
/* Shopify customerPrivacy -> Google consent state */
const toConsentState = (cp) => ({
ad_storage: cp.marketingAllowed ? GRANTED : DENIED,
ad_user_data: cp.marketingAllowed ? GRANTED : DENIED,
ad_personalization: cp.marketingAllowed ? GRANTED : DENIED,
analytics_storage: cp.analyticsProcessingAllowed ? GRANTED : DENIED,
functionality_storage: cp.preferencesProcessingAllowed ? GRANTED : DENIED,
personalization_storage: cp.preferencesProcessingAllowed ? GRANTED : DENIED,
security_storage: GRANTED,
});
/* The pixel sandbox has its own dataLayer. */
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
/* Pandectes developer ID. Identifies the implementation to Google,
* has no effect on your data. Leave it as it is. */
gtag("set", `developer_id.${DEVELOPER_ID}`, true);
/* STEP 1a: policy for everyone outside the listed regions. */
gtag("consent", "default", {
ad_storage: GRANTED,
ad_user_data: GRANTED,
ad_personalization: GRANTED,
analytics_storage: GRANTED,
functionality_storage: GRANTED,
personalization_storage: GRANTED,
security_storage: GRANTED,
});
/* STEP 1b: policy for the listed regions. Google resolves the region
* from the IP address, so test it with a VPN. */
gtag("consent", "default", {
ad_storage: DENIED,
ad_user_data: DENIED,
ad_personalization: DENIED,
analytics_storage: DENIED,
functionality_storage: DENIED,
personalization_storage: DENIED,
security_storage: GRANTED,
region: RESTRICTED_REGIONS,
});
/* STEP 2: visitor state, always sent. Shopify has already applied your
* regional settings to init.customerPrivacy, so this matches 1a or 1b. */
gtag("consent", "update", toConsentState(init.customerPrivacy));
/* STEP 3: load the Google tag once and configure each property. */
const TAG_IDS = [GA4_ID, AW_ID].filter(Boolean);
if (TAG_IDS.length) {
gtag("js", new Date());
if (GA4_ID) {
gtag("config", GA4_ID, {
send_page_view: false,
...(DEBUG ? { debug_mode: true } : {}),
});
}
if (AW_ID) {
gtag("config", AW_ID);
}
const script = document.createElement("script");
script.async = true;
script.src = GOOGLE_URL + TAG_IDS[0];
document.head.appendChild(script);
}
/* STEP 4: follow the visitor's choices. Note the api. prefix. */
api.customerPrivacy.subscribe("visitorConsentCollected", (event) => {
gtag("consent", "update", toConsentState(event.customerPrivacy));
});
/* YOUR EVENT SUBSCRIPTIONS GO HERE, IN THIS SAME PIXEL.
* Use the same page view and purchase examples as in Snippet 1. */
Verifica che funzioni
Tag Assistant non vede il pixel
Google Tag Assistant ispeziona solo la pagina dello storefront. Il gtag, il dataLayer e le proprietà del pixel vivono in un iframe sandbox che non raggiunge, quindi non riporta nulla (o solo i tag dello storefront) anche quando il pixel funziona correttamente. È un comportamento previsto e non è un errore.
Controlla il dataLayer nel frame del pixel
- Apri Chrome DevTools e vai alla scheda Console.
- Nella barra degli strumenti della console apri il menu a tendina dei frame (di solito mostra
top) e seleziona il frame sandbox del pixel (il cui nome inizia conweb-pixel). Shopify crea un frame per ogni custom pixel, quindi scegli quello giusto se ne hai più di uno. - Esegui i controlli qui sotto.
Nel frame top, dataLayer è il dataLayer dello storefront, che non dice nulla sul pixel.
- I valori predefiniti vengono prima? In
dataLayer, le vociconsentdevono comparire prima delle vociconfig. - Il consenso arriva al tag? Imposta
DEBUG = true, decommenta un evento in modo che venga inviato qualcosa, e apri GA4 DebugView. Conanalytics_storagenegato vedi un ping senza cookie invece di un hit normale. - Il pixel si carica prima del consenso? Deve farlo, per la modalità Advanced. Se il tag Google compare solo dopo che il visitatore ha accettato, il permesso del pixel è impostato su Required e sei in modalità Basic.
- La logica per regione funziona? Prova con una VPN dentro e fuori da un paese elencato.
- L'iscrizione si attiva? Aggiungi temporaneamente un
console.logdentro la callbackvisitorConsentCollectede cambia la tua scelta sul banner.
Errori comuni
Errore | Cosa succede |
|---|---|
Codice del consenso in un pixel, eventi in un altro | Il pixel degli eventi non ha |
Più pixel caricano una proprietà Google, solo uno ha il codice del consenso | Gli altri inviano senza alcuna modalità di consenso, senza avvisi. |
Pixel Permission impostato su Required | Il tag non si carica mai prima del consenso: nessun ping senza cookie e nessuna modellazione. Questa è la modalità Basic. |
Evento | Ogni ordine viene conteggiato due volte in Google Ads. |
|
|
Saltare il | I visitatori di ritorno con un consenso salvato ricevono tag negati già alla prima visualizzazione di pagina. |
| La modalità di consenso non viene applicata ai primi hit. |
Integrazione Google Consent Mode non attivata in Pandectes | Solo le proprietà del pixel ricevono la modalità di consenso. I tag Google dello storefront girano senza. |
Pixel creato mentre GTM carica già la stessa proprietà | Visualizzazioni di pagina, sessioni, acquisti e conversioni duplicati, più due stati di consenso. |
Test con Tag Assistant o lettura di | Nessuno dei due guarda dentro il sandbox del pixel. |
| Compromette i segnali di prevenzione delle frodi senza alcun vantaggio in termini di conformità. |
| Il valore predefinito e l'aggiornamento non coincidono. Vince l'aggiornamento e la policy per regione viene ignorata. |
Impostazioni che questo articolo non copre
Gli snippet non includono le impostazioni a livello di account di Google, quindi si applicano i valori predefiniti di Google:
url_passthrough | Se gli ID di clic degli annunci, come GCLID, vengono passati nell'URL tra una pagina e l'altra quando i cookie non possono essere impostatiads_data_redaction | Se gli ID di clic degli annunci vengono rimossi dai ping senza cookie mentre ad_storage è negatoallow_enhanced_conversions | Se possono essere inviati dati cliente sottoposti ad hash con le conversionirestricted_data_processing | La restrizione statunitense di vendita o condivisione per stato, legata a saleOfDataAllowed di Shopifywait_for_update | Quanto a lungo i tag attendono un aggiornamento del consenso prima di attivarsiPandectes non può consigliarti su queste impostazioni. I valori giusti dipendono dai tuoi account Google, dal modello di attribuzione su cui fai affidamento e dalla posizione legale della tua attività. Discutine con chi gestisce la tua configurazione Google o, se c'è una questione di privacy, con il tuo consulente legale.
Se decidi di impostarne una, aggiungila come chiamata gtag("set", ...) prima dei comandi consent default:
// gtag("set", "url_passthrough", true);
// gtag("set", "ads_data_redaction", true);
wait_for_update è l'eccezione: va dentro un comando default. Questi snippet non ne hanno bisogno, perché init.customerPrivacy è disponibile subito e update viene inviato subito dopo i valori predefiniti.
Aggiornato il: 30/10/2026
Grazie!
