GA4 Counting Purchases Twice? The Duplicate Tag Fix
GA4 shows roughly twice the purchases and events your store actually gets. Shopify or WooCommerce admin says 40 orders, GA4 says 78. In most stores I audit, the cause is simple: GA4 is installed twice - once by a plugin (Site Kit, a Shopify app, a theme field) and once through Google Tag Manager. Every event fires down both pipes.
This is a fifteen-minute diagnosis and usually a five-minute fix. Here is how I confirm it, why it wrecks more than the purchase count, and how to clean it up without losing data.
Confirm the duplicate in five minutes
Open your store in an incognito window. Open DevTools (F12 or Cmd+Option+I), go to the Network tab, type collect in the filter box, reload the page. A healthy install produces one request containing en=page_view per measurement ID. If you see two requests with the same tid=G-XXXXXXX and en=page_view, you are double-tagged:
https://region1.google-analytics.com/g/collect?v=2&tid=G-ABC1234&...&en=page_view https://www.google-analytics.com/g/collect?v=2&tid=G-ABC1234&...&en=page_view
Three more checks that settle it:
- Tag Assistant. Go to tagassistant.google.com, connect your domain. Two Google tags loading the same GA4 destination - typically a GT-XXXX injected by a plugin plus a G-XXXX config firing from your GTM-XXXX container - is the classic pattern. Since Google's tag consolidation, plugins often load a GT- ID that carries your G- stream, so GT- and G- both firing is the tell, not a feature.
- GA4 DebugView. Admin > DebugView while Tag Assistant is connected. Every click and page_view appears twice in the stream.
- Test purchase. Place an order, keep the Network tab open on the thank-you page, filter for collect, look for en=purchase. Two purchase hits means doubled revenue in reports.
You can also view page source and search for both gtag/js?id=G- and googletagmanager.com/gtm.js. If both are present and the GTM container also holds a GA4 tag, that is your duplicate.
Why purchases double (and sessions can inflate)
Each GA4 config on the page dispatches every event once. Two configs for the same measurement ID means two hits per event: page_view, add_to_cart, purchase, all of it.
GA4 has one built-in guard for purchases: it drops a purchase whose transaction_id matches one it already recorded from the same user. That guard only works when both installs send an identical ID. Two independent installs rarely do. The plugin sends the raw order ID, GTM sends a prefixed order number, or one omits the field entirely. Both purchases count. Revenue doubles.
Sessions inflate for a duller reason: the two installs initialize at different moments with different settings, and redirects through payment gateways or consent updates can restart a session under one config but not the other. Even when session counts hold, event counts double, so every ratio built on the reports - conversion rate, revenue per session, AOV per channel - is computed from corrupted inputs.
Why attribution falls apart
The same order now exists as two purchase events with different timing and session context. One fires the moment the thank-you page loads, the other after a consent update or a gateway redirect. GA4 attributes each copy independently, so a single order can show under two channels, or the late copy lands in Direct.
If you import GA4 key events into Google Ads, Ads receives doubled conversions. Smart Bidding optimizes toward a ROAS that does not exist and spends accordingly. And because GA4 no longer reconciles with your store admin, Meta, or your bank, every budget argument turns into a guess.
The fix: one pipe, not two
Pick one install and kill the other. My default: keep GTM, remove the plugin's Analytics output. GTM gives you one place to manage GA4, Google Ads, Meta and consent, and it upgrades cleanly to server-side tagging later.
- WordPress with Site Kit: Site Kit > Settings > Connected Services > Analytics > disconnect the Analytics module. Site Kit keeps working for Search Console and PageSpeed. You are removing its GA4 snippet, not the plugin.
- Other WP sources: MonsterInsights, Google for WooCommerce's analytics option, or a theme's Google Analytics ID field. Remove the measurement ID or disable the analytics feature. An empty ID field means no snippet.
- Shopify: here I usually flip the default and keep the Google & YouTube channel for GA4, because it covers checkout events natively, then delete the GA4 config and event tags from GTM while keeping GTM for everything else. Also check theme.liquid and Settings > Customer events for a pasted gtag snippet - old ones survive theme updates.
Do not delete the GA4 property or the data stream. Your history lives in the property. You are removing one of two loaders, nothing else.
Verify after the fix
Purge page cache and CDN first (WP Rocket, LiteSpeed, Cloudflare), otherwise the old snippet keeps serving. Then, in a fresh incognito window:
- Network tab: one collect request with en=page_view per page load, one per event as you click around.
- Tag Assistant: a single GA4 destination for your measurement ID.
- Realtime: browse the site yourself with GA4 Realtime open. Event counts should step by one per action, not two.
- Test purchase: one en=purchase hit in the network tab, one purchase in DebugView.
Next day, compare GA4 purchases against your store admin. GA4 at or slightly below the admin count is healthy - browser-side tracking always loses a share to ad blockers and declined consent. GA4 above admin means something still fires twice. Note the fix date: GA4 does not rewrite history, so reports before that date stay doubled and any period comparison has to start after it.
Numbers still don't add up?
Tell my assistant what you see and I will reach out to you directly. Every rated job on Upwork is 5.0, check them live.
FAQ
Will disconnecting Site Kit's Analytics module delete my GA4 data?
No. The GA4 property and its history live in your Google account, not in the plugin. Disconnecting only removes the tracking snippet Site Kit injects, and Search Console plus the other Site Kit modules keep working.
GA4 shows more purchases than Shopify. Is it always double-tagging?
It is the most common cause, and a ratio near 2x makes it almost certain. A healthy browser-side setup reports slightly fewer purchases than the store admin, rarely more - cancelled or failed orders can put GA4 slightly above the completed-order count. A gap approaching 2x deserves the network tab check.
Doesn't GA4 deduplicate purchases with the same transaction_id?
It does, when the same user sends two purchase events with an identical transaction_id. Two independent installs rarely send identical IDs - one uses the raw order ID, the other a prefixed order number, or one omits the field - so the guard does not save you.
Should I keep GTM or the plugin?
Keep GTM if you run paid traffic, consent mode, or plan server-side tagging, since it is the one place to manage all tags. A plugin-only install is fine for a simple content site with no ad spend. Never run both for the same measurement ID.
Want it checked by professionals?
Seven days of platform conversions next to your real orders is enough for us to name the likely cause. No charge, usually under an hour.