How to check if your Consent Management Platform (CMP) is connected with Shopify Customer Privacy API
Shopify customer privacy API controls the behavior of all Shopify apps including ProfitMetrics. Follow the steps below in order to check if your Consent Management Platform (CMP) is connected with the Shopify customer privacy API .
Part 1: Check "Customer privacy" settings in Shopify
Part 2: Connect your third-party Consent Management Platform (CMP) with the Shopify Consent API
Part 3: Confirm your Consent Management Platform (CMP) is connected with the Shopify Customer Privacy API
Part 1: Check "Customer privacy" settings in Shopify
- Login to admin.shopify.com for your website
- Click "Settings"

- Click "Customer privacy"

- Click "Cookie banner"

- Identify if the "Cookie banner" is enabled and how
- If you see "Activate cookie banner" button - the Cookie banner is not enabled

- If you see the "Region visibility" and "Appearance" section - The native Shopify Cookie banner is enabled.

- If you only see the "Visibility" and "Region visibility" sections- A Third Party Cookie Banner is expected

- If you see "Activate cookie banner" button - the Cookie banner is not enabled
- Ensure the settings are as desired.
If you use the Shopify native Consent banner, then it should look like option "b" above. If you use a third-party app or Consent Management Platform like CookieInformation.com or cookiebot, it should look like option "c" above.
Part 2: Connect your third-party Consent Management Platform (CMP) with the Shopify Customer Privacy API
Cookiebot
CookieYesUsercentrics
Cookieinformation
Part 3: Confirm your Consent Management Platform (CMP) is connected with the Shopify Customer Privacy API
- Visit your website and make sure you grant consent in your Consent Management Platform (CMP)
- Right-click and Inspect the page

- Click on "Console"

- Copy and paste the following code in the console and press Enter
(async () => {
'use strict';
const TITLE = 'background:#111;color:#fff;font:bold 14px sans-serif;padding:6px 10px;border-radius:4px;';
const HEADING = 'background:#4f46e5;color:#fff;font:bold 13px sans-serif;padding:4px 8px;border-radius:3px;';
const NOTE = 'color:#6b7280;font-style:italic;';
const BAD = 'color:#dc2626;font-weight:bold;';
const WARN = 'color:#d97706;font-weight:bold;';
console.log('%cπ Shopify Consent & Privacy Diagnostic', TITLE);
// βββββββββββββββ 1. CONSENT MODE SETTINGS βββββββββββββββ
console.log('%c1. Consent Mode settings', HEADING);
console.log('%cUsed by Google tags for ads and analytics.', NOTE);
// ββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββ
const readIcs = (win) => {
try { return win.google_tag_data?.ics; } catch { return null; }
};
// Walk top + every reachable child frame (BFS). Sandboxed / cross-origin
// frames throw SecurityError on access β swallowed by readIcs / try-catch.
const findIcsAnywhere = () => {
let top = window;
try { while (top.parent && top.parent !== top) top = top.parent; } catch {}
const queue = [top];
const seen = new Set();
while (queue.length) {
const w = queue.shift();
if (seen.has(w)) continue;
seen.add(w);
const ics = readIcs(w);
if (ics?.entries) {
let label = 'this window';
if (w !== window) {
try { label = 'iframe: ' + w.location.href; }
catch { label = 'iframe (cross-origin)'; }
}
return { ics, source: label };
}
try { for (let i = 0; i < w.length; i++) queue.push(w[i]); } catch {}
}
return null;
};
// Fallback: reconstruct entries from dataLayer pushes.
// Catches the "defaults pushed in parent, gtag.js runs in sandboxed iframe"
// case (e.g. Shopify Web Pixels) where the iframe's window is opaque to us.
const reconstructFromDataLayer = (win = window) => {
const dl = win.dataLayer;
if (!Array.isArray(dl)) return null;
const entries = {};
for (const item of dl) {
if (!item || item[0] !== 'consent') continue;
const action = item[1]; // 'default' | 'update'
const settings = item[2];
if (!settings || typeof settings !== 'object') continue;
if (action !== 'default' && action !== 'update') continue;
for (const [k, v] of Object.entries(settings)) {
if (k === 'wait_for_update' || k === 'region') continue;
entries[k] ??= {};
entries[k][action] = v === 'granted';
}
}
return Object.keys(entries).length ? { entries, _reconstructed: true } : null;
};
// ββ Resolve ββββββββββββββββββββββββββββββββββββββββββββββ
const found = findIcsAnywhere();
const ics = found?.ics ?? reconstructFromDataLayer();
const entries = ics?.entries;
if (found) {
console.log(`%cSource: google_tag_data.ics from ${found.source}`, NOTE);
} else if (ics?._reconstructed) {
console.log('%cSource: reconstructed from dataLayer (no gtag.js reachable from this context β likely running inside a sandboxed iframe like Shopify Web Pixels)', NOTE);
}
const fmt = v => v === true ? 'β granted' : v === false ? 'β denied' : '';
const cats = {
ad_storage: 'Cookies for ads',
ad_user_data: 'Sending user data to Google for ads',
ad_personalization: 'Personalised / remarketing ads',
analytics_storage: 'Cookies for analytics',
functionality_storage: 'Storage for site functionality',
personalization_storage: 'Storage for personalisation',
security_storage: 'Storage for security'
};
if (!entries) {
console.log('%cβ Consent Mode is not configured. Google treats this user as denied for everything.', BAD);
} else {
let hasAnyDefault = false;
const table = {};
for (const [k, desc] of Object.entries(cats)) {
const e = entries[k];
const defVal = e?.default;
const updVal = e?.update;
if (defVal === undefined && updVal === undefined) {
table[k] = { Default: '', Current: '', 'What it covers': desc };
continue;
}
if (defVal !== undefined) hasAnyDefault = true;
const currentVal = updVal !== undefined ? updVal : defVal;
table[k] = { Default: fmt(defVal), Current: fmt(currentVal), 'What it covers': desc };
}
console.table(table);
if (!hasAnyDefault) console.log('%cβ οΈ No default consent set β anything firing before the update has no signal.', WARN);
}
// βββββββββββββββ 2. CUSTOMER PRIVACY SETTINGS βββββββββββββββ
console.log('%c2. Customer Privacy settings', HEADING);
console.log('%cUsed by Shopify pixels and apps.', NOTE);
// New-banner builds (e.g. Horizon) don't auto-attach customerPrivacy to
// window.Shopify. Force-load the legacy API if it's missing.
if (!window.Shopify?.customerPrivacy && typeof window.Shopify?.loadFeatures === 'function') {
await new Promise(resolve => {
window.Shopify.loadFeatures(
[{ name: 'consent-tracking-api', version: '0.1' }],
() => resolve()
);
});
}
const cp = window.Shopify?.customerPrivacy;
const safe = (fn) => { try { return typeof fn === 'function' ? fn() : undefined; } catch { return undefined; } };
if (!cp) {
console.log('%cβ Shopify Customer Privacy API not available. Re-run after the page finishes loading.', BAD);
} else {
const visitor = safe(cp.currentVisitorConsent?.bind(cp)) || {};
const fmtConsent = v => v === 'yes' ? 'β yes' : v === 'no' ? 'β no' : '';
const fmtTracked = v => v === true ? 'β true' : v === false ? 'β false' : '';
const table = {
marketing: { Status: fmtConsent(visitor.marketing), 'What it covers': 'Marketing pixels' },
analytics: { Status: fmtConsent(visitor.analytics), 'What it covers': 'Analytics tracking' },
preferences: { Status: fmtConsent(visitor.preferences), 'What it covers': 'User preferences' },
sale_of_data: { Status: fmtConsent(visitor.sale_of_data), 'What it covers': 'Selling / sharing data' },
userCanBeTracked: { Status: fmtTracked(safe(cp.userCanBeTracked?.bind(cp))), 'What it covers': 'Can you track this user?' }
};
console.table(table);
console.log('%cBlank = visitor has not made a decision yet (or no banner shown in their region).', NOTE);
}
})();
The output in the console breaks down both the Consent Mode and Shopify customer privacy settings.
Normally, the output may look something like the below screenshot before a consent choice is made, or when you click 'Deny'. 
And then, if the consent manager is connected correctly to the Shopify Customer Privacy API, the output should look something like the below screenshot once you click 'Accept':

If you have run the diagnostics in the console above and consent still is not flowing through correctly, or if you're unclear on how to read this information, please contact support@profitmetrics.io with a screenshot of the console output and we will help you investigate.