Duplicate purchase events on Shopify: why GA4 and Meta count orders twice

More purchases than orders? How to confirm duplicates in GA4, Meta and Google Ads, and the six causes behind them.

GA4 shows more purchases than Shopify has orders: the classic sign of duplicate purchase events. Or Meta reports a ROAS that looks too good to be true. Duplicate purchase events are less talked about than missing ones, but they are just as damaging: ad platforms bid on conversions that never happened, and every report built on that data overstates revenue.

How to confirm you have duplicates

In GA4

Create a free-form exploration with Transaction ID as the dimension and Purchases or Transactions as the metric, sorted from high to low. Any transaction ID with a count above 1 is a duplicate. Also look for purchases with a (not set) transaction ID: they cannot be deduplicated at all.

In Meta

Compare Purchase events in Events Manager with Shopify online store orders over the same week. If Meta receives clearly more purchases than you had orders, check the deduplication details of the Purchase event.

In Google Ads

List purchase conversion actions under Goals → Conversions. Two primary purchase actions usually mean every order is counted twice.

Cause 1: several tools send the same purchase

This is the most common cause by far. A typical store I audit has the Google & YouTube app sending GA4 purchases, plus a custom pixel with GTM sending them again, plus a tracking app installed two years ago that still runs. Each one is correct on its own; together, they double or triple your numbers.

Native apps can also send purchases from Shopify’s servers, which you won’t see in the browser: the Facebook & Instagram app at its Enhanced or Maximum data-sharing level, and the Google & YouTube app with its server-to-server connection to GA4 and Google Ads. If GTM also sends purchases to those platforms, switch the app’s tracking off.

Go to Settings → Customer events and list every app pixel and custom pixel. For each destination (GA4, Meta, Google Ads, TikTok), decide on one source and disconnect the others.

Cause 2: no transaction ID

GA4 and Google Ads can ignore a repeat purchase that carries the same transaction ID. Without one, every reload of the thank-you page or every second tag becomes a new sale. Always send the Shopify order ID as transaction_id, and keep the same format everywhere: either the numeric ID or the order name like #1234, not one in one tool and the other elsewhere.

Cause 3: pixel and Conversions API without a shared event ID

When the Meta pixel and the Conversions API both send a Purchase, Meta merges them only if they have the same event name and the same event_id. If your server events come from one tool and your browser events from another, the IDs rarely match, and Meta counts the order twice. I cover this in Meta Conversions API on Shopify.

Cause 4: client-side and server-side both send to GA4

When moving to server-side tracking, it is easy to leave the old browser tag running. GA4 then receives the purchase once from the browser and once from your server container. During a migration, route each event through one path only, and compare both paths before switching the old one off.

Cause 5: post-purchase upsells and order edits

Post-purchase upsell apps can create a second order, or send a second purchase event for the upsell amount. Decide whether an upsell should be its own conversion (with its own order ID) or an update to the first order, and make sure every tool follows the same rule.

Cause 6: test and staff orders

Test orders placed by your team or your developers end up in GA4 and ad platforms too. Exclude internal traffic in GA4, and use a test code when testing Meta.

What to do about past data

You can’t delete duplicate events from GA4 or Meta. Add an annotation with the date of the fix so nobody compares before and after without context. If you export GA4 to BigQuery, you can deduplicate past purchases on transaction ID in your reporting.

Prevention checklist

  • One source per destination, documented in a tagging plan.
  • Shopify order ID sent as transaction ID, in one format, everywhere.
  • Shared event_id between browser and server events.
  • One primary purchase action in Google Ads.
  • Old tracking apps and legacy scripts removed, not just paused.
  • A monthly check of purchases by transaction ID against Shopify orders.

Frequently asked questions

Does GA4 deduplicate purchases with the same transaction_id?

GA4 uses transaction_id to drop some repeated purchases, but don’t rely on it as your protection: it doesn’t help when IDs differ between tools, and it does nothing for Meta or Google Ads. The fix is one purchase source per platform.

What does “Potential duplicate events” mean in Meta Events Manager?

Meta received browser and server Purchase events that look like the same order but don’t share the same event ID, so it can’t deduplicate them. Send the same event_id from the pixel and the Conversions API.

Can server-side tracking create duplicates?

Yes. A server setup that sends purchases from Shopify’s order webhook can send the same order twice if the webhook is delivered again, and a server purchase added next to an existing browser purchase doubles GA4 counts. Deduplicate on the order ID on the server, and keep one GA4 purchase source.

Why do I see duplicates only for some orders?

Partial duplicates usually come from a specific path: a post-purchase upsell, an order edit, a payment method that returns to the thank-you page twice, or staff and test orders. Break duplicated order IDs down by payment method and device to find it.

Need a clean setup?

Duplicates usually come with other problems, like missing checkout events or consent not reaching the checkout. My Shopify tracking packages replace the stack of apps and scripts with one documented setup, checked order by order. Book a free 30-minute call to see what yours needs.

Elliot Latil

Full Stack Web Analytics expert: GA4, GTM, server-side tracking and Shopify. About me