Manipulate dataLayer using Google tag manager - google-analytics

Is it possible to get a value from the dataLayer, modify it and push it back to the dataLayer?
I used this custom HTML for that, but it returns NaN (Not a Number), thoughts?
<script type="text/javascript">
(function() {
amsdataLayer.push({
'roomcount' : 6*('roomcount').float()
});
})();
</script>

If roomcount is currently in the dataLayer (for precisions sake: if it is in the dataLayer and you access it via a GTM variable) you need to use double curly brackets to access it, i.e. {{roomcount}}. Currently you are applying your calls to the literal string "roomcount", which does not result in a number (also, is there really a float() method for numbers in JS ? Currently I can only think of parseFloat which has a different syntax).
Also you need a (native or custom) event to make GTM aware of changes to the dataLayer.

Related

Can I replace dataLayer.push() with gtag()?

While trying to implement and understand the use of Google Tag Manager and Google Analytics I was wondering why there is talk about dataLayer.push() in some places while gtag() is used for similar operations in other places. They seems to be serving the same purpose even though the result is not exactly the same.
gtag() is defined as:
function gtag(){dataLayer.push(arguments)};
If I try the code I get a wrapping Arguments-object when using gtag. So I understand that there is a difference, but does this matter and should they be used for different purposes?
> dataLayer = []
> dataLayer.push({'event','login'})
[{'event','login'}]
> dataLayer = []
> gtag({'event','login'})
[Arguments({'event','login'})]
When should either one of them be used or could I resolve to only using one of them?
Well, there is no difference. gtag() is just a wrapper JS function around dataLayer.push(). However, gtag is preferable.
The reason for using gtag is to avoid any action that might pollute or change data inside dataLayer object by accident, which might affect analytic data.
Technically, they're the same, and you can use either ways.
Personally, when tagging events, I usually create my own function:
// definition
function gevent(name, data) {
gtag('event', name, data);
}
// sample
gevent('level_up', { userId: 123, prevLevel: 12, currLevel: 13 });
gevent('logout', { userId: 123 });

Google tag manager problem - Firing an event early, before "container loaded" message

I am trying to capture IP address, hash it and store the value in session-scoped dimension in Google Analytics
First, I am firing a custom JS tag to get user IP using this method :
function getIP(json) {
dataLayer.push({"event":"ipEvent","ipAddress" : json.ip});
}
</script>
<script type="application/javascript" src="https://api.ipify.org?format=jsonp&callback=getIP"></script>
The script creates an "ipEvent" which pulls the user IP and triggers the "hash 2 ip scrambled" event to hash the values.
Everything works fine but the problem is when I need to send hashed values via Pageview which is executed on [3] Container loaded.
You can see from the screenshot that the script to get IP was executed before "[3] Container loaded" message but an actual event happened after.
Any idea how this can be done (get "ipEvent" before [3] Container loaded)
No need to fire a tag for this. Well, maybe to load the hashing code. But I would just use some simple hashing function and run it inline rather than loading it from elsewhere. Unneeded network requests should be avoided.
Move your main hashing logic to a CJS variable and return the hash instead of touching the datalayer.
Now reference your shiny CJS variable in whatever tag you wanna use it in. Or, better yet, in GA config variable. Up to you really.
As a result: everything works, but no changes to DOM and to the global JS scope.
Your JSONP request is asynchronous - you send the request and the callback is executed when the results come back.
To make sure that the result of the ip api call is pushed reliably as the first event, you would have to make a synchronous call, which ipify does IMO not support (I might be wrong here) and which you do not want, because you would need to stop execution of everything else in your GTM installation. In that case you would also have to handle timeouts somehow etc. Not a good idea (and even if you resolve it outside GTM, you do not know when the result from the API call comes back).
If you really want to make sure that the IP is available in a given tag, use a tag sequence. In that case you need to include an onHtmlSuccess call in your callback function, which signals that your setup tag has executed and subsequent tags can be triggered. From the top of my head, it should look something like this:
<script>
function getIP(json) {
dataLayer.push({"event":"ipEvent","ipAddress" : json.ip});
var gtm = window.google_tag_manager[{{Container ID}}];
gtm.onHtmlSuccess({{HTML ID}});
}
</script>
<script type="application/javascript" src="https://api.ipify.org?format=jsonp&callback=getIP"></script>
Use this as setup tag in a tag sequence for the tags that require the IP. Set the follow up tag to only fire when the setup tag was successful, and set the setup tag to fire only once per page, so that the API call is not repeated for every tag.
While this does not make your tag fire before the first event (so technically it does not answer your question) it does make sure that tags require the IP are deferred until the IP is available, which as a result is probably somewhat close to what you want.

How to use GTM trigger name in custom javascript conditional statement?

I'm wondering whether it is possible in a custom javascript variable in GTM (google tag manager) to find the "trigger name" that the variable is called by and use this in a conditional statement within the variable? I can find anything online about this? Is there something way of using the API maybe. I know we can get variable names with the curly braces. Anything like this for triggers?
Cheers
Usually triggers are based on built-in variables, and if you need to, you can reconstruct the trigger in your custom JS and then refer to it elsewhere.
For example, if you want to track a certain type of link click, you might start by creating the custom JS variable isTargetLink:
function() {
var targetLinkClass = 'relevant-css-selector'
if (targetLinkClass === {{click classes}}) {
return true;
}
}
You can then save this and refer to isTargetLink in another custom JS variable, e.g.
function() {
if ({{isTargetLink}}) {
// do something
}
}

Google Tag Manager - Parse Dynamic Data Layer Variable

I want to parse a 'pushed' data layer string. I intend to use it to track click events and setup the appropiate funnels in Google Analytics, it looks as follows: products.view.19|view recent product|19
The first part (products.view.19) is the unique page identifier.
The second part (view recent product) is the action.
The last part is (19) is the action identifier, this way actions may be grouped and compared more easily.
So I did the following, I first created a trigger (it fires when a link has the tag 'data-trackclick' in it) which pushes the data value to a variable (variable for datalayer). However, now I want to split that variable in to 3 new variables, as described above. I selected 'javascript macro' for this but somehow it returns 'undefined'. The macro looks as follows:
function() {
var data = {{TrackClickData}};
var pieces = data.split('|');
if (pieces[0].length()) {
return pieces[0];
} else {
return data;
}
}
Obviously this didnt work since it would only run on the initial load and not (like I thought) when the macro was requested, so it should somehow be fired on the 'click' and then set the variables accordingly.
Is this possible to do? Or do I really have to add the dataLayer.push() in script tags?
A few things:
.length() is wrong, the property for array length is .length without the ()
if it exists, pieces[0] is not an array, then .length would return the string length, see How do you check for an empty string in JavaScript? for more standard way of checking for empty strings
Is this possible to do? There's virtually nothing you can't do with GTM, since you can write JavaScript code, you can do whathever you code allows you to do, and splitting a string to use parts of it as variables is certainly within the realm of possibilities.
My advise is to make your code work outside GTM first (eg test it in the browser console), then once it's all working, port it to GTM.

Implementing Finite State Machine for Web UI

I am intending to develop a Finite State Machine in the following manner.
Extract Control IDs from a --> web-page,
Write control IDs to a XML --> Controls-XML.
Manually declare States and Transition in the --> Controls-XML
Scan Controls-XML and attach pre-declared Jscript to eventhandlers embed them in the --> web-page..
5.
How feasible this would be..
Am I getting into can of worms ?
First, we live in a can of worms!
your questions are a bit vague, please provide more details if i'm missing your point and maybe this should be beak in parfts to deepen the discution in part details
assuming you want to work live on a client side browser over any page
by extrating ID's of controls i supouse it's all controls of a webpage (it could be by clicking or clicking possibly with key combos), but lets be simple.
Extrating ID's
here's a code than might help you:
function scan(e) {
if (e&&e.childNodes)
for(var i=0;i<e.childNodes.length;i++) {
var child=e.childNodes[i];
if (child) {
if(child.id) console.log(child.nodeName,child.id);
scan(child);
}
}
}
note: this was done with chrome, but any browser console will do i think.
just paste the function on the console and then call it like:
scan(document)
and it will list (on console) all elements that have id's showing element type and id... you can filter that eazy by just printing elements of certain tags like INPUT, SELECT TEXTAREA, etc...
About the XML
here browsers get a bit tricky, you can simplify it too your favorite browser, the following functions constructs a XML document given some XML text.
So by this aproach your scan function should compose the xml text (instead of writing to the console) and later we can feed the XML document
function makeNode(text) {
var doc;
if (window.ActiveXObject) {
doc=new ActiveXObject("Microsoft.XMLDOM");
doc.async="false";
doc.loadXML(text);
} else {// code for Mozilla, Firefox, Opera, etc.
var parser=new DOMParser();
doc=parser.parseFromString(text,"text/xml");
}// documentElement always represents the root node
return doc.documentElement;
}
other aproach is to create an empty XML document (as the above function does) and the instead of feed raw xml text your scan function should use XMLDOM commands to insert nodes into the document.
Manually declare States and Transition in the --> Controls-XML
this is an hard one, is this (XML doc) info to be copy/pasted and latter edited? is it edited inplace by inserting a bunch of code to build an interface?
many doubts here, but once we have the information in XML format we would be free to use our imagination and decide a format to handle the wanted state changes.
Scan Controls-XML and attach pre-declared Jscript to eventhandlers embed them in the --> web-page
at this point actions depend on methods followed above, but in any case using XMLDOM functions to traverse the xml doc and apply status change or event handlers to the controls is trivial.
controls need not be scanned anymore because we have stored the id's (use getElementById)
i have a form validation system that does something similar, except the XML is predefined and stored on server side, but once loaded it will do just that. attaching event handlers and do status changes based on evaluated expressions.

Resources