My question is for someone with experience using Google Analytics Linker Plugin programmatically. However my example has a bit complicated setup.
I'm currently working on the website which is using Google Tag Manager for loading GA scripts. It loads several GA scripts on the same page for different purposes.
This website also has a custom dropdown with related domains and I have to use GA Linker Plugin in order to keep them connected. I have to do it manually through the code on every domain element click event. I used the setup suggested by Google Analytics docs:
// inside onclick handler
ga(function(tracker) {
var linkerParam = tracker.get('linkerParam');
// apply to url and navigate window.location.href = url etc.
});
Obviously this doesn't work in my case because of multiple trackers on the page:
// inside onclick handler
ga(function(tracker) {
// tracker is undefined :(
});
I managed to check how many trackers are available and requested linkerParam on each:
// inside onclick handler
ga(function () {
var trackers = ga.getAll();
trackers.forEach(function (tracker) {
console.log(tracker.get('name'), tracker.get('trackingId'), tracker.get('linkerParam'));
});
});
// outputs
// gtm1 UA-XXXYYY-1 _ga=2.234343242.904959305.3434234324-394093204.3094039402
// gtm2 UA-XXXYYY-2 _ga=2.234343242.904959305.3434234324-394093204.3094039402
// gtm3 UA-XXXYYY-3 _ga=2.234343242.904959305.3434234324-394093204.3094039402
As you can see all trackers have the same linker param value, but different names and tracking ids. My question are -
Is it safe to use just first tracker from the list as long as all values are the same (e.g. ga.getAll()[0].get('linkerParam'))?
Or will it be safer to create a specific name for one of the GA trackers in GTM and get it by name in code, e.g:
// inside onclick handler
ga(function () {
var tracker = ga.getByName('websiteTracker');
console.log(tracker.get('name'), tracker.get('trackingId'), tracker.get('linkerParam'));
});
// outputs
// gtm3 UA-XXXYYY-3 _ga=2.234343242.904959305.3434234324-394093204.3094039402
Thanks!
You might be overthinking the problem. Google Analytics through GTM has a simple, built-in way to implement cross-domain tracking. For each GA property that you are loading through GTM, simply set the domains you want to link in the "Cross-Domain Tracking" fields of the Analytics Setting variable or in the over-riding settings in the GA tag.
Bounteous has a very detailed article on how to implement and debug this here.
This has worked in almost all cases in which I want to implement cross-domain tracking through GTM - even if it is for numerous domains.
In the case that you actually need to do this programmatically, I'm pretty sure you can use the same linker param for all the GA properties. You can verify and debug your implementation by doing something like:
Open up the real-time report in the GA property you want to test cross-domain tracking
Visit domain1.com with these UTM values appended: domain1.com?utm_source=test&utm_medium=test
You should be able to filter the real-time traffic by source / medium by clicking on "test" as source or medium under the traffic sources tab.
Navigate to the content tab of the real-time report, you should see the page path and page title for domain1.com
For each domain you want to test that cross-domain tracking works, click the link in your navigation
If everything works, your filtered real-time view should update to the page path and title of domain2.com
If cross-domain linking isn't working, the filtered real-time report will not update. Removing the filter, you should see "domain1.com / referral" or "(direct) / (none)" as the source / medium depending on your referral exclusions.
Hopefully this will help you configure cross-domain tracking or debug efficiently.
Related
I have a simple html page in order to test locally the Adobe Analytics.
I try to implement analytics for url.
I have a simple url with onClick event like this:
Youtube
Using the official documentation at page 223 I found the following variables:
s.referrer="https://www.youtube.com/"
s.pageURL="https://www.youtube.com/"
I add them to my code but the problem persists again. What can I do in order to fix the server call problem?
Solved using this:
Youtube
If you set your s.linkInternalFilters correctly you shouldn't need to hard code an exit link for www.youtube.com.
The purpose of this configuration variable is to tell Adobe Analytics which link clicks will be considered internal to your site vs. external link clicks (exits) which take you away from your site (IE www.youtube.com).
If you're looking to count any click on a YT link as an exit you can set your s.linkInternalFilters like this:
// s_code or DTM JS config
s.linkInternalFilters ="my-local-URL,javascript:,mailto:,tel:"
YT link clicks (exits) will now be tracked automatically.
Content Script can be injected programatically or permanently by declaring in Extension manifest file. Programatic injection require host permission, which is generally grant by browser or page action.
In my use case, I want to inject gmail, outlook.com and yahoo mail web site without user action. I can do by declaring all of them manifest, but by doing so require all data access to those account. Some use may want to grant only outlook.com, but not gmail. Programatic injection does not work because I need to know when to inject. Using tabs permission is also require another permission.
Is there any good way to optionally inject web site?
You cannot run code on a site without the appropriate permissions. Fortunately, you can add the host permissions to optional_permissions in the manifest file to declare them optional and still allow the extension to use them.
In response to a user gesture, you can use chrome.permission.request to request additional permissions. This API can only be used in extension pages (background page, popup page, options page, ...). As of Chrome 36.0.1957.0, the required user gesture also carries over from content scripts, so if you want to, you could add a click event listener from a content script and use chrome.runtime.sendMessage to send the request to the background page, which in turn calls chrome.permissions.request.
Optional code execution in tabs
After obtaining the host permissions (optional or mandatory), you have to somehow inject the content script (or CSS style) in the matching pages. There are a few options, in order of my preference:
Use the chrome.declarativeContent.RequestContentScript action to insert a content script in the page. Read the documentation if you want to learn how to use this API.
Use the webNavigation API (e.g. chrome.webNavigation.onCommitted) to detect when the user has navigated to the page, then use chrome.tabs.executeScript to insert the content script in the tab (or chrome.tabs.insertCSS to insert styles).
Use the tabs API (chrome.tabs.onUpdated) to detect that a page might have changed, and insert a content script in the page using chrome.tabs.executeScript.
I strongly recommend option 1, because it was specifically designed for this use case. Note: This API was added in Chrome 38, but only worked with optional permissions since Chrome 39. Despite the "WARNING: This action is still experimental and is not supported on stable builds of Chrome." in the documentation, the API is actually supported on stable. Initially the idea was to wait for a review before publishing the API on stable, but that review never came and so now this API has been working fine for almost two years.
The second and third options are similar. The difference between the two is that using the webNavigation API adds an additional permission warning ("Read your browsing history"). For this warning, you get an API that can efficiently filter the navigations, so the number of chrome.tabs.executeScript calls can be minimized.
If you don't want to put this extra permission warning in your permission dialog, then you could blindly try to inject on every tab. If your extension has the permission, then the injection will succeed. Otherwise, it fails. This doesn't sound very efficient, and it is not... ...on the bright side, this method does not require any additional permissions.
By using either of the latter two methods, your content script must be designed in such a way that it can handle multiple insertions (e.g. with a guard). Inserting in frames is also supported (allFrames:true), but only if your extension is allowed to access the tab's URL (or the frame's URL if frameId is set).
I advise against using declarativeContent APIs because they're deprecated and buggy with CSS, as described by the last comment on https://bugs.chromium.org/p/chromium/issues/detail?id=708115.
Use the new content script registration APIs instead. Here's what you need, in two parts:
Programmatic script injection
There's a new contentScripts.register() API which can programmatically register content scripts and they'll be loaded exactly like content_scripts defined in the manifest:
browser.contentScripts.register({
matches: ['https://your-dynamic-domain.example.com/*'],
js: [{file: 'content.js'}]
});
This API is only available in Firefox but there's a Chrome polyfill you can use. If you're using Manifest v3, there's the native chrome.scripting.registerContentScript which does the same thing but slightly differently.
Acquiring new permissions
By using chrome.permissions.request you can add new domains on which you can inject content scripts. An example would be:
// In a content script or options page
document.querySelector('button').addEventListener('click', () => {
chrome.permissions.request({
origins: ['https://your-dynamic-domain.example.com/*']
}, granted => {
if (granted) {
/* Use contentScripts.register */
}
});
});
And you'll have to add optional_permissions in your manifest.json to allow new origins to be requested:
{
"optional_permissions": [
"*://*/*"
]
}
In Manifest v3 this property was renamed to optional_host_permissions.
I also wrote some tools to further simplify this for you and for the end user, such as
webext-domain-permission-toggle and webext-dynamic-content-scripts. They will automatically register your scripts in the next browser launches and allow the user the remove the new permissions and scripts.
Since the existing answer is now a few years old, optional injection is now much easier and is described here. It says that to inject a new file conditionally, you can use the following code:
// The lines I have commented are in the documentation, but the uncommented
// lines are the important part
//chrome.runtime.onMessage.addListener((message, callback) => {
// if (message == “runContentScript”){
chrome.tabs.executeScript({
file: 'contentScript.js'
});
// }
//});
You will need the Active Tab Permission to do this.
How do I use GTM with Angular?
I'm trying to fire a (virtual) pageview event when I load a new partial using this code:
dataLayer.push({
'event' : 'pageview',
'pageview' : $location.path(),
'virtualUrl' : $location.path()
});
But I don't see the event firing (I'm using the Google Analytics Chrome debug extension to view fired events).
I find the Chrome extension unreliable.
Simply run the global variable dataLayer in the console to print the array of events. One of the objects should be your pageview event.
Here is an example of how we are using it:
Note: we're not simply using $location.path(), instead everything in the url after the domain. Which includes the .search() & .hash().
$location in the Angular docs
modules/analytic.js
(function(window, angular) {
'use strict';
angular.module('Analytic.module', ['Analytic.services']).
run(function($rootScope, $window, $location, GoogleTagManager) {
$rootScope.$on('$viewContentLoaded', function() {
var path= $location.path(),
absUrl = $location.absUrl(),
virtualUrl = absUrl.substring(absUrl.indexOf(path));
GoogleTagManager.push({ event: 'virtualPageView', virtualUrl: virtualUrl });
});
});
})(window, window.angular);
services/analytic.js
(function() {
angular.module('Analytic.services', []).
service('GoogleTagManager', function($window) {
this.push = function(data) {
try {
$window.dataLayer.push(data);
} catch (e) {}
};
});
})();
In GTM
You'll need {{virtualUrl}} and {{event}} Macros which listen for the dataLayer variables of the same name.
You'll need a Google Analytics Event Tracking Tag with a Firing Rule which triggers when {{event}} equals 'virtualPageView'. Make sure you remove the default 'All Pages' Rule which makes it run on every page load. Instead, you want it to run when you dataLayer.push() the event, which may happen multiple times per page refresh.
The Tag should be configured with:
Track Type == 'Page View'
More Settings > Basic Configuration > Virtual Page Path == '{{virtualUrl}}'
Similar to the accepted answer, we created a simpler, more explicit solution using a pagename variable in a Javascript in our controller for our single-page app,
// Note, this may not be how your app works, YMMV
var pagename = $location.path().substr(1,$location.path().length);
and push them to the dataLayer like this:
window.dataLayer.push({'event':pagename+'-page'})
Then in GTM we added triggers in GTM like so:
Trigger: Custom Event
Event Name: home-page
... about-page, faq-page, etc.
For more complex angular apps, there are some available extensions for using Google Analytics and Google Tag Manager with Angular.
See Angulartics (which also supports web analytics solutions other than Google Analytics via its plugin architecture) and the related NPM package for GTM.
I would highly recommend you to use the angulartics library. I have used it on multiple sites. It gets you running pretty quickly.
It includes support for Virtual Page Views and events out of the box. It does not support GA eCommerce but has support for extensibility.
Also - I have used with both GTM and Piwik.
No need to add code.
Configure a "history change" trigger, this is triggered by angular route changes, add it as a trigger to your "page views" tag.
The possible way to do this is using $window service.
Look at this answer to try, if it works: Tracking Google Analytics Page Views with Angular.js
Hope it works.
Currently in my website, I used HTML5's pushState() and popState in links to increase the speed. However, this doesn't really change the real URL and it looks like it will affect and mess up the Google Analytics's code. (doesn't show a url change) Is there a possible solution for this? Thanks,
If you are using the newer analytics.js API, Google's documentation requires the following code to trigger the event:
ga('send', 'pageview', '/some-page');
If you are using the older ga.js API, David Walsh suggests AJAX websites to use the _gaq.push method:
_gaq.push(['_trackPageview', '/some-page']);
I know it's old question but since this question is first result in Google about tracking pushState() in Google Analytics and all answers are wrong I decided to answer it.
In other answers they mentioned to use directly ga('send' ..... ) but this is wrong way to do it.
First you have to 'set' parameters and then use 'send' to track it.
If you want to update only url, use following code
// set new url
ga('set', 'page', '/new-page');
// send it for tracking
ga('send', 'pageview');
If you want to update url and title, add title parameter to it
// set new url and title
ga('set', {
page: '/new-page',
title: 'New Page'
});
// send it for tracking
ga('send', 'pageview');
Source Single Page Application Tracking - Web Tracking (analytics.js)
February 2018 Update - Global Site Tag (gtag.js)
Google Analytics has a new tracking code snippet, so the other answers might not work for gtag.
This is the default tracking code. It only runs once even though we try to run it each URL changes.
gtag('config', 'GA_TRACKING_ID');
But with a page_path parameter we can make GA run manually.
gtag('config', 'GA_TRACKING_ID', {'page_path': '/new-page.html'});
And we can make something like this.
var origin = window.location.protocol + '//' + window.location.host;
var pathname = window.location.href.substr(origin.length);
gtag('config', 'GA_TRACKING_ID', {'page_path': pathname});
Single page application tracking with gtag.js (Google documentation)
Recent answer (2017)
You can now use Google's autotrack.js, a script that enhances analytics.js.
It includes a plugin that automatically tracks URL changes for single page applications.
You just need to include the script and the following line in your html:
ga('require', 'urlChangeTracker');
2020 Update
If you are using Google Analytics 4 you don't need to push the event anymore IF you enabled the Page views option in the Enhanced measurement feature in Data Streams menu.
At the time of writing, here in September 2013,
Google Analytics has a new JavaScript API.
After you've included Google's new "analytics.js" asynchronous snippet, use the send pageview command to track pages:
ga('send','pageview');
After your pushState madness, use this send pageview command to track your asynchronous navigation. According to Google's Documentation on Page Tracking with Analytics.js, the send pageview command will magically read and track the new location given by pushState, as it will, in the moment the send pageview command is called, use the following values by default (though you can specify them):
var locationToTrack = window.location.protocol+'//'
+window.location.hostname
+window.location.pathname
+window.location.search;
var titleToTrack = document.title;
var pathToTrack = location.pathname+location.search;
Note, Google's standard analytics snippet includes an initial send pageview command.
Update:
I've implemented Google Analytics tracking on my website in the way above that I described -- however, it does not seem to be successfully tracking any of the pushState page views.
I'm going to try specifying the location, title, and page name explicitly on the send pageview command, and see if GA tracks properly.
I'll post back with the results, unless I forget.
Using ga('send', 'pageview') was not registering a pageview on GA.
The way that worked for me is:
window.ga.getAll()[0].set('page', location);
window.ga.getAll()[0].send('pageview');
I can use it after changing the url with history.pushState.
I also had problems with ga('send','pageview');, after using history.pushState.
The workaround was simply make the URL explicit.
ga('send','pageview','/my-url')
Has anyone else had any problems using google's Domain Tracking API, I am specifically talking about the _link() method.
The documentation is here
The example provided shows that the _link() method should be used in the onclick event like this:
Go to our sister site
However, this essentially just makes the link...do nothing (most probably because of the 'return false').
My understanding is that the pageTracker._link() method is 'supposed' to add additional parameters to the url and do it's own document.location style redirect.
Any ideas / catches / previous posts??
Sorry for the obvious question, but did you enable linking on the target page:
You must also enable linking on the target site (pageTracker._setAllowLinker(true);) in order for link to work properly.
Apparently a miss-interpretation of the documentation:
You must also enable linking on the target site
So lets clarify also
pageTracker._setAllowLinker(true); is set on the ORIGINATING page
pageTracker._setAllowLinker(true); is set on the TARGET page
I only had it enabled on the target page, as the docs indicate.