Having been away from Google Tag Manager (GTM) for a bit of a spell, a recent client project gave me a much welcome opportunity to jump back in.
Enjoying that warm fuzzy feeling of the familiar as I re-oriented myself to the UI, I was abruptly pulled out of it when one of the use cases required the need for some cryptographic hashing of Personally Identifiable Information (PII) across a variety of interactions.
See I’d become rather spoiled, with such functionality readily available in Tealium iQ which made this sort of thing an absolute doozy.
At the point of resigning myself to the work at hand I spotted something new in the GTM UI, Templates. A new feature less than a year old that elicited the same jaw dropping reaction experienced by other GTM users.
A quick read of the google documentation and my day was made, they have an api providing access to the SHA-256 hashing algorithm.
I expected that someone had already written a perfectly suitable hashing template, so into the gallery i went only to find that the single hashing template available was a re-work of the google analytics tag with the ability to hash dimensions. A good effort but not quite what I was after as the data potentially would need to be passed to a variety of tag tech.
So, filing in the gap, I’ve prepared a cryptographic hashing template available for you to use in the google tag manager community gallery aptly called, ‘CryptoMe’.
Now I’m not going to go into the ins and outs of the GTM templates feature, this subject being more than adequately covered by GTM’s unofficial documentation writer and all-round legend Simo Ahava to whom I also owe a nod of gratitude in edging me to the final solution.
Putting it together
There are two template types, Variable templates, and Tag templates. My first instinct was to create a variable template that would simply return the encrypted value. Much to my frustration no matter what I tried I simply could not get it to work, returning instead an undefined value.
In conversation with Simo, he pointed out what should have been obvious. The SHA-256 api call was an async operation while the variable code runs synchronously, so it simply skips over to the return statement while the call resolves.
Ok, onto the tag template.
The tag’s objective is it to output a custom dataLayer event with the hashed value passed in the object together with any other data points you may need. This gives you the flexibility of passing the data to whatever tag tech you want.
To build it we first define the Fields we need for the template. The first two are the main input fields of type text. One takes the name you want for the custom event, the other the value you want encrypted.
The other two fields are for the additional data points, a checkbox to switch on the option and a field of type ‘simple table’ which allows end users to create a table of key-value pairs which we will then pass into the event object.
The tag code
To do this we required 4 api functions (not counting the logToConsole
used for debugging purposes during the build).
createQueue
which allows us to create an array in window and returns a push function to push the values into that array, essentially, we can create the equivalent of dataLayer.push within the sandboxed js.
To get this to work we will also require the queryPermission
to check that the necessary permissions on access_globals
are available.
The makeTablemap
to turn our key value table into an object of key value pairs.
And finally, the sha256
.
//APIs const log = require('logToConsole'); const check = require('queryPermission'); const create = require('createQueue'); const hash = require('sha256'); const map = require('makeTableMap');
You then want to create:
- dataLayer push call
- a merge function to merge all the various key value pairs into the one object
- the success and failure call backs
- and finally the call for the encryption and push to dataLayer
// The dataLayer push const push = create('dataLayer'); // a function to merge all the object key value pairs const merge = function(){ const obj = {}, l = arguments.length; let i = 0, key; for (; i < l; i++){ for (key in arguments[i]) { obj[key] = arguments[i][key]; } } return obj; }; const event = {'event': data.event}; const other = map(data.add_fields, 'key', 'value'); //success/failure const onSuccess = () =>{ data.gtmOnSuccess(); }; const onFailure = () => { data.gtmOnFailure(); }; //Now let's hash hash(data.to_hash, (digest) => { const h = {'hash': digest}; const dlayer = merge(event, h, other); if (check('access_globals', 'readwrite', 'dataLayer')) { push(dlayer); onSuccess(); }},() =>{onFailure();},{outputEncoding: 'hex'});
The last step is to setup the permissions for the access global variables.
Simply add the key you declared using the createQueue function, in this case ‘dataLayer’, and set read write permissions to ‘true’.
Using the Tag
In the template gallery search for CryptoMe and add it. Then create a new tag and select the CryptoMe template tag which should appear under custom.
Then simply fill in the tag fields. Give your event a name, choose the value to encrypt and pass any additional value pairs you need.
The result, a custom event with all the data points you need and PII encrypted ready to pass to whatever tag tech you need.
I hope you find this useful, please leave any comments, feedback, or improvements you would like in the comments below, and of course feel free to take this adapt it for your own means.
Gavin Attard is a Consultant at 120feet. An analytics expert that applies over 15 years of commercial and marketing experience across multiple verticals with geek level technical skills in the field of data analytics, digital analytics implementation, target marketing, customer insight and enabling data orchestration for campaign management and personalisation.
Alteryx ACE Emeritus and a Tealium Expert, Gavin helps businesses maximise their opportunities by enabling their ability to design experiences that drive engagement.
We pushed V1.1 today whcih fixes a bug where users got an exception error thrown if they did not select additional properties.
Gavin Attard, thanks for creating this plug in and associted article, as this is something I was due to be working on I saved this for use later. I am just commenting as others my find this comment thread useful in the future
Just a quick question, I am trying to use this plug in and have come up against a snag.
The use case is as followed, I am passing an ID in an email campaing through the query string, I would like to hash this value and plase this into the Data Layer as you descrive your plug in.
I set up your plugin tag, and create a variable which captures the ID from the querry string. I than also use a Page View trigger to fire when the ID is present in the query string.
On testing, I can see the tag fire, as shown in screen shot, but I get an error thrown from the tag so I never see the event fire, or the value pushed to the data layer.
Just wanted to check that my workflow is correct or am I missing something really obvious.
Any advice on this would be much appreciated.
Gavin Attard, thanks for creating this plug in and associted article, as this is something I was due to be working on I saved this for use later. I am just commenting as others my find this comment thread useful in the future
Just a quick question, I am trying to use this plug in and have come up against a snag.
The use case is as followed, I am passing an ID in an email campaing through the query string, I would like to hash this value and plase this into the Data Layer as you descrive your plug in.
I set up your plugin tag, and create a variable which captures the ID from the querry string. I than also use a Page View trigger to fire when the ID is present in the query string.
On testing, I can see the tag fire, as shown in screen shot, but I get an error thrown from the tag so I never see the event fire, or the value pushed to the data layer.
Just wanted to check that my workflow is correct or am I missing something really obvious.
Any advice on this would be much appreciated.
Do you have any idea why I can’t find your template in the Tag Manager templates gallery?
I can see your template on the tag manager website. But not in my system when I search for a community template
Hi Gavin,
Me again, thanks for pushing that fix live it is all working beautifully now; I just have two questions/feature requests relating to the actual hashing function and the business case.
My current use case for context, as I mentioned to you before, is that I am hashing a Member ID from a URL string, this is a six-digit numerical value, here are my two questions:
1. Is there a way of providing a seed key to the algorithm like you do with random number generation. My issue is that if the format of my Member IDs are known by a third party to be six digit numbers, it’s not too much of an effort (still a pain) to backwards map the hash back to a Member ID
2. Is there a way of modifying the output hash from (I think a 32-byte) format which looks something like this “5lDYVnzl7x0OYjHNjQEPffK7GVaoc2BpDWsYrXyKWo4” to something a bit more human, maybe 10 digit Hex? I know this is literally the exact opposite of what a hash is suppose to do.
Thanks again for this plugin, it’s great 🙂
Hi Gavin,
Me again, thanks for pushing that fix live it is all working beautifully now; I just have two questions/feature requests relating to the actual hashing function and the business case.
My current use case for context, as I mentioned to you before, is that I am hashing a Member ID from a URL string, this is a six-digit numerical value, here are my two questions:
1. Is there a way of providing a seed key to the algorithm like you do with random number generation. My issue is that if the format of my Member IDs are known by a third party to be six digit numbers, it’s not too much of an effort (still a pain) to backwards map the hash back to a Member ID
2. Is there a way of modifying the output hash from (I think a 32-byte) format which looks something like this “5lDYVnzl7x0OYjHNjQEPffK7GVaoc2BpDWsYrXyKWo4” to something a bit more human, maybe 10 digit Hex? I know this is literally the exact opposite of what a hash is suppose to do.
Thanks again for this plugin, it’s great 🙂
Hi, it looks like this template is no longer available in the GTM community gallery. Did something happen / will it be available again soon?
Hi Dustin, really odd, we did not realise it is no longer available, we are looking into what happened.
Hi Folks, we found the issue with why it disappeared from the gallery. A missing space in the metadata file…. humpf.
Ok should be back up by tomorrow in the gallery.