GA4 transaction_id on Shopify: missing, empty or wrong
The transaction_id is one field in one GA4 purchase event, but get it wrong and Shopify orders can be undercounted, duplicated or impossible to reconcile with your store. The usual implementation problems are a missing ID, an empty value, a repeated one, or two tracking systems sending different IDs for the same order.
The short answer. Send a unique transaction identifier for each order, as a string, and use the same value from every purchase sender. On Shopify, read it from the completed order in the checkout_completed event.
Check what GA4 received in an exploration, then place a fresh test order and inspect the resulting purchase in DebugView.
What transaction_id does
Google's purchase reference lists four required parameters, transaction_id, value, currency and items, and describes the ID as the unique identifier of a transaction that helps you avoid getting duplicate events for a purchase. Google's transaction ID page goes further. It says to add a transaction ID to every ecommerce event so purchases can be deduplicated and refunds processed, that GA4 deduplicates purchase events with the same ID, that this works only for web streams and not app streams, and that the same ID should not be used across different users. Google describes this as deduplication of purchase events, so do not expect it to remove other duplicated events.
So the ID has two jobs. It lets GA4 recognise a purchase it has already seen, and it lets GA4 tie a refund back to the sale. Everything below is a way of failing at one of them.
The 5 ways transaction_id goes wrong on Shopify
1. It is missing
The purchase arrives with a value and items but no transaction_id. GA4 then has no transaction ID to use for purchase deduplication. If the purchase event fires again, for example when a confirmation page is revisited, there is nothing to recognise it as the same transaction. In reports, a purchase with no transaction ID can appear as (not set) for the Transaction ID dimension. It is often the result of old hand-built code that never read the order ID, or a tag whose ID field was left blank.
Fix. Map the order ID into transaction_id in whatever sends the purchase. Our post on theme-code tracking shows the before and after.
2. It is empty
The opposite failure, and the nastier one, because it undercounts. Google's instruction is not to send an empty string, and it warns that GA4 will deduplicate every purchase event that has transaction_id="", so all of them are treated as one order. It happens when a variable that should hold the order ID resolves to nothing, for example a Tag Manager variable pointing at a dataLayer key that is not there on that page.
Fix. Find where the value comes from and why it is blank at the moment the purchase is sent. Then test with a real order.
3. It is the same for every order
Google says the ID must be unique for each order, and to pass a dynamic value so you do not undercount by sending identical IDs across different transactions. Google's own example for the field is T_12345, which is easy to leave in a tag by mistake. Used as a fixed value in a live tag, it can cause the same kind of undercounting as an empty ID. The ID should not be reused across different customers either.
Fix. Search your tags and pixels for T_12345 and for any ID typed in by hand.
4. Two tracking systems build it differently
One sender uses the order's ID, another uses the order number you see in Shopify admin, or the same number with and without the #. If two purchase events reach the same GA4 web stream with different transaction IDs, GA4 cannot use those IDs to recognise them as one purchase, which can result in the order being counted more than once. This is the classic double install, covered in how to find the second purchase.
Matching IDs help only where deduplication applies. Google says it works for web streams and not app streams, so do not assume that using the same ID deduplicates every setup.
Fix. Pick one identifier and make every sender use it. If you only need one sender, keep one.
5. It is not sent in the expected format
Google defines transaction_id as a string and says it must be unique for each order. What matters is less whether the value looks numeric than whether it is a consistent, unique identifier for the order.
Fix. Convert the order identifier to a string when you build the purchase event, and make sure every sender uses the same value.
Not sure how GA4 reaches your store? The free pixel checker reads your homepage and shows whether GA4 comes from an app, your theme or Tag Manager, which tells you where an ID could go missing. Check your store's pixels →
What should Shopify send to GA4?
Shopify's pixel events carry the order's ID where you need it. The checkout_completed event has checkout.order.id, and Shopify's reference says that ID is null for every event except checkout_completed, so read it there and nowhere earlier. In a custom pixel that sends GA4 itself, it looks like this.
analytics.subscribe('checkout_completed', (event) => {
const checkout = event.data.checkout;
// skip rather than send a blank or "undefined" ID
if (!checkout.order?.id) return;
gtag('event', 'purchase', {
transaction_id: String(checkout.order.id),
// value, currency and items as before
});
});
This example assumes gtag is available inside your pixel and that the rest of the purchase payload is filled in correctly. If you send through Tag Manager or an app, the same rule holds. Whatever your sender calls the field, it should come out as a unique identifier for the order, as text.
Shopify order ID or order number
A merchant asks "my order is #1042, so is my transaction ID 1042?" It can be, if that is the value every sender consistently sends and it is unique. But do not assume it. Shopify's reference describes order.id only as the ID of the order, a string or null, and the order object in that event carries no order number. So the value a pixel sends may not be the number you see in your admin. Whichever you choose, compare what each of your senders actually sends against your orders, and make them agree.
Keep customer details out of it
Use an order identifier, not an email address, name or phone number. Google says transaction IDs must omit any information that could be used to identify individual customers.
What a healthy Shopify GA4 purchase looks like
A completed order should produce one recorded purchase, a purchase event containing all of these.
- A unique
transaction_id, as a string - The order
value - The
currency - The purchased
items
If more than one system sends the purchase, they should agree on the transaction ID. If a purchase reaches GA4 without an ID, or different systems send different IDs for the same order, investigate the setup before trusting the purchase numbers.
Check your store in five minutes
- List purchases by Transaction ID. In GA4 open Explore and create a Free form exploration. Add Transaction ID as the dimension and Ecommerce purchases as the metric, and set the date range to a few recent days. Google's Transactions report also lists purchases by Transaction ID with the same metric.
- Read the list against this table.
| What you see | What it may mean |
|---|---|
| Unique IDs in a consistent format | The IDs look healthy for the purchases GA4 received. This does not prove every Shopify order reached GA4. If the totals still disagree, look at consent, ad blockers and checkout routing. Why the numbers don't match. |
A large (not set) row | Some purchase events arrived without a usable transaction ID. Failure 1, and possibly failure 2. |
| One repeated ID with a huge count | An empty or fixed value may be reused, so purchases are merged. Failures 2 and 3, and a cause of undercounting. |
| The same order with two different IDs | More than one sender may be firing, each building its own ID. Failure 4. |
| IDs that do not match what you expected from Shopify | Compare the ID each implementation sends against your orders. Do not assume the order number and the ID in Shopify's pixel events are the same thing. |
- See what GA4 flags itself. Google's purchase event diagnostics can report purchase events from your Google tag that are missing a transaction ID, IDs reused across different user identifiers, and a very low transaction ID overlap between a data import or Measurement Protocol source and your tag. If they appear in your property, read them alongside your own list.
- Prove it with one test order. Place a test order, open the
purchaseevent in DebugView and read thetransaction_id. It should be this order's ID, once. Step by step in how to test a GA4 purchase in DebugView. - Use a fresh order each time you retest. Google's validation guide warns that because GA4 deduplicates repeated transaction IDs, retesting with the same ID can make a working event look missing.
If you have the code that sends the purchase, the free GA4 purchase event checker flags a missing, empty, example or non-string ID against the same reference. It runs in your browser, so nothing you paste leaves it.
What this check shows
- Whether GA4 received an ID on each purchase it recorded
- Whether any ID is blank, repeated or in two formats
- Whether the IDs agree with the orders in your admin
What this doesn't prove
That every order was tracked. A clean transaction ID list only covers the purchases GA4 received, so a purchase lost to a declined cookie banner, an ad blocker or a checkout the tag never runs on leaves no row to inspect. AuditTag's free audit reads your public pages, so it cannot see the ID in a purchase event at all. That takes a test order.
Questions people ask
Is transaction_id required for a GA4 purchase event?
Yes. Google's purchase event reference lists it as a required parameter, alongside value, currency and items. Without it you lose the identifier GA4 uses to deduplicate purchases, and Google says to add one to every ecommerce event so purchases can be deduplicated and refunds processed.
What should I use as the transaction_id on Shopify?
A value that is unique for each order, sent as a string and used by every purchase sender. In Shopify's checkout_completed event the order's ID is checkout.order.id. Shopify's reference does not say it matches the order number shown in your admin, so check which value each of your senders uses rather than assuming.
Does GA4 remove duplicate purchases with the same transaction_id?
Google says it deduplicates purchase events that share a transaction ID, but only for data from web streams, not app streams, and the same ID should not be used across different users.
Why does GA4 show far fewer purchases than Shopify?
One cause is an empty transaction_id. Google warns that it deduplicates every purchase whose ID is an empty string, so they are all merged into one. A fixed ID reused across orders can undercount in a similar way. Check the transaction ID list for one row with a huge count. If that is not it, consent, ad blockers and checkout routing are the next things to look at, covered in why Shopify and GA4 purchases don't match.
See what is sending GA4 from your store
AuditTag checks the installation. It reads your public Shopify pages and shows which tracking tags are installed and where, including a second GA4 route that could send the same order with a different ID. The purchase event checker checks the event code you paste in. A test order confirms what actually reaches GA4. The audit cannot see a purchase fire or what ID it carries.
Run a free audit →