customTask - The Guide
Last updated 4 September 2018
If you have been reading my blog articles over the past year, you might have noticed a disturbing trend. I’ve published 9 articles on customTask
since the API was released. It might not sound like much, but I can’t think of a single feature in Google Analytics or Google Tag Manager that has so completely convinced me of its usefulness in such a short time.
The customTask
API is a feature of the Universal Analytics library (used by Google Tag Manager’s tags, too). It lets you get
and set
values from and to the (Measurement Protocol) hit as it’s being generated. This is really useful for a couple of reasons, which I’ve covered in the previous articles, but I’ll go over them briefly in the beginning of this guide, too.
Suffice to say that especially for Google Tag Manager, customTask
adds a lot of value. With GTM, it’s always been quite difficult to access the hit-building process when using tag templates. Luckily, customTask
offers a solution to this problem, and at least for this particular developer it’s opened a whole new world of Google Analytics customization.
However, in spite of writing all those articles on customTask
, I recently realized that I never actually took the time to explain more thoroughly how it works. Also, I haven’t yet shared solutions for combining multiple customTask
tricks in a single tag. This guide seeks to address these points.
Be sure to check out my customTask Builder tool as well - it will help you compile the necessary JavaScript for
customTask
to run in your setup without conflicts!
Table of Contents
The Simmer Newsletter
Subscribe to the Simmer newsletter to get the latest news and content from Simo Ahava into your email inbox!
How Tasks work
When you run the ga('send', 'pageview')
command either directly in your site JavaScript or indirectly via Google Tag Manager’s Google Analytics tags, you actually request that the Universal Analytics JavaScript library (analytics.js) compile an HTTP request to the Google Analytics servers.
The endpoint to which the hits are sent is typically /collect
on the Google Analytics collector domain. The process of building and sending hits to the GA servers is also known as Measurement Protocol (MP). In fact, MP is the underlying process used by all GA tracking mechanisms, be they the ga('send'...)
JavaScript SDK, Google Tag Manager’s GA tags, native SDKs for Android and iOS, and custom-built HTTP requests from point-of-sales systems, for example.
When you use the JavaScript SDK, either via ga('send', 'pageview')
or the Google Analytics tags in GTM, you are thus initiating a sequence of processes, where the final product is the actual MP request to Google Analytics. This sequence comprises a number of tasks, of which customTask
is the first one that is executed.
Here’s a quick recap of what each task does, listed in the order they are applied to the hit.
Task | Description |
---|---|
customTask | No functionality of its own, but can be used to manipulate the model object before it is processed by the other tasks. |
previewTask | If the request is generated from the pageview of a “Top Sites” thumbnail in Safari, abort the hit. |
checkProtocolTask | Aborts the request if the page protocol is not valid (http or https). |
validationTask | Checks if the fields in the request have valid and expected values. Aborts the request if this is not the case (e.g. trying to send a string as the Event Value). |
historyImportTask | If there is still legacy tracking running on the site, this task imports information from the old GA library cookies into Universal Analytics. Very useful if the site is migrating to Universal Analytics. |
samplerTask | If you’ve decided to manually sample the users to stay within Google Analytics’ processing limits, this task aborts the request if the user is sampled out of data collection. |
buildHitTask | Generates the hitPayload string, which is essentially the list of query parameters and their values passed to the Measurement Protocol request. |
sendHitTask | Sends the hitPayload in a Measurement Protocol request to the GA servers. |
timingTask | If you are automatically sampling pages for page speed measurements, this task sends the timing hit to Google Analytics. |
displayFeaturesTask | If you have enabled display features in GA settings, this task compiles the request to the DoubleClick servers. |
Each tasks receives the model
object as a parameter. The model
object contains all the fields that have been set in the tracker, as well as any enhancements applied in the tasks themselves.
The beauty of customTask
is that because it runs before any of the other tasks, you can use it to overwrite behavior of these other tasks. For example, if you want to run Google Analytics locally or in a Chrome Extension, you’ll need to make sure checkProtocolTask
is never run, because it aborts the hit builder if the page protocol is not http or https. The customTask
would look like this:
var customTask = function(model) {
// Prevent checkProtocolTask from running
model.set('checkProtocolTask', null);
};
As you can see, the task is actually a field in the model
object that you can manipulate just as you can manipulate any other field in the model
. For example, if you want to grab the tracking ID (UA-XXXXXX-Y) and send it in the Custom Dimension with index 15, you can use the following customTask
:
var customTask = function(model) {
// Get the tracking ID from the model object
var trackingId = model.get('trackingId');
// Set the tracking ID to Custom Dimension 15
model.set('dimension15', trackingId);
};
To see what fields are available in the model object, check this developer documentation. Note that it’s not complete, since it’s missing all the tasks.
By running these model
interactions with customTask
, you have a lot of control over how the task sequence is run. Especially with Google Tag Manager, it would be difficult to run any complicated logic for when and how to manipulate sendHitTask
, if you applied it directly to the tag as a field.
How to add customTask
to your hits
To add customTask
to your Google Tag Manager tags, you need to create a Custom JavaScript variable which returns the customTask
method in the variable body. Practically all my customTask
articles show examples of what this Custom JavaScript variable looks like.
When you are ready to add the variable to your tags, you can do it either via a Google Analytics Settings variable (recommended), or by overriding the tag settings directly.
You need to scroll down to Fields to set, and add a new field which looks like this:
If using the on-page Universal Analytics (analytics.js) snippet, you add the customTask
like this, for example:
var _customTask = function() {
// Set Client ID to Custom Dimension 199
return function(customTaskModel) {
customTaskModel.set('dimension199', customTaskModel.get('clientId'));
};
};
ga('create', 'UA-12345-1');
ga('set', 'customTask', _customTask());
ga('send', 'pageview');
Do note that you can only set one customTask
per tracker / hit / tag. If you want to add more than one “trick” to the customTask
function, you need to write the JavaScript that combines all the different solutions into one coherent whole.
Or, you can use my customTask Builder tool, which does the dirty work for you.
Things you can do with customTask
As written above, customTask
is special for two reasons.
-
It has no special functionality of its own. A task queue can and will run perfectly without
customTask
defined. -
It runs before any other task, meaning you have full control over how the queue is processed.
With these two things in mind, here’s the list of all the customTask
tricks I’ve written about, with a description of what makes them special.
1. Set Client ID as a Custom Dimension
Link to article: #GTMTips: Use customTask To Access Tracker Values In Google Tag Manager.
This is one of the simpler tricks. It doesn’t manipulate the task queue itself at all, it simply gets the Client ID from the model object, and then sets it as the value of the specified Custom Dimension.
It’s an elegant solution to a difficult problem. Without customTask
, getting and setting the Client ID in a Google Analytics tag was difficult. If the tag is run for a first-time visitor who hasn’t received a Client ID yet, the actual clientId
field is not available when the regular tag fields are resolved. A typical hack for this solution was to fetch the Client ID by creating a dummy tracker or by sending the Client ID with an Event tag that fired after the Pageview.
But with customTask
, there’s no need for such unorthodox methods.
2. Duplicate Google Analytics tags to more than one property
Link to article: #GTMTips: Send Google Analytics Tag To Multiple Properties.
This is customTask
at its purest. The customTask
function first stores a reference to sendHitTask
in a global variable, after which it overwrites sendHitTask
in the current model object with the duplicator code.
The duplicator first lets the original hit fire to GA, after which it replaces the Tracking ID in the hitPayload
with the Tracking ID of the second property. Then, the global sendHitTask
is invoked again, and the hit is sent to the second property with an identical payload.
Note! The reason the reference to sendHitTask
is stored in a global variable is to avoid issues with field multiplication. Let’s say you always use this to get the original sendHitTask
reference:
var originalSendTask = model.get('sendHitTask');
Each time this customTask
code is run, it will get a reference to what is stored in the model object’s sendHitTask
. Unfortunately, when building standard Ecommerce hits, or when automatically sampling timing hits, the tag is automatically sent more than once. Thus the reference to the original sendHitTask
is recursively augmented with each iteration of model.set('sendHitTask');
, resulting in code being executed erratically.
By having a global variable store the reference to the original sendHitTask
, this recursive problem is avoided.
3. Track offline users in Google Analytics
Link to article: Track Users Who Are Offline In Google Analytics.
This is all David Vallejo. His solution tackles the problem of lost internet connectivity and hits that are aborted because of this. It uses customTask
to check if the user is offline, and if they are, the hits are stored in a batch queue. Once connectivity is restored, the queue is processed, and the hits are finally sent to GA.
4. Remove PII from GA payloads
Link to article: #GTMTips: Remove PII From Google Analytics Hits.
With GDPR coming soon, covering all your bases with regard to private data is a good idea. Fixing potential PII leaks before they hit Google Analytics servers is a good method as any to make sure you’re complying with Google Analytics’ Terms of Service as well as the increasingly stricter regulations for sending and collecting personal data.
Here, customTask
takes the hit payload before it is sent to GA, and purges it of all matches against any given regular expressions. These regular expressions can be built to match things like email addresses and social security numbers.
5. Fix site speed sampling messing with your Custom Metrics
Link to article: Prevent Site Speed Sampling Rate From Skewing Custom Dimensions And Custom Metrics.
This is a fairly simple trick, but it fixes a potential issue with Custom Metric data being skewed by the automatically collected page timing hits. The issue is that the timing hit copies all parameters from the Page View tag that is being sampled, and thus any Custom Dimensions and Custom Metrics are sent more than once, too.
Here, customTask
is attached to the Page View tag, where it checks if the hit type is timing
(due to the automatically generated timing hit), and if it is, it removes all references to Custom Dimensions and Metrics from the request.
6. Respect opt-out
Link to article: #GTMTips: Respect Opt-Out From Advertising And Analytics.
A simple trick, again. This time customTask
checks if the user has specific opt-out settings in the browser, and if they do, it aborts the requests to Google Analytics and DoubleClick. You’ll need to manually create the setting itself, be it a pop-up that stores the opt-out in a browser cookie or something, but once you’ve done it, this solution makes it easy to enact the opt-out programmatically.
7. Send details about Optimize experiments to Google Analytics
Link to article: Send Event And Custom Dimension If Google Optimize Experiment Is Running.
This trick tackles an issue with how Google Optimize data is being reported in Google Analytics. Basically, the Experiment Name and Experiment ID dimensions are scoped to the user for the duration of the experiment. Thus it’s not possible to get a segment of the actual sessions when the user was actively participating in an experiment page.
The customTask
checks for certain features of the Page View tag it is attached to, and if these features are found, it updates a Custom Dimension in the hit payload with details about the experiment. You can then segment your GA data with these Custom Dimensions to see sessions where the user was actually active on an experiment page.
8. Auto-link domains with regular expressions
Link to article: #GTMTips: Auto Link Domains With Regex.
With this trick, customTask
brings Google Tag Manager to feature parity with analytics.js. Regular, on-page Google Analytics tracking lets you use regular expressions with the Auto-Link Domains plugin. Google Tag Manager only accepts string values.
Here, customTask
actually applies the Auto-Link plugin to the tracker object itself, passing the array of regular expressions to the plugin. This way, domains can be automatically linked with cross-domain parameters based on a regular expression match, rather than an exhaustive list of strings.
9. Send Google Analytics payloads to Snowplow
Link to article: #GTMTips: Automatically Duplicate Google Analytics Hits To Snowplow.
I’m a huge fan of Snowplow, mainly because it’s open-source and tackles many difficult issues having to do with sessionization and tracking schemas. This trick uses customTask
to replicate what the “official” Snowplow Google Analytics plugin does.
Google Tag Manager doesn’t support adding plugins to tags, so using customTask
to replicate plugin features is as good a solution as any.
10. Send Google Analytics payload length as a Custom Dimension
Link to article: Send Google Analytics Payload Length As Custom Dimension.
This tip lets you collect the payload length of each Google Analytics request as a Custom Dimension in Google Analytics.
The maximum length of a Google Analytics payload is 8192 bytes. It’s useful to check if you’re approaching this value with some of your hits, because if the payload length exceeds this, the hit is never sent to Google Analytics.
Be sure to check my tip below on how to automatically reduce the payload length.
11. Send Hit Type as a Custom Dimension
Link to article: #GTMTips: Add Hit Type As A Custom Dimension.
With this trick, you can send the hit type (e.g. pageview
, event
, timing
) as a Custom Dimension with every hit to which this customTask
is attached.
Very useful for debugging, since you can now build segments where you directly refer to the hit type, which is not available (surprisingly) as a default dimension in Google Analytics.
12. Automatically reduce payload length
Link to article: Automatically Reduce Google Analytics Payload Length.
With this customTask
, the payload sent to Google Analytics is automatically parsed and, if necessary, reduced to go under the maximum payload length of 8192 bytes.
It’s very typical especially with Enhanced Ecommerce to send very long payloads to Google Analytics. Unfortunately, if these payloads exceed the maximum length, the hits are never sent and key data will thus be missing from your data set.
You can use this trick to recursively parse the payload and drop unnecessary parameters from it, which only serve to waste valuable space under the length cap.
13. Create and update a session cookie
Link to article: Create And Update Google Analytics Session Timeout Cookie.
This trick creates (or updates) a browser cookie which expires after a timeout you have configured (30 minutes by default).
Each hit that uses this customTask
will refresh the cookie very time the hit is fired.
Thus, if this cookie exists in the browser, it’s an indication that there might well be a Google Analytics session active for the current user.
You can use the cookie to block event hits from being dispatched to Google Analytics if there is no active session, for example.
14. Tracking cross-domain iframes
Link to article: Tracking Cross-Domain Iframes - Upgraded Solution.
Here we’ll update an older solution of mine by using customTask
and a window.setInterval()
polling script together to great effect.
The idea is that when the hit is built, the customTask
looks for the given iframe on the page, and if it’s found within a configured timeout, the iframe is reloaded with cross-domain tracking parameters.
This is a more elegant way to approach the problem of cross-domain iframes, because it skips past the race condition of running the script before the iframe has been loaded on the page, and it also uses the correct tracker object instead of just the first tracker on the page.
15. Prevent duplicate transactions from being sent
Link to article: Prevent Duplicate Transactions In Google Analytics With customTask.
Again an update to an old trick.
In this solution, customTask
stores all sent TransactionIDs in the browser. Once a transaction hit is queued for dispatching to GA, the customTask
checks if the hit’s Transaction ID is found in this list of IDs that have already been sent. If a match is made, the hit is blocked, thus preventing duplicated data from being sent to GA.
If no match is made, the hit is sent normally, and the Transaction ID is written into the list of sent IDs, so that any future attempt to send a transaction with this ID will be blocked.
Contrary to the older solution, this upgraded method will block Enhanced Ecommerce as well. For Standard Ecommerce, you can (and should) still use the customTask
, but you’ll still need to use triggers and exceptions. This is all detailed behind the link above.
16. Obfuscate and duplicate Google Analytics data
Link to article: Obfuscate And Duplicate Google Analytics Data.
This is a rather complex little script which duplicates all the Google Analytics data to which the customTask
is added to, and dispatches it to the Tracking ID you provide in the configuration.
The catch is that in addition to duplicating it, the data is also obfuscated. All the strings are converted to words in a finite set, and this is done predictably (so any given string is always converted to the same word). All prices are also modified by a randomized percent value.
The point is that you can use this to create a demo or training GA data set out of any actual and real data set without revealing where the data comes from.
17. Use localStorage for Client ID persistence in Google Analytics
Link to article: #GTMTips: Use localStorage For Client ID Persistence In Google Analytics.
Here, I tackle the latest attack on cookie storage by Apple: Intelligent Tracking Prevention 2.1.
By using localStorage
to save the Client ID, you can circumvent the policy of limiting cookies set with document.cookie
to a maximum expiration of 7 days.
It’s not perfect, and it’s definitely more a tech demo rather than a fully functional solution to solve your enterprise web analytics woes, but the functionality should be sound. There are some hiccups with regard to cross-domain tracking, so remember to revisit the article if you find that something is broken - I’m going to try to keep it up-to-date if Google decides to update the cross-domain linker parameter format, for example.
Putting it all together (literally)
NOTE! I’ve built a tool which you can use to compile the necessary JavaScript automatically. You’ll still want to read through this chapter, though, as it explains why building the script can be a chore.
If you like customTask
as much as I do, chances are you’ll want to use more than one trick listed above (and elsewhere) in your tags. There’s a catch though. You need to respect the basic features of JavaScript, mainly:
-
You can only
set
a single field once per tag, so you can only set onecustomTask
field per tag. -
You can only
set
a single model parameter once per tag, so you can only set onesendHitTask
attribute per tag, for example.
So, let’s say you want to do both tricks (2) (Send GA hit to more than one property) and (4) (Remove PII from GA hits). You might be tempted to try this:
function() {
return function(model) {
// Specify the PII regular expressions
var piiRegEx = [{
name: 'EMAIL',
regex: /.{4}@.{4}/g
}];
var globalSendTaskName = '_' + model.get('trackingId') + '_originalSendTask';
var originalSendTask = window[globalSendTaskName] = window[globalSendTaskName] || model.get('sendHitTask');
// Clear the payload from PII:
model.set('sendHitTask', function(sendModel) {
...
});
// Duplicate the hit to another tracking ID:
model.set('sendHitTask', function(sendModel) {
...
});
};
}
Unfortunately, this would not work. You are setting the sendHitTask
field twice, meaning the second one is the only one that counts (since it overwrites the first set
).
Instead, you need to apply some JavaScript chops and combine both of these solutions in the same sendHitTask
. It’s not exactly trivial, and there’s no textbook method for doing it. You’ll need to figure out the order in which the code should be processed.
In this example, we want the PII purge to happen before any hits are sent or duplicated. So the final code would look something like this:
function() {
return function(model) {
// Specify the PII regular expressions
var piiRegEx = [{
name: 'EMAIL',
regex: /.{4}@.{4}/g
}];
// Specify the GA tracking ID of the property to which you want to duplicate the hits
var newTrackingId = 'UA-12345-2';
var globalSendTaskName = '_' + model.get('trackingId') + '_originalSendTask';
var originalSendTask = window[globalSendTaskName] = window[globalSendTaskName] || model.get('sendHitTask');
var i, hitPayload, parts, val, oldTrackingId;
model.set('sendHitTask', function(sendModel) {
// Clear the payload of PII:
hitPayload = sendModel.get('hitPayload').split('&');
for (i = 0; i < hitPayload.length; i++) {
parts = hitPayload[i].split('=');
// Double-decode, to account for web server encode + analytics.js encode
val = decodeURIComponent(decodeURIComponent(parts[1]));
piiRegEx.forEach(function(pii) {
val = val.replace(pii.regex, '[REDACTED ' + pii.name + ']');
});
parts[1] = encodeURIComponent(val);
hitPayload[i] = parts.join('=');
}
sendModel.set('hitPayload', hitPayload.join('&'), true);
originalSendTask(sendModel);
// Rewrite the tracking ID
hitPayload = sendModel.get('hitPayload');
oldTrackingId = new RegExp(sendModel.get('trackingId'), 'gi');
sendModel.set('hitPayload', hitPayload.replace(oldTrackingId, newTrackingId), true);
originalSendTask(sendModel);
});
};
}
The code is fairly complex, and complexity increases with each distinct trick you want to run. This is an unfortunate consequence of the limitations of JavaScript and the fact that there is only one customTask
to manipulate.
In the end, it’s really up to your JavaScript skills. You’ll need to be aware of how the browser runs the code line-by-line, and thus you’ll need to make sure that whatever you want to run first is also executed first by the browser. That’s why in the example above I have the PII purge running before the hit duplication. If the PII purge happened AFTER the hit is duplicated, it would be redundant, since it would still allow PII to potentially flow to Google Analytics.
Summary
As I wrote in the beginning, customTask
is one of the nicest features to emerge in Google Analytics in a long time. With Google Tag Manager, it’s a real powerhouse of customization.
It’s a good idea to read about the Task queue in general. Understanding how tasks work will give you great insight into how analytics.js compiles and dispatches hits to Google Analytics. Once you have a good grasp on all the different moving parts of the Tasks queue, you should be able to come up with cool customTask
solutions of your own, which you can then share in the comments of this article, for example!