Artículos sobre: Integraciones
Este artículo también está disponible en:

Google Consent Mode en un píxel personalizado de Shopify (gtag.js)

Resumen


Algunas tiendas cargan Google Analytics 4 (G-) o Google Ads (AW-) directamente con gtag.js desde un Shopify custom pixel (Settings > Customer events). Este artículo te da código de píxel listo para pegar que aplica Google Consent Mode Advanced a esas propiedades, usando el consentimiento que tus visitantes dan en el banner de Pandectes.


Si tus propiedades de Google las carga un contenedor de Google Tag Manager, usa en su lugar Google Consent Mode en un píxel personalizado de Shopify (Google Tag Manager).


Esto es una guía de implementación. Para información de base sobre los comandos default y update y sobre el modo Advanced, consulta Consent Mode con gtag.js de Google.


Antes de empezar



Este píxel es una mitad de una configuración en dos partes. En Shopify Admin, ve a Apps > Pandectes GDPR > Integrations, haz clic en Configure en la tarjeta Google Consent Mode y activa la integración. Consulta Usar la integración de Google Consent Mode. Google Consent Mode funciona en el plan Plus y superiores.


Un píxel personalizado de Shopify se ejecuta en un iframe aislado con su propio window, dataLayer y copia de gtag.js. Está separado de la página de la tienda, y el consentimiento configurado en uno es invisible para el otro. Por eso cada uno necesita su propia configuración:


Dónde

Qué se ejecuta allí

Qué configura el modo de consentimiento

Página de la tienda

Etiquetas de Google en theme.liquid, tu contenedor de GTM, etiquetas de otras apps

La integración de Pandectes Google Consent Mode

Sandbox del píxel

La gtag.js que cargas en el píxel y sus propiedades

El código de este artículo


El píxel no sustituye a la integración. Nada en el píxel puede llegar a la página de la tienda, así que sin la integración tu tienda no tiene ningún modo de consentimiento.


¿Usas Google Tag Manager?


Si tu tienda tiene un contenedor de GTM, comprueba si tus propiedades de Google ya se cargan ahí. Normalmente sí. Añadir un píxel que vuelve a cargar la misma propiedad de GA4 o Google Ads duplica tus visualizaciones de página, sesiones, compras y conversiones, y crea dos estados de consentimiento en competencia.


Tu configuración | Sigue--- | --- |

GA4 o Google Ads cargados por un contenedor de GTM

Google Consent Mode en un píxel personalizado de Shopify (Google Tag Manager)

Sin GTM, propiedades cargadas con gtag.js en un píxel personalizado

Este artículo


Qué cubre este código


El código configura el estado de consentimiento y nada más. Envía a Google la política por defecto de la tienda, aplica la elección del visitante, la mantiene sincronizada con el banner y carga la etiqueta de Google para que las señales de consentimiento tengan adónde ir. No envía datos de analítica ni de conversiones por sí mismo.


Pandectes solo proporciona la capa de consentimiento. Qué eventos envías, qué datos llevan, cómo se asignan a tu propiedad de GA4 o a tus conversiones de Google Ads y si tus informes son precisos son responsabilidad tuya. Pandectes no da soporte ni verifica el seguimiento construido sobre este código.


Tus suscripciones a eventos van en el mismo píxel


Enviar los eventos de clientes de Shopify a Google es el verdadero propósito del píxel, y esas suscripciones deben estar en el mismo píxel, debajo del código de consentimiento. Los ejemplos de cada fragmento están comentados a propósito. Descoméntalos o sustitúyelos por los tuyos.


Cada píxel que cargue una propiedad de Google necesita su propia copia


No puedes poner el código de consentimiento en un píxel personalizado y tus eventos en otro. Cada píxel es un sandbox separado. Un píxel que carga GA4 o Google Ads sin el código de consentimiento dispara todo con los valores por defecto de Google, como si no existiera ningún modo de consentimiento, y Shopify no te avisa.


  • Un píxel carga tus propiedades: una copia del código, con los eventos de ese píxel debajo.
  • Tres píxeles cargan una propiedad de Google cada uno: tres copias, una en cada píxel.
  • Si varios píxeles cargan la misma propiedad, corrige primero esa duplicación.


Modo Advanced y permiso del píxel


Este código te ofrece Google Consent Mode Advanced: la etiqueta de Google se carga en cada visualización de página, envía pings sin cookies mientras el consentimiento está denegado y pasa a medición completa cuando se concede. Así es como Google puede modelar las conversiones de los visitantes que no dan su consentimiento.


Para eso, el píxel debe poder ejecutarse antes del consentimiento. En Shopify Admin, ve a Settings > Customer events, abre tu píxel personalizado y, en Customer privacy, configura Permission como Not required. Si lo configuras como Required, Shopify retiene el píxel hasta que el visitante acepta, así que la etiqueta de Google nunca se carga antes del consentimiento y no se envía ningún ping sin cookies.


Si quieres Basic mode (nada se carga hasta que se da el consentimiento), no necesitas este código. Configura Permission como Required, selecciona las categorías que necesites y deja que Shopify retenga el píxel.


Cómo funciona el código


Shopify da al píxel el consentimiento del visitante en init.customerPrivacy, pero no indica si es el valor por defecto de la tienda o una elección que el visitante ya había hecho. Por eso el código siempre ejecuta estos pasos, en este orden:


  1. consent default: la política de la tienda, escrita en el código.
  2. consent update: lo que contenga init.customerPrivacy. Si solo era el valor por defecto, no cambia nada. Si era una elección guardada, se aplica antes del primer envío.
  3. Carga gtag.js y configura tus propiedades de Google.
  4. Escucha visitorConsentCollected y envía un update cada vez que el visitante cambie su elección.


En un píxel personalizado, analytics, browser y init están disponibles directamente, pero customerPrivacy se accede a través de api. Llamar a customerPrivacy.subscribe(...) sin api. genera un ReferenceError.


Los valores de consentimiento de Shopify se asignan a los tipos de consentimiento de Google así:


Shopify

Google

analyticsProcessingAllowed

analytics_storage

marketingAllowed

ad_storage, ad_user_data, ad_personalization

preferencesProcessingAllowed

functionality_storage, personalization_storage

saleOfDataAllowed

No tiene equivalente en Consent Mode. Es una señal de venta o compartición en estados de EE. UU. (ver restricted_data_processing).

(siempre)

security_storage es siempre granted


¿Qué fragmento necesito?


La política de tu tienda

Usa

Misma política en todo el mundo: nada se ejecuta hasta que el visitante da su consentimiento

Snippet 1 (un comando por defecto)

Consentimiento recogido solo en algunas regiones, permitido en el resto

Snippet 2 (comandos por defecto según región)


Ambos fragmentos admiten GA4, Google Ads o los dos.


  1. En Shopify Admin, ve a Settings > Customer events y haz clic en Add custom pixel.
  2. Dale un nombre al píxel y pega uno de los fragmentos.
  3. Escribe tus IDs entre START_MODIFY_FOR_YOUR_STORE y END_MODIFY_FOR_YOUR_STORE.
  4. Añade tus propias suscripciones a eventos al final.
  5. Configura el permiso como se describe arriba, haz clic en Save y luego en Connect.


Fragmento 1: un comando por defecto


Un comando default sin región, así que se aplica a todos los visitantes. Todo se deniega excepto 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,
// });
// });


Fragmento 2: comandos por defecto según región


Para tiendas que recogen el consentimiento solo donde la ley lo exige. Hay dos comandos default: uno global que concede todo, y otro para las regiones indicadas que deniega todo excepto security_storage. Cuando ambos coinciden con un visitante, gana la región más específica.


El resto es idéntico al Fragmento 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. */


Comprueba que funciona


Tag Assistant no puede ver el píxel


Google Tag Assistant solo inspecciona la página de la tienda. Las gtag, dataLayer y propiedades del píxel viven en un iframe aislado al que no llega, así que no muestra nada (o solo las etiquetas propias de la tienda) aunque el píxel funcione correctamente. Esto es lo esperado y no es un error.


Revisa el dataLayer en el frame del píxel


  1. Abre las DevTools de Chrome y ve a la pestaña Console.
  2. En la barra de herramientas de la consola, abre el desplegable de frames (normalmente muestra top) y selecciona el frame del sandbox del píxel (su nombre empieza por web-pixel). Shopify crea un frame por cada píxel personalizado, así que elige el correcto si tienes varios.
  3. Ejecuta las comprobaciones de abajo.


En el frame top, dataLayer es el dataLayer de la tienda, que no te dice nada sobre el píxel.


  • ¿Van primero los valores por defecto? En dataLayer, las entradas consent deben ir antes que las entradas config.
  • ¿Llega el consentimiento a la etiqueta? Configura DEBUG = true, descomenta un evento para que se envíe algo y abre DebugView de GA4. Con analytics_storage denegado verás un ping sin cookies en lugar de un envío normal.
  • ¿Se carga el píxel antes del consentimiento? Debe hacerlo para el modo Advanced. Si la etiqueta de Google solo aparece después de que el visitante acepte, el permiso del píxel está en Required y estás en modo Basic.
  • ¿Funciona la lógica por regiones? Prueba con una VPN dentro y fuera de un país de la lista.
  • ¿Se dispara la suscripción? Añade un console.log temporal dentro del callback visitorConsentCollected y cambia tu elección en el banner.


Errores habituales


Error

Qué ocurre

Código de consentimiento en un píxel, eventos en otro

El píxel de eventos no tiene gtag ni estado de consentimiento. Sus eventos no llegan a ningún sitio.

Varios píxeles cargan una propiedad de Google, pero solo uno tiene el código de consentimiento

Los demás se disparan sin modo de consentimiento y sin aviso.

Píxel Permission configurado en Required

La etiqueta nunca se carga antes del consentimiento: sin pings sin cookies ni modelado. Eso es modo Basic.

Evento de conversion de Ads enviado mientras la compra de GA4 también se importa como conversión

Cada pedido se cuenta dos veces en Google Ads.

customerPrivacy.subscribe(...) sin api.

ReferenceError. El consentimiento nunca se actualiza tras el banner.

Omitir update porque init.customerPrivacy parece el valor por defecto

Los visitantes que vuelven con consentimiento guardado reciben etiquetas denegadas en su primera visualización de página.

default enviado después de config

Consent Mode no se aplica a los primeros envíos.

La integración de Google Consent Mode no está activada en Pandectes

Solo las propiedades del píxel reciben el modo de consentimiento. Las etiquetas de Google de la tienda se ejecutan sin él.

Píxel creado mientras GTM ya carga la misma propiedad

Visualizaciones de página, sesiones, compras y conversiones duplicadas, además de dos estados de consentimiento.

Probar con Tag Assistant o leer dataLayer en el frame top

Ninguno mira dentro del sandbox del píxel.

security_storage denegado

Rompe las señales de prevención de fraude sin ningún beneficio de cumplimiento.

RESTRICTED_REGIONS no coincide con las regiones del banner

El valor por defecto y la actualización no coinciden. Gana la actualización y se ignora la política por regiones.


Ajustes que este artículo no cubre


Los fragmentos no incluyen los ajustes de cuenta de Google, así que se aplican sus valores por defecto:


Ajuste

Qué controla

url_passthrough

Si los ID de clic de anuncios, como GCLID, se pasan en la URL entre páginas cuando no se pueden establecer cookies

ads_data_redaction

Si los ID de clic de anuncios se eliminan de los pings sin cookies mientras ad_storage está denegado

allow_enhanced_conversions

Si se pueden enviar datos de cliente hasheados con las conversiones

restricted_data_processing

La restricción de venta o compartición en estados de EE. UU., relacionada con saleOfDataAllowed de Shopify

wait_for_update

Cuánto tiempo esperan las etiquetas una actualización de consentimiento antes de dispararse


Pandectes no puede asesorar sobre estos ajustes. Los valores correctos dependen de tus cuentas de Google, del modelado en el que confíes y de la situación legal de tu negocio. Coméntalo con quien gestione tu configuración de Google o con tu asesor legal si hay una cuestión de privacidad.


Si decides configurar alguno, añádelo como una llamada gtag("set", ...) antes de los comandos consent default:


// gtag("set", "url_passthrough", true);
// gtag("set", "ads_data_redaction", true);


wait_for_update es la excepción: va dentro de un comando default. Estos fragmentos no lo necesitan, porque init.customerPrivacy está disponible de inmediato y update se envía justo después de los valores por defecto.

Actualizado el: 30/10/2026

¿Este artículo te resultó útil?

Comparte tu opinión

Cancelar

¡Gracias!