如何排除掉谷歌分析师GA4里的重复购买次数
如果你使用的是WordPress建站系统,且按照我之前写的转化价值追踪教程安装了GTM4WP插件的话,那么,你就可以继续看完这个教程,并按照教程去实践,从而排除GA4里的重复购买次数。
为什么会出现重复的购买次数
在使用Google analystics 去追踪woocommerce的转化次数数,你可能会遇到这种情况:purchase事件追踪的数量是远远大于真实的转化次数的。而在GA4的报表中,有一个指标叫做“交易量“,你会发现交易量可以反馈真实的订单数量,但是我们自己追踪到的purchase数据却不准确。这是为什么?
这是因为大部分营销人员在进行购买成功的转化追踪时,采用的是页面被浏览的次数来追踪, 他们通常会采用这样的正则表达式,如:
Page location contains /checkout/order-received (woocommerce的付款成功页面URL)
Page path contains thank-you (shopify付款成功的thank you page)
当然我自己也会这样设置,但是这种设置在以下情形下就会多次触发事件,导致重复记录。
通过电子邮件链接或书签返回页面
刷新付款成功页面
导航到不同的页面并通过后退按钮返回
从关闭的浏览器会话或手机上恢复页面
所以想要从根本上解决这个问题,就需要从追踪转化成功的方式来着手。URL的正则表达式已经证明是不靠谱的了,所以只能寻求其他的追踪方式。
直到我找到了这个老外的教程,英文好的同学可以直接看原文,我也按着这个教程走了一遍
https://www.simoahava.com/analytics/prevent-google-analytics-duplicate-transactions-with-customtask/
注意:前方高能预警,这套解决方案再次涉及到了大量的代码使用,调用逻辑和参数,变量之间的关系。实践起来有些烧脑,如果你有技术的同事,可以让让技术同学一起协助解决。
再次强调,使用这套方案的前提是你已经在网站安装了transactionId的数据层变量,并在GTM创建了相应的变量。如果没有transactionID的变量,那么这套方案,你便无法使用。
排除重复购买的原理
页面会刷新,但是交易ID是唯一的,如果我们以交易ID为维度,去记录购买次数,不就可以拿到100%正确的购买成功次数了吗。
实现的思路是在创建一个叫做customtask的变量,它会在每一次事件被触发的时候开始运行,在任务过程中,该方法会在触发事件的模型中查找键值,如果在浏览器存储中找到触发中的交易 ID,此 customTask 会阻止命中被触发,从而防止重复信息到达 Google Analytics。
直接用老外的图来解释吧
需要注意的时, 要使用这个方案, 你必须要要使用增强型电子商务, 对于 Standard Ecommerce,customTask 只会更新浏览器存储,但不会阻止任何内容。
如何排除重复的购买
我先放一张最终的完成图,按照教程实践后, 你的Google tag manger里会增加3个变量,2个触发器,和对purchase的tag修改。如下图所示。
我们先看变量部分,虽然是增加了3个变量,但是这3个变量当中, 需要调用到之前已经创建好了的transactionID变量,所以,我圈出了4个变量名称。因为你有可能需要根据你自己的transactionID的名称来修改其中一个变量中的代码。
触发器里有新增了2个。分别代表着发送transactionID为true 和购买完成
最后就是一个purchase的tag啦,可以看到, 它的触发已经不再依赖于page location的正则表达式了, 而是通过自定义JS来实现。
具体怎么做呢?
首先,创建好3个变量。
第一个变量A:customtask-transaction deduper
以下代码直接复制粘贴进去:
function() {
// customTask Builder by Simo Ahava
var transactionDeduper = {
keyName: '_transaction_ids',
cookieExpiresDays: 365
};
// DO NOT EDIT ANYTHING BELOW THIS LINE
var readFromStorage = function(key) {
if (!window.Storage) {
// From: https://stackoverflow.com/a/15724300/2367037
var value = '; ' + document.cookie;
var parts = value.split('; ' + key + '=');
if (parts.length === 2) return parts.pop().split(';').shift();
} else {
return window.localStorage.getItem(key);
}
};
var writeToStorage = function(key, value, expireDays) {
if (!window.Storage) {
var expiresDate = new Date();
expiresDate.setDate(expiresDate.getDate() + expireDays);
document.cookie = key + '=' + value + ';expires=' + expiresDate.toUTCString();
} else {
window.localStorage.setItem(key, value);
}
};
var globalSendHitTaskName = '_ga_originalSendHitTask';
return function(customTaskModel) {
window[globalSendHitTaskName] = window[globalSendHitTaskName] || customTaskModel.get('sendHitTask');
var tempFieldObject, dimensionIndex, count, ga, tracker, decorateTimer, decorateIframe, iframe;
customTaskModel.set('sendHitTask', function(sendHitTaskModel) {
var originalSendHitTaskModel = sendHitTaskModel,
originalSendHitTask = window[globalSendHitTaskName],
canSendHit = true;
var hitPayload, hitPayloadParts, param, val, regexI, trackingId, snowplowVendor, snowplowVersion, snowplowPath, request, originalTrackingId, hitType, nonInteraction, d, transactionId, storedIds;
try {
// transactionDeduper
if (typeof transactionDeduper === 'object' && transactionDeduper.hasOwnProperty('keyName') && transactionDeduper.hasOwnProperty('cookieExpiresDays') && typeof sendHitTaskModel.get('&ti') !== 'undefined') {
transactionId = sendHitTaskModel.get('&ti');
storedIds = JSON.parse(readFromStorage(transactionDeduper.keyName) || '[]');
if (storedIds.indexOf(transactionId) > -1 && ['transaction', 'item'].indexOf(sendHitTaskModel.get('hitType')) === -1) {
canSendHit = false;
} else if (storedIds.indexOf(transactionId) === -1) {
storedIds.push(transactionId);
writeToStorage(transactionDeduper.keyName, JSON.stringify(storedIds), transactionDeduper.cookieExpiresDays);
}
}
// /transactionDeduper
if (canSendHit) {
originalSendHitTask(sendHitTaskModel);
}
} catch(e) {
originalSendHitTask(originalSendHitTaskModel);
}
});
};
}
第二个变量B:cookie-_transactionId
这里的名字,请和我保持一模一样,不要改动,因为在其他变量里会调用这个名称。
第三个变量C:transactionId_sent
注意大小写, 要一模一样哦
在这段代码里,调用了之前已经创建过的transactionID的变量,所以这个为主,你自己需要检查下。
整段代码如下:
function() {
// Change this to match the keyName you added to customTask:
var keyName = '_transaction_ids';
var ids = JSON.parse((!!window.Storage ? window.localStorage.getItem(keyName) : {{cookie - _transactionId}}) || '[]');
return ids.indexOf({{Ecommerce_Transaction_ID}}) > -1;
}
接下来,是2个触发器
最后, 就是purchase的Tag设置了。
在你照着这套教程去使用的时候,也最好理清一下变量之间的调用关系。
变量B里调用了变量A里的key name:_transaction_ids, 变量C里调用了变量B的名称和已经创建过了的交易ID变量名称。
完成购物的触发器里的事件名称是woocommerce对于购买的事件名purchase,这个应该是写在GTM4WP这个插件里。
按照这个教程做好配置的后, 接下来要做的事情就是等待和调试了。毕竟购物成功这个东西,我可不想刷信用卡去支付购买再测试。因为我已经在GTM里做了屏蔽管理员访问的设置。。。
除此之外,我也看到另外一套解决方案,也是要写代码,但是它用到了一个叫做时间戳的变量, timestamp,这个数据层变量需要技术去操作。由于我的插件不支持这个数据层变量的植入,就无法尝试了,感兴趣的同学可以查看下面这个教程。
https://www.bounteous.com/insights/2020/09/02/duplicate-transactions-google-analytics-and-ga4-properties