Hi everyone,
I’m very close to finalizing my GA4 and Shopify integration but have hit a wall with sending a user-scoped Custom Dimension (shopify_customer_id) when loading GTM via a Custom Pixel.
The basic GA4 integration (via Google & YouTube app) is working. My goal is to send the Shopify Customer ID to GA4 as a User Property to enable cohort analysis.
What I Have Done
-
GA4 Custom Dimension:
-
I’ve set up a User-scoped Custom Dimension in GA4 (see screenshot 1).
-
Dimension Name:
shopify_customer_id -
Scope:
User -
User Property:
shopify_customer_id
-
-
GTM Setup (via Custom Pixel):
-
I am loading the GTM container using the standard GTM snippet inside a Custom Pixel.
-
I am NOT injecting GTM into
theme.liquidto ensure tracking works on the thank-you page (Checkout Extensibility).
-
-
Custom Pixel Code:
- My Custom Pixel loads GTM and then tries to send the Customer ID during the
initevent.
- My Custom Pixel loads GTM and then tries to send the Customer ID during the
Here is my current Custom Pixel code:
JavaScript
// Load GTM Container
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer', 'GTM-XXXXXXX'); // My GTM ID
// ... (Consent mode settings) ...
// Attempt to send Customer ID
analytics.subscribe('init', (event) => {
const customer = event.data.customer;
if (customer && customer.id) {
const customerId = String(customer.id);
// Send User Property directly to GA4
gtag('set', 'user_properties', {
'shopify_customer_id': customerId // Matches GA4 setup
});
// (I also tried sending a GTM event, but it didn't work)
// gtag('event', 'shopify_customer_id', {});
}
});
// ... (Other analytics.subscribe events like 'checkout_completed' using dataLayer.push) ...
The Problem
The shopify_customer_id user property is never received by GA4.
-
Standard events (like
page_viewed,checkout_completedwhich usedataLayer.push) are working correctly. -
Only the
gtag('set', 'user_properties', ...)call from theinitevent seems to fail. -
When using GTM Preview Mode, I do not see the
shopify_customer_idevent or any user properties being set on initialization.
My Hypothesis (The Core Question)
I believe this is a timing issue. The analytics.subscribe('init', ...) callback fires before the GTM snippet (gtm.js) has fully loaded and defined the global gtag function. This results in a “gtag is not a function” error, and the command is lost.
I tried to fix this by creating a polling function to wait for gtag (based on an old implementation I had), but it also doesn’t seem to work reliably in the pixel:
JavaScript
// My attempt to fix the timing issue
analytics.subscribe('init', (event) => {
const customer = event.data.customer;
if (customer && customer.id) {
const customerId = String(customer.id);
const checkGtagAndSend = () => {
if (typeof gtag === 'function') {
// gtag is loaded, now send
gtag('set', 'user_properties', {
'shopify_customer_id': customerId
});
} else {
// gtag not ready, wait and retry
setTimeout(checkGtagAndSend, 100);
}
};
// Start checking
checkGtagAndSend();
}
});
Even with this fix, the user property does not arrive in GA4.
What is the correct, recommended way within a Custom Pixel to get the event.data.customer.id from the init event and reliably send it to GA4 after GTM (gtag) has fully loaded?
Thank you for any guidance!