by Zdravko Verguilov, ServiceNow Platform Developer, Do IT Wise
Google Analytics is a powerful set of tools that will give you a pretty accurate picture of the ways your website needs to improve in order to be, or remain, successful and convenient to its viewers.
Implementing Google Analytics or simply GA on a portal page is essential for a couple of reasons:
1. To find out how many people try to load the page on a mobile device, thus helping them decide if they need a responsive mobile layout.
2. To get a better idea of the average customer behavior on the page – if they’re just passing by for a quick glance at the current status or tend to stay around for a detailed check of current and past conditions.
3. To measure page performance, as it has some complex logic involving multiple widgets, and sometimes goes a bit on the heavier side when more items were displayed.
First of all, you should create a GA account. Once everything there is set up, you get a piece or two of JavaScript code. And yes, that’s all it is, some JavaScript functions wrapped in a <script> tag. This tag needs to be in the <head> of the page when it loads to work correctly. Once loaded, the code gets executed and provides the necessary information to the respective Google account.
Bear in mind that you might need to implement a GDPR disclaimer for this. You can find a sample included in this article.
Google Analytics code snippets come in a few different variants, so if yours looks different – don’t worry, they all work in the same or very similar way. So, we won’t go into details about them now.
As already mentioned, we need to get the <script> containing the GA code into the <head> of the page. An otherwise simple task, but here we meet our first obstacle. How do we get it done when we have no direct access to the source HTML of the page, hence its <head>?
One possible way is by a simple DOM manipulation. You can use the Client Controller of a widget to inject the code anywhere you need on the page. Using the header widget is recommended, as it usually reloads less often than other ones on a page.
The code we get from Google usually looks like this:
<script>
function trackingLoad() {
/* GTM Code Snippet */
(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=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');
}
</script>
To get it working in this case, we need to do the following:
4. Remove the <script> tags.
5. Create a Client controller function, in which you will:
a. Create an empty <script> element;
b. Add the GA JavaScript code to it;
c. Append the element to the page <head>;
6. Handle the triggering of this function with a dialog or a modal, thus implementing a simple GDPR disclaimer;
Here’s how it goes:
function loadScript() {
var $script = document.createElement('script');
$script.text = "(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= 'https://www.googletagmanager.com/gtm.js?id='+i+dl; f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-XXXXXXX');";
document.head.appendChild($script);
}
First create the $script variable, which is essentially an empty <script> HTML element. Then add the Stringfield GA code to its ‘text’ property (it’s an object) and then append the <script> to the page’s <head>. This function goes in our widget’s Client Script.
If you don’t need a GDPR disclaimer (sites for Internal use only, etc.), at this point, you can just call the function with a simple loadScript() in our Client Script, and finish with it.
If you need a GDPR consent dialog, do the following:
1. Create a new widget. A simple two-button dialog HTML structure will do, like this one:
<div>
<h2>
How about some tracking?
</h2>
<div>
<button ng-click="c.track(1)">
Yep, track me
</button>
<button ng-click="c.track(0)">
Nope, please don't
</button>
</div>
</div>
2. In the Client Script of the new widget, add a simple function that adds a cookie containing the result of the dialog.
It’s the c.track() function you see in the ng-click property of the dialog buttons. The “$rootScope” object is a global scope object that all widgets on the page have access to. You’ll see why you need the “gdpr” Boolean property in a minute. The “$scope.$parent.$parent.$dismiss()” part closes the modal containing the new widget once the cookie has been added. It’s not really meant to be used this way, but it is a simple solution. The complication is not going away though, we’re just transferring it to the original widget. Here’s what remains in the dialog:
$rootScope.gdpr = false;
c.track = function(value) {
$cookies.put('_trackMe', value);
$rootScope.gdpr = true;
$scope.$parent.$parent.$dismiss();
};
In the end, you’ll have the following code:

3. Back in the original widget, you need to:
a. On load, check if the _trackMe cookie is present;
b. If it’s there, load, or not, the GA code, depending on the cookie value – 0 or 1;
c. If it’s missing, call the GDPR widget so the user can consent or refuse tracking;
Follow few simple steps to do it.
if(!$cookies.get('_trackMe')) {
spModal.open({
widget: 'exl_gdpr',
size: 'md',
buttons: []
})
} else {
if($cookies.get('_trackMe') == 1) {
loadScript();
}
}
$rootScope.$watch('gdpr', function() {
if($cookies.get('_trackMe') != 0) {
loadScript();
}
})
First, check if you have the cookie at all. If not, call a modal, with the “exl_gdpr” widget displayed in it – that’s the dialog widget you created. If you have it, act accordingly to its value – call the function which loads the GA code if you have consent.
The next part is where we handle the case in which we didn’t have consent or a refusal initially, but we fired up the GDPR dialog and got one of the two. It watches for changes of the ‘gdpr’ property of the $rootScope, which only happens when the user interacts with the dialog.
This is just one way to make the implementation. Another one makes use of JavaScript Includes, and we’ll review it in a different article.
Bear in mind that you’ll get two pieces of GA code a lot of times – one meant to go in a <script> tag, and the other for a <noscript> one. The second one you don’t really need. It’s there to provide at least some level of adequate tracking for cases of JavaScript completely turned off in the browser. Since an AngularJS page is not going anywhere with JavaScript off, that piece of code is worthless.
Now that you have successfully implemented Google Analytics on your ServiceNow Portal page and start collecting valuable data about your website, it is up to you to make the best of it and optimize it for a better user experience.
Do you find this article useful? If you enjoyed it, share it with your friends and colleagues!