Skip to content

Instantly share code, notes, and snippets.

@ceaksan
Last active April 3, 2026 21:05
Show Gist options
  • Select an option

  • Save ceaksan/b30eade05d83b3e44a7e62924ac8ac2e to your computer and use it in GitHub Desktop.

Select an option

Save ceaksan/b30eade05d83b3e44a7e62924ac8ac2e to your computer and use it in GitHub Desktop.
Shopify Market Bridge: Consent-gated market cookie writer for Custom Pixels
/**
* Shopify Market Bridge - Consent-Gated Market Cookie Writer
*
* Writes Shopify Markets localization data (country, language, currency,
* market handle) to a cookie via storageHelper. This data is not available
* in the pixel sandbox init event, so the cookie acts as a bridge between
* the storefront (Theme App Extension) and Custom Pixel.
*
* Requires:
* 1. storageHelper (see companion gist)
* 2. Liquid snippet in theme (see below)
*
* Liquid snippet (Theme App Extension / App Embed Block):
*
* <script type="application/json" id="shopify-market-data">
* {
* "market": {
* "id": "{{ localization.market.id }}",
* "handle": "{{ localization.market.handle }}"
* },
* "country": "{{ localization.country.iso_code }}",
* "language": "{{ localization.language.iso_code }}",
* "locale": "{{ request.locale }}",
* "currency": "{{ cart.currency.iso_code }}",
* "shop": "{{ shop.permanent_domain }}"
* }
* </script>
*
* Note: localization.market cannot be serialized with | json filter
* ("json not allowed for this object"). Fields must be listed individually.
*
* Pixel-side reading (Custom Pixel, lax sandbox):
*
* var consentGranted = init.customerPrivacy.analyticsProcessingAllowed;
*
* analytics.subscribe("page_viewed", async function (event) {
* if (!consentGranted) return;
* var raw = await browser.cookie.get("_shopify_m");
* if (!raw) return;
* var market = JSON.parse(decodeURIComponent(raw));
* // market.country, market.currency, market.language, market.market.handle
* });
*
* Note: visitorConsentCollected is a storefront-only DOM event.
* It is NOT available in the pixel sandbox. Pixel reads consent
* from init.customerPrivacy which is fixed for the page lifetime.
*
* @see https://ceaksan.com/tr/shopify-markets-cookie-bridge-consent-aware-veri-koprusu
* @license MIT
*/
(function () {
var MARKET_KEY = "_shopify_m";
// --- Market Data ---
function getMarketData() {
var el = document.getElementById("shopify-market-data");
if (el) {
try {
return JSON.parse(el.textContent);
} catch (e) {
console.warn("[marketBridge] parse error:", e);
}
}
// Fallback: window.Shopify global (less reliable than Liquid)
if (typeof Shopify !== "undefined") {
return {
market: null,
country: Shopify.country || null,
language: Shopify.locale || null,
locale: Shopify.locale || null,
currency: Shopify.currency ? Shopify.currency.active : null,
shop: Shopify.shop || null,
};
}
return null;
}
// --- Consent-Gated Writer ---
function writeMarketData() {
var data = getMarketData();
if (!data) return;
if (!storageHelper.hasChanged(MARKET_KEY, data)) return;
storageHelper.set(MARKET_KEY, data, { maxAge: 2592000 });
}
function deleteMarketData() {
storageHelper.remove(MARKET_KEY);
}
// --- Consent Handler ---
var listenerAttached = false;
function onConsentChange() {
if (
typeof Shopify !== "undefined" &&
typeof Shopify.customerPrivacy !== "undefined" &&
Shopify.customerPrivacy.analyticsProcessingAllowed()
) {
writeMarketData();
} else {
deleteMarketData();
}
}
function attachConsentListener() {
if (listenerAttached) return;
// visitorConsentCollected: storefront-only DOM event
document.addEventListener("visitorConsentCollected", onConsentChange);
listenerAttached = true;
}
function handleConsent() {
if (
typeof Shopify === "undefined" ||
typeof Shopify.customerPrivacy === "undefined"
) {
attachConsentListener();
// Polling: customerPrivacy may load asynchronously
var attempts = 0;
var poll = setInterval(function () {
attempts++;
if (
typeof Shopify !== "undefined" &&
typeof Shopify.customerPrivacy !== "undefined"
) {
clearInterval(poll);
onConsentChange();
}
if (attempts >= 10) clearInterval(poll);
}, 500);
return;
}
onConsentChange();
attachConsentListener();
}
handleConsent();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment