Skip to content

Instantly share code, notes, and snippets.

@mbaersch
Last active November 4, 2021 09:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mbaersch/5919bc1c795031183a525cb8c64a9352 to your computer and use it in GitHub Desktop.
Save mbaersch/5919bc1c795031183a525cb8c64a9352 to your computer and use it in GitHub Desktop.
getUniqueEventId() - creates cacheable event ids for deduplication of events that cannot use the same trigger
/* create unique event ids for specific events that "live" for a limited time
(default: 1 scond).
returns a value that consist of the key, a random number and a timestamp;
dot-separated. An existing value for a key that is requested within the
defined lifespan will remain the same, otherwise (not existing or too old)
a new value is generated and stored. The limited lifespan can be used to
deduplicate several hits of the same type between page loads (e. g. Add2Cart
or multiple PageViews in SPAs).
the purpose is to deduplicate hits for client- and server-side Facebook
tracking even when GA4 tags and FB tags fire at different triggers (e. g.
for consent reasons)
if you create a variable named "getUniqueEventId" with this code, an
example call in a second variable to create a page_view event id would
look like this:
function() { return {{getUniqueEventId}}('page_view'); }
example result: "page_view.44935367.1630613990849"
use as Custom JS Variable to return the function to create event IDs for
PageViews or FB events like ViewContent, AddToCart, InitiateCheckout,
Purchase and others vs. Google Analytics (e-commerce) events that get
sent at different trigger events. Send value as eventID (FB tag
client-side) and event_id (GA4 client-side event property -> FB
tag server-side) in both tags.
Note: if can use the same dataLayer event to trigger / fire GA and FB tags
at the same time, you do not need to "cache" evend ids with this
function. Use the Custom Variable Template for client-side GTM at
https://tagmanager.google.com/gallery/#/owners/mbaersch/templates/event-id
instead to create an event id variable that can be used in both tags
without caching.
*/
function() {
return function(key, lifespan) {
var getRandomInt = function(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
lifespan = lifespan || 1;
window._eventIds = window._eventIds || [];
var e = window._eventIds[key];
if (!(e && e.id && e.ts && ((Date.now() - e.ts) / 1000 < lifespan))) {
window._eventIds[key] = {ts: Date.now(), id: getRandomInt(10000000, 99999999)};
e = window._eventIds[key];
}
return key + "." + e.id+'.'+e.ts;
}
}
<script>
/*
If a unique event id based on gtm.uniqueEventId fails, because GA4 picks up a different
event, an alternative solution can be to repush all relevant events with a complete
unique event id into the dataLayer. Fiddling around with the dataLayer in JS is not
an ideal solution and I have no clue why this works instead of using gtm.uniqueEventId
as part of a variable-based event id... but it solved the problem in some cases.
Note: If it is possible to add event ids to every dataLayer push directly when they are
created by the cms, it would be an ideal solution. Try to have that implemented. As a fix,
the following code can be used to provide a new html tag and trigger this with every
event that has to be duplicated.
The code extracts the last push to the dataLayer, adds a "customEventId" (a dot-separated
combination of a timestamp and a random 10-digit integer), changes gtm.uniqueEventId in
order to have the new event show up in preview mode for debugging and then repushes the
event to the dataLayer, adding ".unique" to the event name.
All tags for FB and "transport"-tags that are used to send the same event to the
server-side tag manager / CAPI (usually GA4 tags) can then be triggered by the new
dataLayer events (like "view_item.unique") and use the "customEventId" from the dataLayer
as a dataLayer variable for deduplication.
*/
if (window.dataLayer) {
var ev = JSON.parse(JSON.stringify(window.dataLayer[window.dataLayer.length-1]));
ev.customEventId = (Date.now() + ".").concat(
Math.floor(Math.random() * (9999999999 - 1000000000 + 1)) + 1000000000
);
ev.event += ".unique";
ev["gtm.uniqueEventId"] += ".1";
window.dataLayer.push(ev);
}
</script>
<script>
/*Code for adding a customEventId without repushing:
--------------------------------------------------
If a repush using the solution from
https://gist.github.com/mbaersch/5919bc1c795031183a525cb8c64a9352#file-option-1-repush-events-with-id-html
means too much work adjusting and adding triggers, the customEventId can be added directly to
the last event in the dataLayer.
In order to achieve this, this first script tag and the contained code can be added as a
custom html tag to the container and then the new tag is used as a setup tag for every
tag that needs to access the unique customEventId.
Note: to access this value in GTM, you cannot use a dataLayer variable! at the time the
dataLayer is read, the key and value will not pe present yet. Use the code from the second
script (see below) to create a custom JS variable. This will enable tags to access the
customEventId from the anhanced dataLayer event push.
*/
if (window.dataLayer) {
var ev = window.dataLayer[window.dataLayer.length-1];
if (!ev.customEventId) {
ev.customEventId = (Date.now() + ".").concat(Math.floor(Math.random() * (9999999999 - 1000000000 + 1)) + 1000000000);
}
}
</script>
<script>
/*
Code for accessing the Id:
--------------------------
paste the following code in a new custom JS variable. This variable can then be used
to add an eventId / event_id to all FB- and transport tags (usually GA4, sent to a
GTM server) that fire on the same event and use the setup tag to create the id first.
*/
function(){
if (window.dataLayer) {
var ev = window.dataLayer[window.dataLayer.length-1];
return ev.customEventId;
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment