We have an app for cookie management and we can't seem to find a way to block/disable the GTM and its tags after it was initially executed/enabled without refreshing the page.
Basically, what we require is, if all of the cookie categories are initially enabled and therefore GTM is running initially, and after that, the visitor choose to change his cookie preferences and block all of the cookie categories, there is no way to block/disable the GTM(and his tags) without having to reset the page. The only workaround for that is to block the GTM script before it is loaded, but this requires a page reset.
We are looking forward to your reply.
There is a way to disable GTM, or to be more precise, to break the GTM instance running on the page.
GTM requires a "dataLayer" variable to work, that is an array of objects that communicates values from the frontend to the javascript that is the actual "engine" of client-side GTM. The datalayer is an array of objects.
GTM overloads the "push" method of the datalayer array with a custom function that, amongst other things, scans for the "event" key in datalayer objects. When it finds the event key, it updates the internal state of the variables an executes all triggers that are connected to that specific event.
So if you break that function, by re-initializing the datalayer variable or by overloading the push method again e.g. with a function that returns a null value, you effectively cripple GTM to a point where it can no longer execute tags.
datalayer.push = function() { return null; }
This will not unload the file (unloading JS is not possible without a reload), it will not purge GTM from memory and will not remove anything that GTM has injected into the page up to this point. This is a bit of a hack, and the datalayer variable name is configurable, so you need to check first how the datalayer is actually called. But breaking the datalayer variable (actual implementation might need a bit more work, but that is the principle) will stop GTM effectively from interacting with the page in any meaningful manner.
Related
I have server-side tracking implemented using Google tag manager.
I noticed duplicate events coming in but not because my GTM web container sends duplicate events (verified in debugger).
The GA4 client in my GTM server container receives two identical event calls, for no obvious reason. The only difference is the param _s:
https://www.google-analytics.com/g/collect?[...]&_s=1
https://www.google-analytics.com/g/collect?[...]&_s=2
I've dealt with this by creating a query parameter variable:
And then excluding all calls where the _s param equals 2 from my GA4 event trigger:
This solves the issue but seems like a hacky solution.
I wonder why two identical server events get triggered in my GTM server container, for a single GTM web event, in the first place?
I had a similar problem, and I couldn't solve it by filtering the parameter because it happened later (I think the params of the two events were _s=6 and _s=7).
I started looking for blog posts until I've found this one: https://www.thyngster.com/google-analytics-4-events-demystified-ga4. The suggestion that helped me was this one:
You may see events being fired on the browser that you didn't define on Google Tag Manager or GTAG. This is normal, don't go crazy with it. If you see a duplicate event or a new event that you don't know where it's coming from take a look at the Data Stream Settings
And, in fact, inside Data Streams was the solution to my problem: under Events settings > Create Events, someone had created a custom event based on the same name as the one I was firing through code, in my case it was add_to_cart.
Disabling the custom event solved the issue.
EDIT
I forgot to mention that the first way of debugging this issue was to check the value of the dataLayer variable in the browser console. This variable keeps track of all the events, together with their send_to attribute. Before looking into the analytics dashboard you should check whether you are sending duplicate events from the code and whether you are firing other events with the same name but without the correct send_to attribute, which will result in two events with the same name firing to the stream you are tracking.
I have an id being pushed to my data layer via dataLayer.push() and there is no event key at the moment.
I know the best practice is to use an event key like 'event': 'idPush' and then in Google Tag Manager UI, have a trigger that activates when the custom event idPush occurs.
Is there is a way that I can still get the trigger to activate upon seeing a generic 'Message'?
I can't be 100% sure because I haven't read the GTM source code and I couldn't find any articles that talk about this, but I'm reasonably certain that this can't be done.
I tried:
creating a Custom Event trigger with a regex match of .* which would match anything, including nothing.
matching undefined, because according to the preview pane, the _event variable is set to undefined for Message events.
Unfortunately neither of these worked, and preview mode just says No tags were evaluated for the Message. This leads me to think that GTM only checks to see if any triggers should fire when an event is pushed into the dataLayer.
No. Until there was an event, GTM does not know about the content of the message - the message is just the debugger telling you that something has been added to the global dataLayer variable (which exists in the global namespace of the browser, not the confined namespace of GTM). The even is what updates GTM's internal state to make it aware of changes and additions to the dataLayer.
Depending on your use case you might be able to use a trigger type that creates it's own event - e.g. setting a visibility trigger to an element that you know will be at the viewport after your message, which will then take the new values of the dataLayer into account. Or create a custom HTML tag with a setInterval functions that periodically pushes an event to the dataLayer.
While these solutions may work, I do not think they are actually good. Finding a solution to change your page code will almost certainly be less headache in the long run than using a workaround.
in google documentation for dataLayer it says
If you put the Google Tag Manager container snippet above the
dataLayer array, Google Tag Manager may malfunction, and will not be
able to read the variables defined in the array.
my question is: is it possible to declare the variable(dataLayer) above the GTM container and then push events to it (dataLayer) below the GTM?
Yes. That's not only possible, that's what GTM itself does (if you have a dataLayer variable declared, GTM pushes its gtm.js, gtm.dom and gtm.load event to the existing dataLayer (if this is undefined it declares the variable itself).
One thing you need to remember is that you need to push a GTM event - literally, a key/value pair where the key is "event". The GTM code amends the native push-Method of the datalayer to scan for the "event" keyword, and if the keyword is found it updates its internal variables (i.e. you cannot access the new variables before a GTM event has been pushed).
E.g. if you wanted to have a dataLayer variable "foo" with the value of "bar" you'd need to do
dataLayer.push({
"foo":"bar",
"event":"myCustomEvent"
});
You can then access the foo variable and retrieve its value. You can also do a custom event type trigger, that fires as soon as the event "myCustomEvent" is pushed (you do not have to, though, the "bar" value will be retained until the page is unloaded, you push another value to the "foo" key or you reset the dataLayer).
Some triggers types like click, submit and visibility provide their own events.
The other thing to keep in mind is that you must not declare the dataLayer variable a second time after the GTM code has loaded, else you remove the changes GTM has made to the dataLayer and GTM breaks.
But in short, yes, that's totally who it is supposed to work, you can push values after the GTM code.
I have a Google Tag Manager tag configured to fire on all page views. However, on some pages, I may need to disable the tag based on internal data. To me, this sounds like a job for the dataLayer.
My initial thought was to create a dataLayer variable called "disableGTMTag" and give it a value to validate against. Then GTM could evaluate that value and take appropriate action.
So, in the dataLayer I created a disableGTMTag variable and hard-coded it to always have a value of "google" (for testing purposes). Running the page in GTM debug mode, I can confirm that the disableGTMTag variable is present in the dataLayer with the value "google".
To set up the tag, I updated the tag's trigger to fire only when disableGTMTag does not contain "google". But the tag still fired. I then tried setting the trigger to fire on All Pages but added an exception when disableGTMTag contains "google". The tag still fired.
My understanding is that a trigger exception must be the same type as the firing trigger. But I went ahead and created a secondary exception for a custom event that matches the regex ".*" that looked at the disableGTMTag value. Still, the tag fired when the page loaded.
This seems like a straightforward thing: always run this tag, unless this dataLayer variable tells you not to. But it's just not working for me.
Is there a different approach to restrict page view firing? How do I prevent page view-based tags from firing using a dataLayer variable?
I've found a solution. The recommended way to reference the dataLayer is as:
window.dataLayer = window.dataLayer || []
But I found that when I used this convention, my Page View event fired first and then all my data messages happened after making the dataLayer values unavailable. Changing it to:
window.dataLayer = []
forced the messages to happen before the page view event, making the dataLayer values available to be evaluated. I understand that this is going to re-declare the dataLayer, but this worked.
I'm using Google Tag Manager and implementing Enhanced Ecommerce tracking via dataLayer. Everything is working fine. However, I'm now adding a CTA (call to action) that I want to track impressions for (there's multiple versions). This CTA is rendered as a partial, so at the time dataLayer is being constructed, it doesn't exist yet and I have no idea what will end up being there.
With straight Google Analytics, it looks like you can manually track an impression via:
ga('ec:addImpression', {
// impression data
});
But, this doesn't work with GTM, as ga is not defined in that scenario. According to the GTM Enhanced Ecommerce documentation, the only other "option", is to manually track the impression through the GTM control panel based on page view. Again, that's not feasible as the impression data is not always the same.
After a little research, I found a third "option" in delaying pushing dataLayer. For example, instead of letting if fire on GTM load, you can tie it to a particular event and then send that event at a later point. I suppose that would let me, then, alter the dataLayer in this partial, as long as I made sure that the event was not sent until well after it's been rendered. However, that not only seems clunky and prone to error, but it would also require me to substantially alter the rest of my Enhanced Ecommerce tracking code.
Is there no way to just send the impression as you can with straight GA, with GTM?
I am not quite sure that I understand the problem (but I have a go anyway). The way to do this is to push new data to the datalayer and have a custom event, i.e. the keyword "event" within the datalayer with a custom value; you then can use a "custom event" type trigger with the value you have pushed:
dataLayer.push({
"event":"mycustomevent",
"impressionData": myData
})
Specifications for EEC dataLayer are here. You then send a GA event that has EEC enabled and reads EEC data from the impressionData variable in the example.
You seem to have figured that out in principle, but seem to think this is somehow bad. No, it isn't, it is the recommended way by Google.
The dataLayer is an array of objects, and you can add new data to it by using the push method. This is not the native push method, but a custom implementation by Google. It scans the added data on every push, and if it finds the "event" key in the added object it adds the data from the on-page dataLayer variable to GTMs internal data model, where you then can use it in your tags.
Your problem might be, if I understand correctly, that you seem to think you have to construct all of the datalayer in a single go. But it is perfectly fine to split it up into multiple pieces and add new data via dataLayer.push as you need it.