Fix guides

transaction_id in GA4: what it does and how to get it right

transaction_id is the order number you send with GA4's purchase event. GA4 uses it to drop a second purchase with the same ID on web streams, and to match refunds to orders. Send your real, unique order number on every purchase: never empty, never a fixed value, never anything that identifies the customer.

Check your own site: the free scan tells you in about a minute whether this problem is on your page.

What GA4 does with it

Google's ecommerce documentation asks for a transaction ID on every ecommerce event, for two reasons: to deduplicate purchases and to process refunds. In practice that means:

  • When two purchases arrive with the same transaction_id, GA4 keeps one. This works for web streams only, not app streams.
  • A refund event with the same transaction_id is tied back to the order.
  • Every purchase with the same ID counts as the same order. So a value that never changes, or an empty string, makes GA4 treat all your orders as one and throw the rest away.

Google Ads uses the same idea: the order number as transaction_id on the conversion stops a reload of the thank-you page from counting twice.

Where it is in the request

In the data layer it sits inside ecommerce, next to value and currency:

dataLayer.push({ ecommerce: null });
dataLayer.push({
  event: 'purchase',
  ecommerce: {
    transaction_id: '10045',
    value: 1299.00,
    currency: 'SEK',
    items: [{ item_id: 'SKU-123', item_name: 'Wool scarf', price: 1299.00, quantity: 1 }]
  }
});

In the request to GA4 (DevTools, Network tab, filter on collect) it shows as ep.transaction_id on the request with en=purchase:

…/g/collect?v=2&tid=G-AB12CD34EF&en=purchase&cu=SEK&epn.value=1299&ep.transaction_id=10045…

If you send several events in one request, they are in the request body instead of the URL. Open the Payload tab and look for the line with en=purchase.

Five ways it goes wrong

  • Missing. Every time a shopper reloads or bookmarks the thank-you page, or comes back to it from the confirmation email, GA4 records another purchase. Revenue and conversion counts drift above your real orders.
  • "undefined", "null" or a template placeholder. A Tag Manager variable that does not resolve sends the same text on every order, and GA4 then counts only one of them. The symptom is the opposite of the one above: far fewer purchases in GA4 than in your shop.
  • Empty string. Same problem. Google's documentation specifically warns against sending "".
  • The old Universal Analytics format. Shops that moved from Universal Analytics sometimes still push the order number as ecommerce.purchase.actionField.id. GA4 expects ecommerce.transaction_id.
  • Customer data in the ID. An ID built from an email address or name sends personal data to Google, which its terms do not allow. Use the order number your shop already assigns.

Find the problem in your reports

  1. In GA4, open Explore and start a blank free-form exploration.
  2. Add the dimension Transaction ID and the metrics Ecommerce purchases and Purchase revenue, and set a date range of a few weeks.
  3. A row called (not set) is purchases with no transaction ID. A few rows with very large counts (an ID like undefined, 0 or your placeholder text) point to a variable that does not resolve.
  4. Compare the number of distinct transaction IDs with the number of orders in your shop for the same days. Large gaps in either direction come from one of the five problems above.

Test the fix

  1. Place a test order with DevTools open on the Network tab and filter on collect.
  2. On the confirmation page, the en=purchase request should carry ep.transaction_id with the real order number from your confirmation email.
  3. Reload the confirmation page. Best case, no second purchase request is sent. Otherwise, it must carry the same ID so GA4 drops it.
  4. In GA4, DebugView (with Tag Assistant debug mode on) shows the purchase event with its transaction_id parameter within seconds.

Scanning the confirmation page with Plumfinch checks the same thing: the scan reports "Google Analytics 4 purchase has no transaction_id" when it is missing.

Sources

Based on the platforms' public documentation; menus and names change, so check the linked pages if a step looks different.