Skip to main content

Conversion Uplift

Is Your Shopify Store Under-Reporting Sales? What We Learned Moving Stores to Server-Side GTM

If you run a Shopify or headless Shopify store and your GA4 reports fewer purchases than your back-end, or returning Safari customers keep showing up as new visitors, the cause is usually in your tracking setup.  We deal with tracking on Shopify stores almost every day, and so we have built up a database of issues we have come across. These issues are often related to how Shopify loads tags, sandboxes the checkout and resolves to its own IP range, and what that does to your cookies and click IDs. That’s apart from frequent updates from Shopify itslef.

After each project, we conduct a review of how it went, and what were the key learnings. For example, across the Shopify stores we have moved to server-side GTM on Stape, the server containers have captured 8% to 11% more conversions than the client-side setups they replaced. In Google Ads the rise has been 8% to 15%. At £500k a year of paid media, that means bids being set on a conversion count that is short by up to one in seven.

The checklist at the bottom of this post is a reference document for Shopify projects. It covers the migration itself, the Safari cookie cap that catches most stores, and consent and headless storefronts. The percentages come from multiple projects, so check them against your own store’s data before you quote them to anyone. Jump to the checklist.

What You Are Dealing With on Shopify

A Shopify implementation has several separate moving parts, and it can appear complex. Some of the problems we have seen came from not appreciating which part is responsible for loading GTM and which are creating the ecommerce events.

  • The Stape Shopify app (app embed) loads web GTM on storefront pages.
  • The Stape Custom Pixel listens to Shopify Customer Events and creates the checkout and purchase events, because normal theme GTM is not available inside checkout.
  • The theme may still contain old GTM loaders, data layer code and custom click tracking.
  • Other Shopify apps may be sending GA4 and Google Ads data of their own. A common one is the Google and YouTube app. 
  • The server container on Stape receives all of it, re-sets cookies and forwards to GA4, Google Ads and Meta.

Each one can double, drop or mislabel data on its own. Together they explain almost every “GA4 doesn’t match Shopify” ticket we have been asked to look at.

1. Migrating a Shopify Store to Stape Server-Side GTM

One rule shapes everything below. We never switch a store’s tracking over in one go. Always run server-side in parallel with the existing client-side setup, and send the server-side data to a new GA4 property created for that purpose. The store keeps reporting from the main GA4 property, and the server-side container sends data to your new test property. You can discover many issues simply by comparing the data from the two properties, and this allows you time to fix them before switching off your client-side tags. We have a template Looker Studio dashboard to compare the data and connect Claude AI to GA4 to automate this process. 

Know What Loads GTM and What Creates the Ecommerce Data

Once you have implemented the Stape Conversion Tracking App, you should be able to remove GTM script from the store front pages. Before doing this, check that the app’s GTM injection has not been turned off. In some instances, the Stape app GTM injection does not cover all store front theme pages, and so a GTM snippet will be required on those page.  Alternatively, if ‘Rely on Shopify Customer Privacy API consent states’ is enabled, or another part of the implementation is gating the app’s loader according to Shopify consent, this could prevent GTM from loading for new visitors. Investigate how consent has been implemented and check the Shopify set up in case you have conflicting consent status mechanisms. 

Only one mechanism should load web GTM. If the Stape conversion app is enabled, and there is also a loader in the theme,  both will run, and the same container loads twice. This presents a risk of duplicate events. Once the app is proven to load GTM, comment out or remove the theme code. Check the live page source and the network requests, because the app settings screen does not always reflect what is happening.

Use the Stape Shopify Conversion app rather than treating Shopify as an “Other” platform. Configure the web GTM ID, the custom tagging domain, the Custom Loader identifier and the ecommerce data layer in the app. It is the setup we recommend on every standard Shopify store. 

Set theme data layer values before the loader runs. Anything GTM needs from the theme should be in place before the Stape loader initialises.

Audit Shopify apps as well as GTM. Ask specifically whether any app sends GA4, Google Ads, Meta or TikTok data. On more than one store we discovered the Google & YouTube app was a second source of tracking. It did not need to be enabled as they already had GTM implemented. The app also creates its own Google Ads conversion actions, and they are often set as primary. Demote or remove them once the sGTM conversions are live, or Google Ads bids on both.

Check the ad platform apps for their own server events. Shopify’s Facebook & Instagram app on “Maximum” data sharing already sends Conversions API events from Shopify’s servers, and the TikTok and Pinterest apps can do the same. If you add Stape’s Meta CAPI tag as well, purchases may be counted twice unless both sources send the same event_id or one of them is switched off. Check the deduplicated event counts in Events Manager before and after the change.

Remove legacy and custom code rather than layering Stape on top. Custom click tracking published through Shopify.analytics and old checkout scripts can make debugging much harder than it needs to be.

Checkout and the Custom Pixel

The Custom Pixel does a different job from the app embed. It runs in a sandbox, so you have to test it differently.

Purchases can reach GA4 Realtime without appearing in the page data layer. Console messages such as “document is sandboxed and lacks allow-same-origin” are expected and do not mean tracking has failed. Web GTM Preview is not dependable inside checkout, so validate with sGTM Preview, the network requests, Shopify’s pixel console output and GA4 together. 

Do not edit Stape’s generated fetch() code in the Custom Pixel. Always use the Stape generated Ecommerce custom pixel code and avoid modifying it if possible. We have sometimes been advised to modify the script, such as replacing it with a script injection, but this can break the data layer. There is no need to have a separate GTM loader in the custom pixel because  the Stape-generated pixel already loads the container itself. 

Fix /web-pixels@... URLs in GA4. The sandbox reports its own URL as the page. Send event.context.window.location.href as page_location, especially for checkout events. sGTM has no browser of its own, so the server GA4 tag must pass the incoming page_location through.

Storefront cookies do not automatically reach checkout. A gclid persisted across the storefront is not guaranteed to be readable inside the sandboxed checkout. Read cookies in the pixel through the Web Pixels API (browser.cookie.get) and confirm in sGTM Preview that the client ID and click IDs arrive with the purchase.

Check the event schema after changing the data source. value, TotalValue, transaction_id, OrderId and email can all change name when you move to the Stape app. Build your Event Data variables from what actually reaches sGTM, not from the old container.

Know which legacy events still matter. Audit custom event tags to identify any legacy tags that are being used by the store for campaign tracking and optimisation.  These should not be removed until the Ads migration is  finished, and replacement server-side events have been tested and verified. 

Check what stopped on the thank-you page. Shopify retired Additional Scripts on the Thank you and Order status pages for Plus stores on 28 August 2025, and auto-upgraded all other stores on 26 August 2026. Any purchase tags that lived there no longer run. If purchases dropped around either date, check there before looking at the server container.

Post-purchase upsells change when the purchase fires. With an upsell app installed, checkout_completed fires on the first upsell page, before the customer accepts or declines the offer, so upsell revenue is not in the purchase value. If that page fails to load, the purchase may not be tracked at all.

Consider a server-side purchase backup. Some buyers never return from PayPal, Klarna or a 3D Secure check, and some block the pixel. The Stape Shopify app can send order webhooks to the server container, so the purchase reaches sGTM from Shopify itself rather than the browser. To attribute those orders, store the client ID and click IDs on the cart (as cart attributes) while the visitor is on the site, and deduplicate on transaction_id so an order from the pixel and the webhook is only counted once. Refund webhooks can send refund events to GA4 at the same time.

Express checkouts skip steps. Shop Pay, Apple Pay, Google Pay and PayPal buttons on product and cart pages can bypass begin_checkout, add_shipping_info and add_payment_info. Lower funnel step counts on those journeys are not a tracking fault if the purchase still arrives.

Attribution, Testing and Google Ads

Attribution needs more attention than event firing. The first big difference between the two properties in the parallel run was far more “Other” traffic on the server-side one. Persisting UTMs and click IDs (gclid, wbraid, gbraid, fbclid, msclkid) through to begin_checkout fixed it before switch-over.

Add payment providers to unwanted referrals in both GA4 properties: paypal.com, klarna.com, Clearpay, your 3D Secure domains and shop.app. Otherwise a buyer returning from a payment page can have the purchase credited to the provider as a referral.

Test as a brand-new visitor. Existing browsers keep GA and consent cookies, so a setup can look healthy while new sessions fail. Incognito and new-session tests can help expose loading failures.

Tag Assistant is not enough on its own. Use the page source, the network requests, the pixel console, sGTM Preview and GA4 Realtime together. To read the full Shopify checkout data layer, Chrome DevTools Local Overrides lets you swap one script for a local copy with extra logging, in your own browser only, without touching the live site. A local proxy such as Caddy does the same job outside Chrome, but needs a locally trusted certificate and fails if the store uses strict CSP hashes on that script. Either way, anything learned is a diagnostic, not a deployment path. The real implementation still has to go through Shopify’s Custom Pixel or the Stape app.

“Server-side must be higher” is not a safe acceptance test. sGTM usually showed more users and better paid-traffic recovery, but purchase counts were occasionally slightly lower. Investigate the difference rather than assuming the bigger number is right.

Some of the extra users can also be bots that client-side tags never saw. Check for unusual sources and very short sessions before accepting an uplift, and consider Stape’s bot detection power-up.

A tag firing is not a conversion validated. Check the transaction ID, value, currency, click IDs and the outgoing Google Ads request.

Match product IDs to your feeds. item_id must use the same format as the Merchant Center feed (the Google & YouTube app uses shopify_GB_productID_variantID), and Meta content_ids must match the catalogue. If they don’t, dynamic remarketing and conversions with cart data stop matching products, and nothing reports an error.

Send user-provided data with the purchase. checkout_completed includes the customer’s email and phone. Hash them and send them to Google Ads enhanced conversions and Meta advanced matching, gated on ad_user_data consent. This matters more as Safari strips click IDs in more places (see section 2).

Test revenue and zero-value orders separately. Use value > 0 for purchases and value = 0 for samples in sGTM rather than recreating legacy triggers.

Run client-side and server-side Google Ads in parallel first. Create new goals for sGTM tags, but configure them as a secondary data source so they don’t impact campaign optimisation. On average,  server-side purchase conversions in Google Ads are around 9% higher and revenue about 8% higher than client-side.  Analysis of the data indicates the gains mainly come from better click ID recovery.  This is an average, and so for one Shopify store we saw an 11% increase in Google Ads conversion rate and an 11% reduction in acquisition costs.

Part of that improvement is a reporting change rather than a saving: when the same clicks record more conversions, the reported cost per acquisition falls on day one. The lasting gain comes from bidding on the fuller conversion count, so judge it over several weeks against back-end sales, not on the first report.

Check attribution in the parallel run as well as event counts. On one store the server-side property showed Direct revenue rising sharply with no matching rise in Direct traffic. The comparison should cover source/medium, sessions, transactions, revenue and conversion rate by channel, and the switch waits until they match.

Compare like with like against your back-end. Use Online Store channel orders only, excluding POS, draft orders, subscription renewals (Recharge, Shopify Subscriptions) and B2B orders, which never pass through the storefront. Match the timezone, the revenue definition (tax, shipping and discounts) and the currency. On stores using Shopify Markets the pixel reports the currency the customer paid in, while Shopify reports in the shop’s currency.

Setting Up the Parallel Run in GTM

The parallel run is built in Tag Manager before anything touches the Shopify theme. The order matters.

  1. Create the server container in Google Tag Manager first. Stape asks for the container’s manual configuration key when you create the Stape container, so the Tag Manager container has to exist before the Stape one.
  2. Create the Stape container with that key, add the custom tagging domain and confirm the server container URL responds. Check the Stape plan at the same time: the duplicated tags roughly double server requests for the length of the parallel run, so confirm the request limit and what happens if you exceed it. For UK and EU stores, host the container in an EU zone.
  3. Duplicate every GA4 event tag in the web container. Export the GA4 event tags, then import them straight back into the same container with Merge and Rename conflicting. You now have a second copy of each GA4 event alongside the original.
  4. Create a new Google Tag, a new Google Tag Configuration Settings variable and a new Event Settings variable. Add server_container_url to both as a constant variable holding the Stape domain. Point the duplicated GA4 event tags at the new Google Tag and the new Event Settings variable. Leave the originals untouched, so client-side keeps sending exactly as before.
  5. Keep the GA4 client in the server container on JavaScript Managed during the parallel run. Server Managed sets a new FPID cookie and uses it as the client ID, so unless “Migrate from JavaScript Managed Client ID” is ticked, existing visitors get new IDs and the two properties stop being comparable. On a standard Shopify store, FPID is also set from Stape’s IP range, so Safari caps it at seven days like _ga (see section 2).
  6. Enable the GA4 client and create the server GA4 event tag with a trigger of Client Name equals GA4, sending to a new GA4 property created for the parallel run, not the reporting property. The store’s reports stay on the existing property, fed by the original client-side tags, until the two agree. Where several reporting properties are involved, route them with a constant or a RegEx table.
  7. Set up the new GA4 property like the reporting one: the same timezone and currency, unwanted referrals, cross-domain settings, 14-month data retention, key events, custom dimensions, internal traffic filters and the Google Ads link. Otherwise some of the differences between the two properties come from configuration, not tracking. Expect new-user counts in the new property to run high for the first few weeks.
  8. Check that checkout events reach the new property in the same session. Events from the Custom Pixel must fire the duplicated GA4 tags as well as the originals. If they arrive under a different stream or without the session cookie for the new measurement ID, checkout can start a new session and purchases show as Direct or Unassigned.
  9. Create the marketing pixels in the server container (Google Ads, Meta and the rest) and the Event Data variables they need: UTMs, click IDs, client_id and session_id. URL parser variables on page_location capture UTMs and other parameters.
  10. Send UTMs and click IDs with the GA4 event tags. If unassigned traffic rises in the server-side property, check which events are arriving without them.

The Migration Order We Use Now

Do not switch everything at once. The sequence for a Shopify store is:

  1. Inventory every mechanism that can load GA4, GTM or Google Ads: theme code, Customer Events pixels, Shopify apps and third-party scripts.
  2. Remove or disable competing implementations, so there is one GTM loader.
  3. Record a baseline of GA4 users, sessions, source/medium, purchases and revenue.
  4. Build the parallel run in GTM as above: server container, Stape container, duplicated GA4 events pointed at the new Google Tag. Then install the Stape app and Custom Pixel and map the event schema that reaches sGTM.
  5. Run client-side and server-side in parallel. The original tags keep sending to the reporting property; the server container sends to the new property. Server-side Ads conversions run as secondary actions.
  6. Test paid, organic, email and affiliate journeys through checkout as a new visitor, and compare Shopify orders with GA4 and Google Ads.
  7. Switch over. Once the two properties agree, point the server GA4 tag at the reporting property and pause the client-side GA4 tags. Check the reporting property stays healthy, then make the sGTM Ads conversions primary and pause the client-side Ads tags.
  8. Remove legacy pixel logic last.

2. Why Returning Safari Customers Look Like New Visitors

The Seven-Day Cap on Shopify

Since Safari 16.4, a cookie set by a server whose IP address differs from the website’s in the first half of the address is capped at seven days, even when it comes from a first-party subdomain. Cookies set by JavaScript are capped at seven days anyway, or 24 hours when the visitor arrives from a domain Safari classes as a tracker and the landing URL carries a query string or fragment, which covers most ad clicks.

Shopify storefronts resolve to Shopify’s IP range (23.227.38.x). A Stape container on a custom subdomain resolves to Stape’s Google Cloud range. So a tagging subdomain on Shopify does not get longer-lived cookies in Safari, however the server container is configured.

This is the usual cause when a store says returning Safari customers look like new visitors. It weakens Meta attribution, remarketing and CRM audiences, and any personalisation that needs to recognise a customer. On a store where most traffic is mobile, that is a large share of repeat buyers being bid on as if they were cold.

Safari also removes some click IDs before your tags see them. Link Tracking Protection strips gclid, fbclid, msclkid and other click IDs in Private Browsing and in links opened from Mail and Messages. Safari 26 added fingerprinting protection in all browsing modes, and reviews of the Safari 27 code report network-level blocking of some ad platform endpoints by IP address, with Microsoft’s UET and LinkedIn’s Insight Tag named so far. Server-side tags are not affected by that block, because the browser only talks to your own server, so send Microsoft Ads and LinkedIn conversions through their server-side APIs. Persist wbraid, gbraid and UTMs as well as gclid, and use enhanced conversions as the fallback when the click ID is missing.

Check the IP Addresses on Day One

Run nslookup on every storefront, the checkout subdomain, the server container domain and the Custom Loader domain. Compare the first half of each IP address with the storefront’s.

A different subdomain for checkout on the same primary domain is fixable. A different primary domain is a much harder problem.

If the store sets its own first-party cookies from its server, compare their expiry in Safari with _ga or FPID. If the store’s own cookie lasts longer, the IP rule is the cause.

Fix Options by Store Type

Whichever route you use, point the Custom Loader and the GA4 server_container_url at the same-origin path, and make the address match the page hostname exactly: www and the bare domain are different.

Store typeRoute to longer cookiesWhat to know
Standard Shopify (theme)Stape Cookie Keeper through the Stape Shopify appThere is no supported way to serve a path on a Shopify-hosted storefront from your own server, so same-origin is not available. Shopify app proxies do serve a path on the storefront, but Shopify strips Set-Cookie headers from their responses, so they cannot set long-lived cookies. Cookie Keeper restores Google, Meta, TikTok and other platform cookies from a Shopify master cookie. Confirm which cookie with Stape (see the note below the table). Pro plan; custom cookies such as _gclid and utm_* need Business.
Headless (Hydrogen on Oxygen)Same-origin: serve the server container from the storefront, for example www.store.com/metrics, through a proxy route in the Hydrogen serverOxygen already runs on Cloudflare Workers, so a Cloudflare proxy in front of the site does not work ("Cloudflare in front of Cloudflare"). The route is a code change the store's developers must deploy.
No code change possibleCookie Keeper on the current domainImproves cookie life but does not fully solve Safari. A server-managed FPID does not help here: it is set from Stape's IP range, so Safari caps it at seven days as well. Say so plainly to the client.

A note on the master cookie. Stape’s Cookie Keeper documentation names _shopify_y and _y as the master cookies, but Shopify’s developer changelog says it stopped setting _shopify_y and _shopify_s from 1 January 2026. Check which cookies your store sets before relying on Cookie Keeper.

Making the Cookie Extender Work

Our standard pattern is a Custom HTML tag in web GTM that saves UTMs and click IDs as first-party cookies and pushes them to the data layer, plus Cookie Monster in the server container to re-set them from the server. Reviewing our own containers showed several ways this goes wrong:

  • The server must write the same cookie names it reads. For example, if in the web container it is set to  _gclid and then written as gclid in the server container, the click ID will never be extended. 
  • Gate both sides on consent. The web tag should need ad_storage and fire on Initialization and again on the consent update event, never on Consent Initialization. In the server container, split Cookie Monster into an analytics tag (_ga, _ga_<stream>, UTMs) and a marketing tag (click IDs, _fbc, _fbp), triggered by the GA4 consent signal: gcs matching ^G1.1 for analytics_storage and ^G11 for ad_storage.
  • Keep expiries consistent across web and server: 90 days for click IDs, 30 days for UTMs and two years for _ga.
  • Set cookies on the root domain (detected by the script, for example .store.com) so the checkout subdomain can read them.
  • Overwrite UTMs as a set when a new campaign arrives, so values from two visits are never mixed, and refresh _fbc when a new fbclid arrives.

Testing Cookie Life in Safari

  1. Test on real Safari on a Mac and a real iPhone. Chrome and simulators do not show the cap.
  2. Land with ?gclid=, ?fbclid=, ?ttclid= and UTMs. Record which cookies are set, whether by a Set-Cookie header or JavaScript, and their expiry in Web Inspector.
  3. Repeat with consent accepted, rejected and not yet answered.
  4. Confirm in sGTM Preview that the cookies arrive and that Cookie Monster or Cookie Keeper re-sets them, then check the expiry again on the next page.

3. Consent, Headless Storefronts and Multi-Store Setups

Consent

  • Connect the consent banner to Shopify’s Customer Privacy API. Three things on a Shopify store take consent from the API, not from GTM. The apps installed from the Shopify App Store (such as the Facebook & Instagram or Google & YouTube apps), Shopify’s own analytics, and the checkout, where GTM does not run. If the banner only updates Consent Mode in GTM, none of these will follow the visitor’s choice. You can check in the browser console with window.Shopify.customerPrivacy.currentVisitorConsent().
  • Set consent for the checkout separately. Custom pixels under Customer events run in a sandbox that can’t see the storefront’s data layer. They follow the consent setting on the pixel, so a pixel set to “Not required” fires whatever the visitor chose. That is only acceptable if the pixel passes the visitor’s consent into Consent Mode.
  • Check app tracking outside GTM. Theme app embeds and app pixels under Customer events may fire outside your consent setup. Check both lists, not just GTM.
  • Map ad_user_data and ad_personalization to marketing consent. They control whether user-provided data and remarketing are allowed in Google Ads. If they are mapped to statistics consent, a visitor who declines marketing but accepts statistics still sends them as granted. Fire a consent update on decline and on withdrawal as well as on acceptance, so the server container sees every change.
  • On headless stores, nothing is connected for you. The developer has to push the consent default before any events and connect the banner to the Customer Privacy API (in Hydrogen, the useCustomerPrivacy hook). If the default arrives after the first page and product events, those early events fire before Consent Mode is set.

Headless (Hydrogen) Storefronts

  • Page views on route changes and all ecommerce events are usually custom code. Check each fires once per route change with the right values.
  • Watch for literal "undefined" strings in event parameters, such as review scores.
  • A Content Security Policy is a good safeguard for an Ecommerce site, but ensure it allows requests to your server-side subdomain. 
  • The GTM loader and data layer live in the Hydrogen code, so ask for the code or read access to the repository at the start.

Several Stores or Storefronts on One Container

  • Map which country storefronts belong to which Shopify store before testing.
  • Where Meta pixels are chosen by hostname in a GTM lookup, test switching between storefronts and check the right pixel and IDs are used.
  • Repeat the core cookie and checkout test on at least one storefront from each store.
  • Agree how test orders are flagged. A cancellation window helps, but test orders can still trigger emails, fulfilment or affiliate commission.

Troubleshooting: Symptom to Cause

What you seeWhere to look first
Server-side property shows fewer users than client-side across every channelNew visitors are not getting GTM in the new setup. Check the live page source and network requests, not the app settings screen.
Every event is doubledTwo GTM loaders: the app embed and theme code both running. Remove one.
Purchases in GA4 Realtime but not in the data layerExpected. The Custom Pixel runs in a sandbox. Validate with sGTM Preview and the pixel console.
Page location shows /web-pixels@...Send event.context.window.location.href as page_location from the pixel and pass it through in the server GA4 tag.
Google Ads conversions missing click IDsStorefront cookies not reaching checkout. Read them in the pixel with browser.cookie.get.
More "Other" traffic in the server-side propertyUTMs and click IDs not persisted to begin_checkout.
Direct revenue up in the server-side property, Direct traffic flatAttribution broke at checkout. Check source/medium by channel as well as event counts.
Returning Safari customers appear as newSeven-day cookie cap. Run nslookup and compare IP ranges.
Click IDs never extended but _ga isCookie Monster writes a different cookie name from the one it reads.
Visitor declined marketing but ad_user_data shows grantedad_user_data mapped to statistics consent instead of marketing.
Meta purchases roughly doubled after adding StapeThe Facebook & Instagram app and Stape's Meta tag both sending Conversions API events without a shared event_id. Switch one off or align the event IDs.
Purchases dropped around 28 August 2025 (Plus) or 26 August 2026Purchase tags in Additional Scripts on the Thank you page stopped running when Shopify upgraded the page. Move them to a Custom Pixel or the server container.
Upsell revenue missing from purchasescheckout_completed fires on the first post-purchase upsell page, before the upsell is accepted.
Dynamic remarketing or cart data empty in Google Adsitem_id does not match the Merchant Center feed format.
Revenue gap on a multi-currency storeThe pixel sends the currency the customer paid in. Shopify reports in the shop currency.
Purchases credited to paypal.com or klarna.comPayment providers missing from unwanted referrals in GA4.

Final Checks Before You Call It Done

Frequently Asked Questions

Usually because the checkout runs in a sandbox the theme’s GTM cannot reach, and because ad blockers, browser extensions and Safari’s tracking prevention stop client-side tags firing. The Stape Custom Pixel and a server container recover most of the gap. On the stores we have migrated, 8% to 11% more conversions were captured.

Use the app. It configures the web GTM ID, the custom tagging domain, the Custom Loader and the ecommerce data layer in one place, and the Custom Pixel handles checkout. A theme snippet alone misses checkout entirely and is easy to end up running twice.

Safari caps cookies at seven days when the server setting them resolves to a different IP range from the website. Shopify storefronts resolve to Shopify’s range and a Stape container to Google Cloud’s, so a custom subdomain does not help on its own. Stape Cookie Keeper is the route for standard stores (confirm which master cookie it uses, as Shopify stopped setting _shopify_y in January 2026); a same-origin proxy route is the route for Hydrogen.

Usually more users and better paid-traffic recovery, but purchase counts can occasionally be slightly lower. Compare transaction IDs, values and click IDs rather than totals, and use zero-value sample orders as a control group to rule out duplication.

With one storefront, a clean theme and no legacy pixels, the parallel-running period is the longest part, because you need enough orders in both setups to compare transaction by transaction before switching GA4 and then Google Ads. Multiple storefronts, a headless build or old custom tracking add time, mostly in the inventory and testing steps.

Download the Shopify Server-Side Tracking Checklist

Every check in this guide, in order, as a printable A4 checklist with space to record your values and who signed each step off.

Not Sure What Your Shopify Store Is Losing?

Send us the store URL. We’ll run a free read-only check of how GTM loads, what reaches checkout and how long your cookies last in Safari, and tell you what it’s worth to fix. No access needed, no pitch.

Neal Cole

Neal Cole is the founder of Conversion Uplift and wrote the official GA4 and GTM audit course for CXL. He has spent 20+ years fixing measurement for Hastings Direct, Casumo, Gardening Express and other businesses where a wrong number is expensive.

Neal Cole

Neal Cole

Neal is the founder of Conversion Uplift and the author of the official GA4/GTM audit course for CXL. It's the course much of the industry trains on. He's spent over 20 years in digital analytics, including senior roles in online gaming and financial services, working out where businesses' numbers go wrong and what it costs them. His work now focuses on server-side tracking, GA4 and BigQuery: getting the data right, and being the person who's accountable for it when a decision depends on it.
Neal Cole

Neal Cole

Neal is the founder of Conversion Uplift and the author of the official GA4/GTM audit course for CXL. It's the course much of the industry trains on. He's spent over 20 years in digital analytics, including senior roles in online gaming and financial services, working out where businesses' numbers go wrong and what it costs them. His work now focuses on server-side tracking, GA4 and BigQuery: getting the data right, and being the person who's accountable for it when a decision depends on it.
Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors

Free audit checklist to

Fix GA4 Tracking Like a Professional

Acceptance