Is it possible to make GTM to tag some elements that are dynamically created - reactjs

I'm a React developer and I barely knows how GTM works as it's not my field.
What I understand is
There are triggers on google tag manager
GTM script will find HTML elements of the triggers by defined css selectors(in my case) and tag them(put GTM attributes) when it's loaded in the page
When an event meeting the condition of a trigger occurs, the trigger will execute defined javascript(in my case)
The problem is that HTML elements possibly don't exist when GTM script is tagging because they can be created by a user interaction. And I want to tag such elements by using GTM's lifecycle method(if exists). Is there any way to do this or at least a workaround?

The best practice I can come up with is something like :
When you render the element you want to track in the React.
Let React push the datalayer about the information of the element like
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "element_render",
element_id: "#id",
element_type: "type",
any_paramter_you_need: "any_value_you_need",
})
So you can set up the Trigger in you Google Tag Manager and the type is Custom Event

Usually that should work out of the box. GTM does not tag elements directly. Instead, GTM is attached to the document root. If an element is clicked, the event bubbles up to the document root, and there GTM checks if the properties of the event target (the actually element interacted with) meet the conditions defined in the trigger.
So unless React is doing something super crazy with the document, you should be safe. Allowing to track dynamically added elements is pretty much the point of this design.
For visibility triggers, you specifically need to enable this behavior by clicking the checkbox on "observe DOM changes". There is a warning that this might impact page speed.

Related

Display [object HTMLDivElement] of google tag manager

I'm trying to setup event tracking of my website using GTM.
However, when trying to debug a tag which fires on a CSS selector, I cannot properly determine which value my clicks are tacking since I can only see:
[object HTMLDivElement]
in the preview mode, like this:
So clearly, the second condition is not met, but I'm not sure why since I can only see the name of the object.
Is there a way to display this? perhaps using another custom tag, or sending the value to the data layer?
Supposedly the element that is target of the click event do is not the one with id #navbar-brand. It seems to be a div inside your #navbar-brand element. If it's the case I'd suggest you to extend your firing condition to include all descendants of a #navbar-brand with selector #navbar-brand *

Angularitics (GA) add fixed value to all tracked events

I am using Angularitics (GA analytics) in my app.
Here's what I doing in my jade file.
a.btn(href="www.some.com" analytics-on="click" analytics-label={{UserID}} analytics-category="Some Category" analytics-event="Some Event")
Now I have a ton of these and the label is always UserId so i can track events by user.
Is there a simpler way to add a constant across the board value to all events. I have an angular app and want to add the userID for the logged in user to all events i track. Looking for a way to add that info without having to add it to each element i track in the html.
I would just recommend you using GTM instead.
With Angulartics and GTM, you can access the dataLayer directly with
window.dataLayer
So you can do something like this at the start of you controller or main app.
window.dataLayer.push('userId','example123');
Then in GTM just read that into a variable and push into GA with the userId as label for the event.

Google Tag Manager with angular js links

I some links in my application which I want to track the click on those links with the help of GTM. Imagine I have a link to download page like this
<a ui-sref="main.download">Download</a>
I create a tag of type 'Universial Google Analytics' for this click named MainDownloadLink.
How should I define a trigger to fire this tag when that link is clicked? Also note that I don't want to use angularitics library. Imagine that I have no control over the source code. just GTM panel.
I define a trigger of type Clicks-Just Link and I am confused for the condition when this event should be fired.
any help is welcomed.
You must make sure that "link validation" is disabled (since GTM does not consider links without href to be valid).
As long as your links are actually named "Download" it probably would be easiest to use the built-in "click text" variable and set a filter "if click text equals download" on your link trigger.
Else you might want to try to access the "main.download" attribute. The built-in click element variable returns the clicked DOM element, so you'd create a custom variable
function() {
return {{Click Element}}.getAttribute('ui.sref');
}
and then test in your trigger if "{{your custom js var}} equals main.download".
Untested, but basically this should work.

Trigger Google Analytics pageview for Angular App while using Google Tag Manager

I am building a SPA using Angular.js. We use Google Tag Manager to load in most of our analytics/marketing scripts, which includes Google Analytics. I am also using ui-router to manage states/views.
I would like to send pageview events off to Google Analytics whenever a user browses to a different state in my app. Part of the complexity in doing this with GTM is that GTM creates a named tracker. That means that all GA events need be prepended with the tracker name. That would usually look like this:
ga('trackerName.send', 'pageview', {page: '/a/path/', title: 'A Title'});
GTM uses a randomly generated tracker name, so the tracker name needs to be grabbed at runtime. That can be done fairly simply with GA's getAll function. If you want to send the pageview event to all trackers, you would simply do:
var allTrackers = ga.getAll();
for(var i=0; i<allTrackers.length; i++) {
ga.send(allTrackers[i].getName()+".send", "pageview", {page: '/a/path', title: 'A Title'});
}
This works great for most of my pageview events. However, there is a race condition between when ui-router fires the initial view's $stateChangeSuccess (which is where I trigger the GA pageview), and when analytics.js is loaded.
Prior to analytics.js being loaded, Google Analytic's snippet creates a faux ga object, that you can send events to. This faux object does not have the rest of the ga functions on it, so you can not run getAll. Without the getAll function, I cannot get the tracker name and I cannot send pageview events.
As far as I can tell, Google Analytics does not provide any callbacks or events for when analytics.js is finished loading, so there is no way to tell when I will be able to start sending events. Right now I am using an $interval to check for the existence of ga.getAll, but that is not a very performant or ideal solution. This is what I've got:
gaCheckInterval = setInterval(function() {
if(typeof(ga) !== 'undefined' && typeof(ga.getAll) == 'function') {
clearInterval(gaCheckInterval);
sendBackloggedEvents();
}
}, 200);
Is there any other way to recognize when analytics.js has finished loading? Or any other way to send events to a named tracker, without having access to getAll?
Attempting to configure and trigger individual trackers circumvents the purpose of using a tag manager. Instead do:
dataLayer.push({event:'spa.pageView', page:..., title:...});
Where:
dataLayer is optionally renamed in the gtm snippet
spa is a handy abbreviation for your app/project/company/whatever in case you need to distinguish its actions later.
page and title can be whatever you like, you will reference them by adding dataLayer macros in your GTM container.
Then, in the tag manager you configure:
rule of {{event}} ends with pageView.
dataLayer macros for the page, title you are pushing into the dataLayer.
UA Tag (and later whatever else) to fire (1) and use the macros in (2) for the TAG parameters they override.
Repeat (3) as many times as you like for different UA properties with additional blocking rules, alternate macros or more granular firing rules as necessary.
Now you can configure the specifics and add other tag types that reuse the rules and macros without modifying the application for each change.

Can I place ui-view on the body tag?

I'm working on an app whose header's styling and UI options will change depending upon the state a user is currently in. For example, if a user clicks the Upload, Edit Profile, Create Playlist or Create Gallery buttons in the main menu, this will cause the following changes to the header:
the header's background to change color
the site logo will have CSS3 animation applied to it to make it slide into a new position
a specific message (depending on what state the user is in) in a word bubble will appear next to the logo
a Cancel button will manifest on the right edge of the header
This means there will be no static element on my site so logic tells me that I should place ui-view in my body tag thus making it look like this:
<body ng-app="app" ui-view>
I have never seen that used before anywhere so I've my doubts. Any ideas?
I'm not sure if this will or will not work technically, but I believe you should avoid it because:
It would require all your templates to include an outermost <body> tag which makes them less reusable
It's generally an unusual thing to do, and that comes with a cost, and I see no particular benefit to this, so IMHO the cost/benefit analysis says stick with what is conventional: use <div>s.
I suspect this may in fact work, but typically the tag with ng-app stays in place for the entire lifecycle of the app. There's a chance you may hit some weird errors if you swap out the tag containing ng-app. Thus many people put ng-app on the very first <html> tag and call it done.
But it's your app and the effort to try both approaches is very low, so just try them out and see (and let us know what you learn). I don't think you need to wait for stackoverflow answer from authority to test 2 slightly different HTML structures with your app.
No, please do not do that!
Having ui-view inside of the body tag may render many JS plugins/libraries unusable, especially in case if they dynamically add some HTML tags to document.body. In such cases, navigation to another view will reinitialize document.body and thus disregard previously added HTML tags.
E.g. this is the case with Firebase and Angular.js (AngularFire). I hope everybody who has come across the error
Uncaught NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
will get to see this post. Just make sure you haven't added ui-view attribute to your body tag.

Resources