Duplicate transaction protection

Last updated ·

Duplicate transaction protection is a GTM Kit Premium option in the Template Assistant, and it is off by default. Select it under Duplicate Transaction Protection when you generate your server container template, then import the template into your server container.

What it does

An order can reach your server container twice. Once from the browser, when the shopper lands on the thank-you page, and once from GTM Kit’s server-side webhook, which sends the purchase from WooCommerce whether or not the shopper ever got back to your shop. That second path is the point of webhooks: it is what recovers a conversion when a payment provider never returns the customer. It also means a healthy checkout can deliver the same sale twice.

With duplicate transaction protection selected, the container records each transaction ID the first time it sees it. If the same ID arrives again, your purchase conversion tags are skipped. Whichever path delivered the order first wins, and the other one is ignored.

It covers the purchase-carrying conversion tags on both paths: Google Ads, Meta, TikTok, LinkedIn, Microsoft, Pinterest, Reddit and Snapchat. Everything that is not a purchase, such as add-to-cart or product views, is untouched, because the check is tied to a transaction ID and those events do not have one.

The GA4 tag is deliberately not gated this way. Its trigger covers every webhook event, not just purchases, so gating it would gate order_paid and the rest along with the sale. For GA4, send the purchase from one side only: GTM Kit’s own “send only if the browser did not confirm” webhook trigger setting does that at the source, and the two features are designed to work together rather than instead of one another.

Choosing where the transaction IDs are stored

The check needs somewhere to remember the IDs it has already seen, and that is the only real decision you have to make.

Container hosted on Stape. Choose the Stape row. There is nothing to set up: it uses the store that comes with your container.

Anywhere else. Choose the Firebase / Firestore row. This needs your own Google Cloud project with Firestore in Native mode, using the default database, and you will be billed by Google for it. Creating and paying for that project is the reason this feature is off by default rather than simply switched on for everyone.

Pick one row, not both.

Two limits worth knowing

It can be beaten by a photo finish. The check reads the store, and then writes to it. There is no lock between those two steps. If the browser event and the webhook arrive at the container at very nearly the same instant, both can read “not seen yet” before either has written, and both will fire. This is a real race, not a theoretical one, and it is exactly the case that GTM Kit’s browser-confirmed webhook trigger removes at the source by not sending the second copy at all. Use both if double counting matters to you.

A storage failure lets the duplicate through, on purpose. If the store cannot be reached, the check returns no answer, and a tag with no answer fires. The same is true of an order that arrives with no transaction ID at all. This is the safer of the two failure directions: a duplicate is visible in your reports and can be reconciled, whereas a conversion the container silently swallowed is gone and you will never know it was there.

Credits

The duplicate transaction check is performed by the Duplicate Transaction Checker variable template by Stape, bundled under the Apache License 2.0.

Related articles

← Previous

Previous article

Next →

Next article