Analytics
GA4 Shopify Setup for South African Stores.
This guide installs Google Analytics 4 on a South African Shopify store so that purchase revenue reports in Rand and behavioural events respect POPIA. Shopify routes checkout on a second subdomain on every plan below Plus, which breaks GA4 sessions unless you configure it correctly. We cover the install, the cross-domain fix, ZAR currency tagging, and POPIA consent wiring.
Prerequisites
- Shopify Admin access with permission to edit theme files and checkout settings
- A Google Analytics 4 property created in analytics.google.com with a Web data stream
- The GA4 Measurement ID in the format G-XXXXXXXXXX
- A POPIA consent banner already running on the storefront (or plan to install one)
- Access to Customer Events in Shopify Admin (Settings > Customer events)
Step 1. Create the GA4 property with ZAR as the reporting currency
Open Analytics Admin, create a new property, and set the reporting currency to ZAR (South African Rand). This is a property-level setting that cannot be overridden per-event — if you leave it at USD, every Rand value in purchase events gets silently converted using yesterday's rate. Set the time zone to (GMT+02:00) Johannesburg. Create a single Web data stream for your primary apex domain.
Step 2. Install the base gtag via Shopify theme.liquid
Shopify has a native GA4 integration under Settings > Customer events, but the theme install gives you control over consent ordering on non-checkout pages. Paste the snippet into theme.liquid just before the closing </head> tag. Replace G-XXXXXXXXXX with your real Measurement ID.
<!-- GA4 base install, consent default denied for POPIA -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied',
'ad_user_data': 'denied',
'ad_personalization': 'denied',
'wait_for_update': 500
});
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX', {
'currency': 'ZAR',
'country': 'ZA',
'send_page_view': true,
'cookie_flags': 'SameSite=None;Secure'
});
</script> Step 3. Update consent state from the POPIA banner
When the visitor accepts cookies, flip analytics_storage (and ad_storage if you run Google Ads) to granted. Fire this from the banner accept handler, not on page load. The 500ms wait_for_update above gives the banner time to report user choice before the first page_view queues.
document.addEventListener('popia:consent:accepted', (e) => {
const categories = e.detail?.categories || [];
gtag('consent', 'update', {
analytics_storage: categories.includes('analytics') ? 'granted' : 'denied',
ad_storage: categories.includes('marketing') ? 'granted' : 'denied',
ad_user_data: categories.includes('marketing') ? 'granted' : 'denied',
ad_personalization: categories.includes('marketing') ? 'granted' : 'denied'
});
}); Step 4. Wire the Shopify Customer Events pixel for checkout
Checkout on Basic, Shopify, and Advanced plans runs on checkout.shopify.com or shop.app, which breaks the cookie domain. Use Settings > Customer events > Add custom pixel. This ensures purchase, add_to_cart, and begin_checkout events include the client_id and ZAR currency. Plus merchants can use checkout.liquid directly instead.
analytics.subscribe('checkout_completed', (event) => {
const checkout = event.data.checkout;
window.gtag && window.gtag('event', 'purchase', {
transaction_id: checkout.order.id,
value: checkout.totalPrice.amount,
currency: checkout.totalPrice.currencyCode, // 'ZAR'
tax: checkout.totalTax?.amount,
shipping: checkout.shippingLine?.price.amount,
items: checkout.lineItems.map((li) => ({
item_id: li.variant.sku,
item_name: li.title,
price: li.variant.price.amount,
quantity: li.quantity
}))
});
}); Step 5. Configure cross-domain measurement
In GA4 Admin > Data Streams > your stream > Configure tag settings > Configure your domains, add your apex domain (yourstore.co.za), www, checkout.shopify.com, and shop.app. Without this the checkout flow starts a new session and purchase attribution detaches from the paid click.
Step 6. Mark purchase as a key event and turn off inflated ecommerce
In GA4 > Admin > Events, mark "purchase" as a key event (formerly "conversion"). Also disable "Enhanced measurement > Form interactions" if you run a single-page product builder — it fires on every keystroke and pollutes engagement rate.
Step 7. Validate with DebugView and a R1 test order
Install the GA Debugger Chrome extension, place a R1 test order through Shopify's bogus gateway, and watch DebugView in GA4. Confirm the purchase event shows value: 1, currency: "ZAR", and a matching transaction_id. If currency shows USD, your property default is wrong — fix in Admin before it pollutes real revenue.
Step 8. Build a ZAR revenue report for daily standups
In Reports > Library, create a detail report with dimensions Session source/medium + Landing page and metrics Sessions, Key events (purchase), Total revenue, Average purchase revenue. Save it to the Monetisation collection. Revenue now displays as "R 1,234.56" automatically because the property currency is ZAR.
SA gotchas
- If your POPIA banner loads after the GA4 snippet, consent default "denied" never gets the chance to run — GA4 will fire a page_view without consent and your DPO will flag it.
- Shopify Basic and Shopify plans do not give access to checkout.liquid, so you must use Custom Pixels. Plus merchants should prefer checkout.liquid because pixels run in a sandbox that strips document access.
- ZAR currency formatting only applies if the property currency is set to ZAR before your first purchase event. Retroactive changes do not fix historical rows.
- Apple Private Relay strips the IP and coarsens geography — expect 15 to 25 percent of iOS Safari traffic to report as "South Africa, unknown city".
- Shopify's native GA4 integration under Customer events double-fires purchase if you also install via theme.liquid with send_page_view and a manual purchase push. Pick one source of truth.
Frequently asked questions
Is Google Analytics 4 POPIA compliant out of the box?
No. GA4 requires explicit opt-in for analytics_storage under POPIA, and you need a Data Processing Addendum signed with Google. Use Consent Mode v2 with default denied, update on user opt-in, and document the lawful basis in your privacy policy.
Why does my GA4 revenue not match Shopify Admin?
Three usual suspects: currency mismatch (property set to USD), partial refunds not being sent as refund events, and checkout sessions dropping when Shopify redirects to checkout.shopify.com without cross-domain configured.
Do I need Google Tag Manager to run GA4 on Shopify?
No, but GTM makes consent orchestration and adding Meta Pixel, TikTok, and Google Ads easier. For a single-tag install, theme.liquid plus Custom Pixels is fine.
Will GA4 still work after the third-party cookie sunset?
Yes. GA4 uses first-party cookies under your domain. The impact lands on cross-site remarketing audiences shared with Google Ads, not on measurement itself.