Marketing Operations
How to Investigate Duplicate GA4 Purchase Events and Transaction IDs
A practical guide to missing, repeated and reused purchase IDs, with a synthetic SQL audit and clear limits on what event rows can prove.
Your purchase-event count has jumped, but the order system has not. Before changing your campaign budget or deleting rows, check what was collected, which identifier each event carried and what your analytics report actually counts.
A repeated transaction ID is a useful clue. It might be a confirmation-page replay or a retry. It can also mean two genuine orders were assigned the same identifier. A missing ID is a different problem again. These cases need different fixes, and none can be quantified as lost revenue from the event count alone.
This guide is for ecommerce marketers, analysts and implementation owners reviewing one purchase-event source at a time. The examples are synthetic. Sources were checked on 3 November 2026. The method profiles the evidence you have; it does not claim to reconstruct true orders or prove a reporting error.
What to check first
- Freeze one source, property, stream, event, period and timezone before comparing counts.
- Separate missing or blank IDs from nonblank IDs and document your comparison rule.
- Count repeated-ID rows as a diagnostic, not as confirmed duplicate orders.
- Verify any ID reused across distinct orders against an authorised source of truth and record how much you reviewed.
- Check collection, raw extracts and platform reports separately; they are different stages.
A purchase event is not an order ledger
An event is a record of something your instrumentation sent or collected. An order ledger records a business transaction according to its own rules. A single transaction can produce several events when a buyer refreshes a confirmation page, a network request is retried or more than one implementation emits a purchase. Conversely, one event may have no usable identifier, arrive late, be filtered, or carry an identifier reused for another transaction.
First identify the business decision. If the question is whether to increase paid spend, the team needs reliable cost and outcome data with compatible scope. An unusual event-row count alone cannot establish that a campaign caused more orders, or that money was lost.
GA4 and Adobe use different rules
Google's guidance says transaction-ID deduplication applies to purchase data collected through web streams, not app streams. Google also warns that sending an empty transaction ID can deduplicate all purchases carrying the empty string, while reusing an ID for separate orders can undercount. IDs should be unique to the order and omit information that identifies a customer. These statements are product-specific; they are not a promise that every raw export or report uses an identical rule.
Google's web-purchase diagnostics describe missing and non-unique identifiers as issues to investigate. A diagnostic is a starting point, not a complete reconciliation. Check the affected stream and collection method before making changes.
Adobe Analytics has its own purchaseID rules. Its documentation, updated 28 September 2026, describes duplicate handling across visitors, an expiry period and a length limit for AppMeasurement. Do not apply those details to GA4. An ID scheme that works in one product may require adaptation in another; check each destination before changing it.
Define the extract before calculating
Write down the property or source, web or app stream, event name, period, timezone, extraction time and expected processing delay. Record which rows are test events and how they were excluded. Keep refunds and order amendments separately defined: a refund is not automatically a duplicate purchase event.
Also document how you compare IDs. Are they case-sensitive? Are whitespace-only values treated as missing? Can two stores use the same short order number? A documented namespace may be necessary to distinguish stores, but adding one changes the key and must be reviewed with the implementation owner. Do not turn an email address, name or other personal data into an analytics transaction ID.
The purchase ID review worksheet gives the analytics and engineering owners one place to record these decisions and the next check.
A worked example: 100 event rows
Imagine a completed synthetic extract with 90 rows carrying a nonblank ID and ten rows with no usable ID. The 90 rows contain 75 distinct nonblank IDs. An authorised partial review confirms that four IDs each refer to more than one real order.
There are 100 observed event rows. Ten of 100 (10%) lack an ID. Among the 90 nonblank rows, 90 − 75 = 15 are repeated-ID rows: 15 ÷ 90 = 16.7%, rounded to one decimal. Four reused IDs are confirmed in the reviewed cases; the remainder may not have been checked. The calculator performs the same arithmetic and keeps an unknown reuse count distinct from zero.
Do not call the 15 rows duplicate sales. Some may be repeated delivery of the same order; some may represent different orders sharing a key. The ten missing-ID rows may include orders already represented among the 90. The extract therefore does not prove there were 75, 90 or 100 real orders. A zero confirmed collision count is meaningful only with review coverage beside it.
A small synthetic SQL audit
The SQLite example below uses made-up event and order references. It treats whitespace-only IDs as missing but keeps nonblank IDs case-sensitive and otherwise unchanged. Its order reference is assumed independently reliable for this demonstration; a missing order reference cannot prove a collision. Use only approved data and permissions in real work. Do not paste customer information into a public AI tool.
WITH purchase_events(event_id, transaction_id, order_ref) AS (
VALUES (1, 'A', 'order-1'), (2, 'A', 'order-1'),
(3, 'B', 'order-2'), (4, 'B', 'order-3'),
(5, '', 'order-4'), (6, NULL, 'order-5'),
(7, 'C', 'order-6')
), cleaned AS (
SELECT CASE WHEN transaction_id IS NULL OR trim(transaction_id) = ''
THEN NULL ELSE transaction_id END AS id, order_ref
FROM purchase_events
), groups AS (
SELECT id, count(*) AS event_rows,
count(DISTINCT CASE WHEN trim(order_ref) <> '' THEN order_ref END) AS observed_orders
FROM cleaned WHERE id IS NOT NULL GROUP BY id
)
SELECT (SELECT count(*) FROM cleaned) AS all_rows,
(SELECT count(*) FROM cleaned WHERE id IS NOT NULL) AS nonblank_rows,
(SELECT count(*) FROM groups) AS distinct_ids,
(SELECT count(*) FROM cleaned WHERE id IS NULL) AS missing_rows,
(SELECT count(*) FROM cleaned WHERE id IS NOT NULL) - (SELECT count(*) FROM groups) AS repeated_id_rows,
(SELECT count(*) FROM groups WHERE observed_orders > 1) AS confirmed_reused_ids;
The result is seven total rows, five with nonblank IDs, three distinct IDs, two missing rows, two repeated-ID rows and one confirmed reused ID. ID A repeats for the same synthetic order; ID B identifies two different synthetic orders. The query distinguishes the evidence available in this fixture. It cannot find reuse when the independent order reference is absent or wrong.
Investigate the cause before touching a report
- Missing or blank IDs: inspect how the event gets the order reference. Check confirmation-page and server paths separately. An empty value is not a safe universal fallback.
- Repeated IDs: compare event timestamps and source delivery evidence within permitted systems. Reproduce page reloads or retries in a non-production or synthetic environment; do not place real orders merely to test.
- Confirmed reuse: trace where a key is created, stored and passed between systems. Check collisions across stores, environments and truncated values. Agree a stable, non-personal order reference with the implementation owner.
- Report mismatch: compare like-for-like source, property, stream, dates, timezone, event definition, consent and data maturity. A raw export can contain observations handled differently in a platform report.
Record before-and-after extracts and changes in definitions. Do not rewrite historical totals or remove legitimate records without an approved reconciliation and a rollback plan.
Write a useful handoff
A short note can say: “In the selected extract, 10% of 100 event rows lack a nonblank ID. Fifteen of 90 nonblank rows repeat an ID; four IDs were confirmed to represent different orders in a partial review. We do not yet know the effect on reported sales. The analytics owner will inspect the source firing and ID generation next business day.”
The copyable review prompt can draft that note from anonymised totals. A person must verify its arithmetic and assumptions. If no AI tool is available, use the worksheet to write the same observation, limitation and next action manually.
For a tracking replacement project, use the separate tracking migration parity guide to compare old and new collectors. ID quality within one extract is a different question from whether two collectors saw the same events.