How to Track a Headless Shopify Store
Going headless breaks every assumption your tracking made. Here is how to instrument a custom storefront without losing checkout data.

Going headless with Shopify is a real upgrade for speed and design control. It is also the fastest way to break every piece of tracking you had, because most of that tracking quietly depended on being inside Shopify’s own theme.
The usual pattern is a launch that looks great, followed by two weeks of everyone asking why Google Ads thinks revenue dropped sixty percent.
Here is how to instrument a headless build so that does not happen.
What actually changes when you go headless
Three things, and each one breaks something different.
Your storefront is no longer a Shopify theme. Shopify apps that inject scripts into the theme have nowhere to inject. Every app based tracking setup stops working.
Your storefront and your checkout are on different domains. The store might be on example.com while checkout is on checkout.shopify.com or a Shopify subdomain. That is a cross domain problem now.
Navigation no longer reloads the page. A React or Next storefront swaps views. Tags that assume a page load will fire once, on the first page, and never again.
So you rebuild the storefront tracking yourself, and you connect the checkout back to it deliberately.
Storefront: build a real data layer
This is the part you now own completely, which is actually good news. You have the product data in your components already.
Push events from your application code at the points that matter:
view_item when a product page renders, with item ID, name, price and currency
add_to_cart when the cart mutation succeeds, not when the button is clicked
view_cart and remove_from_cart if you care about cart behaviour
begin_checkout when you hand off to checkout
That distinction on add to cart matters. Firing on the click means you count adds that failed because the variant was out of stock. Fire on the successful response.
Use the standard GA4 ecommerce shape for these. It costs nothing extra and every tool downstream understands it. Background here: GA4 ecommerce tracking for Shopify.
Storefront: handle client side routing
In your router, push a page view event on every route change, after the new page has rendered and the title has updated.
The ordering matters. If you push before the title updates, every page view reports the previous page’s title, and your reports become quietly useless.
In GTM, trigger your GA4 page view on that custom event rather than on the built in page view trigger.
Checkout: the part people get wrong
Headless or not, Shopify owns checkout. You track it with Web Pixels, the same mechanism as a normal Shopify store.
Create a custom pixel in the Shopify admin that subscribes to checkout_started, payment_info_submitted and checkout_completed. That pixel runs in Shopify’s sandbox on the checkout domain and reports events regardless of what your storefront is built with.
Full walkthrough of that mechanism: Shopify custom pixel setup.
The important detail for headless is that this pixel runs somewhere your storefront’s JavaScript cannot reach. It has no idea who the user was on your storefront. Which brings us to the actual hard problem.
Carrying identity across the boundary
A customer clicks your ad, lands on example.com, browses, then checks out on a Shopify domain. Your ad platform needs to connect those two halves.
Three things need to survive the jump.
The click ID
Capture gclid, gbraid, wbraid, fbclid and your UTM parameters on the first landing page. Store them in a first party cookie on your storefront domain.
Then attach them to the cart as a cart attribute or as a note before handing off to checkout. Shopify carries cart attributes through to the order, which means your click ID ends up on the order record where you can use it later.
This single step is what makes offline and server side attribution possible afterwards. Do it even if you have no immediate use for it.
The GA4 client ID
Read the _ga cookie value on your storefront and pass it to checkout the same way. Without it, GA4 will start a brand new session at checkout and attribute the purchase to a referral from your own site.
This is the number one cause of Shopify purchases showing up under direct or referral traffic.
The user
Email and phone from checkout are the strongest matching signals for Enhanced Conversions and for Meta. You get these on the Shopify side, and they should be hashed and sent from the server rather than exposed in the browser.
Send the purchase from the server
On a headless build, server side is not a nice to have. Your checkout is on a different domain, browsers are actively restricting cross domain cookies, and the browser pixel is the weakest link in the chain.
The reliable setup is a Shopify webhook or a server side GTM container receiving the order, enriched with the click ID you stored on the cart, then forwarding to Google Ads, GA4 and Meta with a consistent event ID for deduplication.
That gives you one source of truth for purchases that does not care about ad blockers, Safari or which domain the customer was on.
Starting points: GA4 server side tagging setup and Meta CAPI with server side GTM and deduplication.
The launch checklist
Before you flip the DNS, not after.
Every storefront event fires once per action, with correct values, in GTM preview.
Route changes produce exactly one page view each, with the correct page title.
A test order carries the click ID and the GA4 client ID as cart attributes all the way onto the order record.
checkout_completed fires from the Shopify pixel with the full order value.
The server side purchase and the browser purchase share an event ID, and Google and Meta each report one conversion, not two.
GA4 purchase count for a test day matches Shopify order count.
If the click ID does not survive the handoff, stop and fix that first. Everything downstream depends on it.
What good looks like afterwards
GA4 purchases within a few percent of Shopify orders. Google Ads conversions attributed to campaigns rather than piling up as direct. Meta event match quality in the good range because you are sending hashed email from the server.
And a setup where, when something breaks, you know exactly which of the four moving parts to look at.
Need this built properly?
Headless builds need tracking designed alongside the build, not bolted on after launch. I set up and repair tracking for ecommerce stores and lead generation businesses, so the numbers in your ad accounts match the money in your bank account.
Have a look at what I do, or book a call and we can go through your setup together.



















