Transaction tracking is often the key stone data set for reporting purposes, providing attribution to marketing spend, user value and detail breakdowns of how a website/application is performing.
Transactions can also be compared to the core business records, providing the ability to determine how accurate the website/application tracking is. So it really goes without saying that tracking this information accurately is key to gaining trust in the analytics, and providing the business with reliable insights.
One of the common issues that appears in transaction reports is the dreaded duplicate transaction. This issue does not always present itself easily as unless you’re running custom reports, or you’re actively looking for duplicate transactions.
Because they’re hard to find, they may be altering your data in some very negative ways without you actually knowing it. You could find distortion in your transaction totals, your revenue, and your product performance metrics (which, if you’re pure Ecommerce, is basically everything you care about).
The issue is often present when the order/receipt page can be revisited or re-viewed by the user, and this inadvertently triggers the transaction tracking again. That’s the most common cause, though note that some mobile browsers can also store the current website pages in memory when it’s closed/minimized, when loading the browser back up it reloads previous pages and therefore can trigger the order confirmation page again. A scenario that your development time might not be able to assist with.
Spotting the issue
Take a look at your transaction report, then create a custom report (flat table) that looks at Transaction IDs with the metrics of transactions and revenue. The result could be shocking! Take a look at the below example.
Standard Ecommerce Transaction Report
Custom Report “Duplicate Transactions Template link: https://analytics.google.com/analytics/web/template?uid=FK5maX3XRqSoatUVAMDR8A
Using a segment and User Explorer targeted to the “5” Transaction count Id.
Transaction report, specific to the “5” transaction count.
Looking at the above we can see the negative impact, note the user originally purchased 2 of the same item. As the website allows a user to review their receipt and inadvertently re-sends the transaction with every review we can see Google Analytics records the quantity and revenue x 5 times higher than the business records will.
While the ideal solution is to request your development team to prevent this, note it is possible and should be for most platforms, it’s a potential that this won't be an option for you.
If that's the case then following can help reduce the duplicate transactions but won’t entirely rule them out.
The Concept
- After successful transaction, store the Transaction IDs in the browser's cookie.
- Before tracking a transaction check the cookie to see if it has already been tracked.
This solution will use the unique Transaction ID. It will place this in the users browser cookie and before sending a transaction, perform a quick check to see if the id already exists, if it does it won’t resend the transaction. If not it will send and then add the id to the cookie.
As the solution requires cookies it will only work for the same device and browser, therefore if a user purchases on desktop and then reviews the order page on a different device/browser e.g. mobile, this solution won’t work due to how cookies behave. It will however eliminate a significant amount of the duplicates.
The Setup
- Google Tag Manager implemented on the main website
- Google Analytics is implemented on the main website
- Transaction tracking is done via the dataLayer
- Transaction tracking is using Enhanced Ecommerce
The Solution
Setting up the Variables
In order to store a Transaction ID for use in triggering and duplicate prevention, we need to setup the following variables.
Create the Variables Workspace > Variables > User-Defined Variables > New
Cookie - gtm-custom-transaction-ids This is used to get the stored transactions ids from the cookie.
Configuration | Value |
---|---|
Choose variable type | 1st-Party Cookie |
Name/Title | Cookie - gtm-custom-transaction-ids |
Cookie Name | gtm-custom-transaction-ids |
DLV - EE - Transaction - ID This is used to extract the Transaction ID from the dataLayer.
Configuration | Value |
---|---|
Choose variable type | Data Layer Variable |
Name/Title | DLV - EE - Transaction - ID |
Data Layer Variable Name | ecommerce.purchase.actionField.id |
CJS - Transaction ID is in Cookie This variable will use the current Transaction ID and compare it to values previously stored in the Cookie. If a match is found it will return “yes” otherwise by default it will return “no”.
Configuration | Value |
---|---|
Choose variable type | Custom JavaScript |
Name/Title | CJS - Transaction ID is in Cookie |
Custom JavaScript | Code Snippet below |
Code snippet:
function(){ try { var tid = {{DLV - EE - Transaction - ID}}; var ctids = {{Cookie - gtm-custom-transaction-ids}}; if(tid && tid.length > 0 && ctids && ctids.length > 0) { var tids = ctids.split(','); if(tids.indexOf(tid) >= 0) { return 'yes'; } } } catch (err){if({{Debug Mode}}) console.log(err);} return 'no'; }
Setting up the Transaction Trigger
The trigger that fires the Transaction Tag needs a rule that checks for duplicate transactions.
Create the Trigger Workspace > Triggers > New
Custom - EE - Transaction Complete - Prevent Duplicate This trigger will fire only when the current Transaction ID is not already present in the stored cookie value.
Configuration | Value |
---|---|
Choose trigger type | Custom Event |
Name/Title | Custom - EE - Transaction Complete - Prevent Duplicate |
Event name | custom.ecom.purchase |
Use regex matching | True |
This trigger fires on | Some Custom Events |
Trigger Rules
Use Variable | Match Type | Value |
---|---|---|
CJS - Transaction ID is in Cookie | does not equal | yes |
Tag setup
The setup requires two tags. The Google Analytics Transaction Tag (Event or Pageview that includes the enhanced ecommerce purchase data) and a Custom HTML Tag that will store the current Transaction ID in the users cookie.
Create the Tags Workspace > Tags > New
CHTML - Utility - Cookie - Store - Transaction ID This is used to store the transactions ids in the cookie. Please note this Tag will use sequencing, so no trigger is required.
Configuration | Value |
---|---|
Choose tag type | Custom HTML |
Name/Title | CHTML - Utility - Cookie - Store - Transaction ID |
HTML | Code Snippet below |
Triggering | No Triggers required |
Code snippet:
(function(){ try { var tid = {{DLV - EE - Transaction - ID}}; var ctids = {{Cookie - gtm-custom-transaction-ids}}; if(tid) { var update = false; if(ctids && ctids.length > 0) { if(ctids.indexOf(tid) == -1 ) { ctids += ','+tid; update = true; } } else { ctids = tid; update = true; } if(update) { var date = new Date(); date.setTime(date.getTime()+(30*24*60*60*1000)); // create expire time var cookieName = 'gtm-custom-tids'; // give cookie a name var cookieExpires = date.toGMTString(); // set expire time var cookiePath = '/'; // set cookie path document.cookie = cookieName + '=' + ctids + '; Expires=' + cookieExpires + '; Path=' + cookiePath; // set cookie } } } catch (err){if({{Debug Mode}}) console.log(err);} })();
This snippet will get both the current Transaction ID and any values stored in the users Cookie. If the current value does not exist in the cookie, it will add the value and update/create the cookie. It’s worth noting that the Transaction IDs are stored as a comma separated string, this allows for multiple values to be stored under one cookie key.
Create the Google Analytics Transaction Tag
Please note the Tag required for this next step will be dictated on how you are tracking transactions. This will be different between Standard & Enhanced Ecommerce tracking and could be a Pageview or Event Tag. For the purpose of this setup, the Transaction data is sent via a Google Analytics Event with Enhanced Ecommerce data.
The key configurations of your Tag will be:
- The Trigger “Custom - EE - Transaction Complete - Prevent Duplicate”
- Using Tag Sequence to fire the “CHTML - Utility - Cookie - Store - Transaction ID” after the Tag fires.
Workspace > Tags > New UA - Event - EE - Transaction - Complete
Configuration | Value |
---|---|
Choose tag type | Google Analytics - Universal Analytics |
Name/Title | UA - Event - EE - Transaction - Complete |
Track Type | Event |
Category | Ecommerce |
Action | Transaction Complete |
Label | {{DLV - EE - Transaction - ID}} |
Google Analytics settings | Select your Google Analytics settings variable |
Enable overriding settings in this tag | True |
More Settings > E-commerce > Enable Enhanced Ecommerce Features | True |
More Settings > E-commerce > Use Data Layer | Checked |
Advanced Settings > Tag Sequencing > Fire a tag after ... | CHTML - Utility - Cookie - Store - Transaction ID |
Triggering > Choose a trigger | Custom - EE - Transaction Complete - Prevent Duplicate |
Final Thoughts
If your analytics is impacted by duplicate transactions the ideal approach will to be work with your development team to prevent it occuring at the source. The solution presented here is a good short term alternative to help prevent duplicate transactions, however it is limited to the same device & browser.
Whenever you are editing/altering logic around transaction tracking, it should be thoroughly tested. While in principle the functionality is straightforward its purpose is to block transactions from firing, this could lead to legitimate transaction being blocked. So please take care and test, test, test.
I would also highly recommend using the same logic that prevents the transaction to trigger an event that indicates that a transaction was blocked (with no ecommerce data). This way you can see how wide spread the issue is and also help identify any issues with the setup should you be blocking legitimate transactions.