Duplicate dataLayer objects [GTM] - google-analytics

In a specific page (for not all) I see some objects duplicated in GTM dataLayer as given below.
Here is the reproducable version of the code:
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
'ad_storage': 'denied',
'analytics_storage': 'denied'
});
window.dataLayer.push({customerID: "", language:"en", em:""});
document.addEventListener("DOMContentLoaded", function(event) {
var gtmcode = '${gtmCode}',
gtmscript = "(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src='//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer', '" + gtmcode + "');";
eval(gtmscript);
});
What could be causing this problem, is this issue backend related?
Any help?

What seems to be the problem, does it break your tags?
dataLayer is an array of objects and it is normal to add new objects with same keys to the dataLayer. In your GTM you use either dataLayer variable Version 1 (takes into account only the currently added object = last added) or Version 2 (aggregates the array into one object and update keys and values so only the last added values for those keys remain - in your example for event=consent, only the second values remain).
This ensures that you don't have to worry about objects added multiple times into dataLayer.
More on DL variable in GTM: https://www.simoahava.com/gtm-tips/data-layer-variable-versions-explained/

Related

dataLayer.push is adding a new item instead of updating an existing one

I'm running some A/B tests with Google Optimize and am trying to just update a value in the dataLayer from my app but instead of updating it, it just adds a new object to it. According to the docs it should update if the key already exists.
Am I missing something?
For example:
// initiate dataLayer at the top of <head>
window.dataLayer = [{
message: ""
}];
// later after some stuff loaded
window.dataLayer.push({message: 'Test message'});
console.log(window.dataLayer) // added instead of updated
// [
// {message: ""},
// {message: "test"}
// ]
In short, and thanks to comment of #IskandarRezaRazali, it's working correctly but I should have been using window.google_tag_manager["GTM-XXXXXX"].dataLayer.get('message') (which will always give you the latest entry) to retrieve the value rather than trying to access it via index or having to do Array.find`.
Steven ,
Looks like you have missed the use of single quotes in your statement . In the documentation Google says
dataLayer.push({new-variable: 'value'}); // Won't work
instead
dataLayer.push({'new-variable': 'value'}); // Better
Look at the code below
<script>
dataLayer = [];
dataLayer.push({'message' : 'Test message'});
</script>
You can read the documentation here - https://developers.google.com/tag-manager/devguide

How is Google analytics gtag supposed to work in a SPA?

From what I can tell, how google recommends to set up gtag, it's a function that is always pushing more variables onto an array:
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
Following the docs on how to use it in a SPA, it seems I'm actually creating a memory leak.
gtag('config', 'GA_TRACKING_ID', {'page_path': '/new-page.html'});
console.log('window.dataLayer', window.dataLayer);
My console shows that every time I navigate to a new page the window.dataLayer array gets larger.
I'm assuming there's something I'm not understanding, because I doubt that Google wants me to create a memory leak in my app, but I'm stumped now.
The size of the dataLayer is capped at 300 (FIFO style) currently.
That's not currently documented and likely to change in the future. But the limit is there exactly to avoid blowing up memory in case repeated events happen inside the same page.
I do not know thoroughly but I assume this is just a normal array initialized before gtag is loaded. If the sole concern is to prevent this array from getting larger, then can't we create an array that prevents itself from getting larger than a set limit? Something like this?:
function createDL(limit){
var dL = [],//the array
iCounts = [];//the log of arg. length every time push is called
dL.push = function(){
if(this.length >= limit) {
return (
!!iCounts[1]
&&
(
this.splice(iCounts[0],iCounts[1]),
iCounts.splice(1,1),
this.push.apply(this,arguments)
)
);
}
this.constructor.prototype.push.apply(this,arguments);
iCounts.push(arguments.length);
return this;
}
return dL;
}
Usage:
window.dataLayer = dataLayer || createDL(5);
dataLayer.push(1,2,3);//1,2,3
dataLayer.push(4,5);//1,2,3,4,5
dataLayer.push(6);//1,2,3,6
dataLayer.push(8,9,10,11);//1,2,3,6,8,9,10,11
dataLayer.push("aaa");//1,2,3,"aaa"
I did not touch the first things pushed to dataLayer since they contain the "config" directive and some optional arguments. If the first things pushed to array are larger than the limit, obviously it will always return false and you can't push any longer.
In your case a limit would be 300.
Or am I missing something?

Google Tag Manager: dataLayer in a Custom Html tag

I would need to apply the same dataLayer to multiple sites that are using the same ecommerce system. Rather than copying/pasting the exact same DL onto multiple sites, I was thinking of pushing to the dataLayer withing a Custom HTML Tag in the GTM console.
Is that something specific you would recommend doing or not doing?
As a reference this is my DL:
var impressions = [];
var i, len;
var date1 = new Date();
var date2 = new Date(abe_searchParams["arrivalDate"]);
var timeDiff = Math.abs(date2.getTime() - date1.getTime());
var leadDays = Math.ceil(timeDiff / (1000 * 3600 * 24));
for (i = 0, len = abe_roomRatesData.length; i < len; i++) {
impressions.push({
'name' : abe_roomRatesData[i]['roomCode'] + "-" + abe_roomRatesData[i]['rateCode'],
'id' : abe_roomRatesData[i]['rateCode'],
'price' : abe_roomRatesData[i]['totalRate'],
'category' : abe_roomRatesData[i]['roomCode'],
'variant': abe_searchParams["iataNumber"],
'metric1' : leadDays,
'metric2' : abe_roomRatesData[i]['totalRate'],
'metric3' : abe_searchParams['numberOfNights'],
'metric7' : abe_roomRatesData[i]['totalRate'] / abe_searchParams['numberOfNights']
});
}
window.dataLayer = window.dataLayer || [];
dataLayer.push({
'event' : 'addtoCart',
'metric6' : leadDays,
'ecommerce' : {
'currencyCode': abe_hotelInfo["hotelCurrency"],
'impressions' : impressions
}
});
Thx
I would advise against this as a best practice. Pushing things onto the dataLayer in a custom HTML tag can be misleading for any future developers who will work on the code of the website as it will be very difficult for them to identify where the actual push is happening in the code.
If you want to implement GTM on several e-commerce sites, then your e-commerce platform should usually have some sort of templating system that allows you to build a GTM template of some sort that gets loaded by all the sites. This would be the cleaner approach.
You can definitely do that if you will be able to maintain it. And there is nothing wrong with if you will place this code in custom HTML tag

Populating Array Data from Data Layer into GTM

I have a Data Layer that is giving me information like this from Drupal
dataLayer = [{
"entityType":"node",
"entityBundle":"article",
"entityTaxonomy":
{"funnel_path":{"2":"Find a Park"},
"byline":{"4":"Name1","5":"Name2"}},"drupalLanguage":"en",
"userUid":"1"}
];
</script>
I can easily use GTM's Data Layer variable to pull in entityBundle. How do I set it to pull in the information in byline? I tried entityTaxonomy.byline, but that give me an array. I can set to do entityTaxonomy.byline.4 to get Name1, but that would be silly since the editors would be regularly adding things.
I am planning to add the byline, ultimately, into Custom Dimension 2 in Google Analytics.
I am looking to have the data that goes to Custom Dimension 2 to be Name1, Name2 . Sometimes this will be just one value. Sometimes it can be up to 20 values.
What do I need to do in GTM to get it to register that information?
entityTaxonomy.byline actually gives you an object. You would need to do a bit of processing to get an array that you can join into a string. One possible way would be
temp = [];
Object.keys(test.entityTaxonomy.byline).map(function(key, index) {
temp.push(test.entityTaxonomy.byline[key]);
});
bylines = temp.join(",")
(I'm sure that could be done much more concise). In GTM you would need to create a variable that contains the objects with the bylines, then you could do the processing in a custom javascript variable (which is by definition an anonymous function with a return value)
function() {
var byLineObject = {{bylines}} // created as datalayer var beforehand
temp = [];
Object.keys(byLineObject).map(function(key, index) {
temp.push(byLineObject[key]);
});
return temp.join(",")
}

Unable to Push Custom Variables w/ Google Tag Manager to GA

I am trying to build remarketing audience lists within Google Analytics using GTM. I need some help figuring out how to pass custom variables via GTM thru the datalayer and into GA.
So far, I have been able to successfully do this by hard coding some custom code and passing custom variables directly into GA (bypassing GTM). However, when I use this code it skews the GA numbers b/c 2 instances of the same GA that are present via custom code, and existing GTM instance. Which is great since it inflates the numbers favorably ;) Unfortunately, we are currently very dependent GTM, and therefore cannot abandon it.
What we are now trying to do is modify the working code to use with GTM so that we are not inflating our numbers as mentioned. Thus far, we can see this data in the datalayer by inspecting the console in chrome. However, we haven’t been able to push this data to GA.
Here is an example of the code that we used previously which does not rely on GTM and is successfully pushing the custom variables to GA.
<script>var _gaq = _gaq || [];_gaq.push(["_setAccount", "UA-XXXXXX-X"]);_gaq.push(['_setCustomVar', 1, "Category", "testing", 3]);_gaq.push(['_setCustomVar', 2, "content-type", "Brief", 3]);_gaq.push(['_setCustomVar', 3, "publish-date", "Wednesday, July 16, 2014 - 17:42", 3]);_gaq.push(['_setCustomVar', 4, "author", "Greg Bates", 3]);_gaq.push(["_trackPageview"]);(function() {var ga = document.createElement("script");ga.type = "text/javascript";ga.async = true;ga.src = ("https:" == document.location.protocol ? "https://ssl" : "http://www") + ".google-analytics.com/ga.js";var s = document.getElementsByTagName("script")[0];s.parentNode.insertBefore(ga, s);})();</script>
For the current GTM implementation, there is a bit of a hybridization using GTM and hard coding a newer script which I will detail below.
In my standard GA tag for GTM it is setup as follows:
Tag Name: GA Universal
Tag Type: universal analytics
Tracking ID: UA-XXXXXX-X
Enable Display Advertising Features √
Track Type: Page View
Firing Rules: All pages
More Settings>>Custom Dimensions:
Index = 4 Dimension = {{Author}}
Index = 3 Dimension = {{Publish Date}}
Index = 2 Dimension = {{Content Type}}
Index = 1 Dimension = {{Page Category}}
The custom code that is hardcoded into the page manually is as follows:
<script>
if (Drupal.settings.common !== undefined && Drupal.settings.common.pageCategory !== undefined) {
dataLayer = [{
'pageCategory': Drupal.settings.common.pageCategory
}];
var google_tag_params = {
section: Drupal.settings.common.pageCategory,
pagetype: ' ',
membertype: ' '
};
if (Drupal.settings.common.contentType !== undefined) {
dataLayer.push({'contentType': Drupal.settings.common.contentType});
google_tag_params.contenttype = Drupal.settings.common.contentType;
}
if (Drupal.settings.common.publishDate !== undefined) {
dataLayer.push({'publishDate': Drupal.settings.common.publishDate});
google_tag_params.publishdate = Drupal.settings.common.publishDate;
}
if (Drupal.settings.common.author !== undefined) {
dataLayer.push({'author': Drupal.settings.common.author});
google_tag_params.author = Drupal.settings.common.author;
}
}
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXX');</script> <noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-XXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
I‘ll also add that Drupal.settings.common.author, Drupal.settings.common.contentType, Drupal.settings.common.pageCategory and Drupal.settings.common.publishDate are defined before executing the GTM script.
Can anybody provide some helpful insight as to what we are doing incorrect and what can be done to pass these custom variables into Google Analytics?
If it would be helpful to see a live implementation, please follow this link http://api.pw/Uem8ba .
Thanks in advance of your time and help!
Brett
ok, first of all, since it's Drupal - drop your custom implementation in favor of these two modules:
https://www.drupal.org/project/google_tag
https://www.drupal.org/project/datalayer
Configure GTM container ID, and pass all the data you need via dataLayer - if after enabling all checkboxes in data_layer module you don't have everything you need in data layer, you have to use alter hook from this module, to push your variables there - since your code is ready it should be very easy.
Next, you have to configure GTM to collect your data in GTM and pass it to GA, so:
add a macro choosing "dataLayer variable" as a type
put variable name in the input and name it (it'd be best to name it in the same way for debuging purposes)
repeat 1 and 2 for remaining 3 dimensions
edit your standard GTM GA tag by expanding "more options->custom dimensions" and add there your dimension numbers and varaibles you've configured in steps 1-3.
save updated tag and click "preview button" to launch your site with GTM debug bar at the bottom
check in the debug bar if your data has been passed to dataLayer and then if variables were matched and passed on to GA
nobody said using GTM is simple ;)

Resources