essentially: bind mixpanel.track()
calls to existing Universal Analytics + GA4 implementations without adding new triggers for each event
note: this is experimental... every product's GTM implementation is different... please test this in a sandbox before using in production
Step 1: Install the Mixpanel GTM Template to your GTM container
this module binds all of mixpanel's javascript SDK methods to an object that is native to the GTM container.
Step 2: Configure mixpanel.init()
to run at consent initialization
- add a new tag, choose
mixpanel
... in the tag type dropdown, chooseset_config
and in the Project Token dialog paste in your mixpanel project token (mixpanel settings => project settings => access keys)
- for the required
set_config
option choose:
persistence : localStorage
- for firing triggers, choose consent initialization
- we do this because we want to ensure mixpanel is available as soon as possible... we want it at the "top" of the GTM data layer, so it can listen to initial page view events
this is the code:
<script>
/**
title: GTM → Mixpanel (auto capture)
purpose: capture GTM's dataLayer as mixpanel events
requires: mixpanel installed on page
by: AK <ak@mixpanel.com>
governance: see eventBlackList, propertyKeyBlackList, & propertyValueBlackList
*/
(function() {
if (!window.mixpanel_gtm_dataCapture) {
try {
//ensure code only runs once
window.mixpanel_gtm_dataCapture = true
//events that CONTAIN the following names WILL NOT be tracked
var eventBlackList = ['gtm.init', 'gtm.dom', 'gtm.load', 'gtm.scrollDepth', 'gtm.click', 'optimize.']
//events that HAVE the following properties KEYS WILL NOT be tracked
var propertyKeyBlackList = ['foo', 'bar', 'baz']
//events that HAVE the following properties VALUES WILL NOT be tracked
var propertyValueBlackList = ['qux', 'mux', 'dux']
//copy gtm's data layer
var proxied = window.dataLayer.push;
//patch a function which knows how to track to mixpanel when items are pushed onto the data layer
window.dataLayer.push = function() {
var args = Array.prototype.slice.call(arguments);
var _this = this;
var gtagData = arguments[0]
if (gtagData.event && window.mixpanel) {
//event is not blacklisted
if (!doesContain(eventBlackList, gtagData.event)) {
//event does not have blacklisted property KEYS
if (unionArr(Object.keys(gtagData), propertyKeyBlackList).length === 0) {
//event does not have blacklisted property VALUES
if (unionArr(Object.values(gtagData), propertyValueBlackList).length === 0) {
//send the event to mixpanel
mixpanel.track(gtagData.event, cleanObject(gtagData))
}
}
}
//gtm proceeds as normal
return proxied.apply(this, arguments);
};
}
} catch (e) {
// if anything fails, gtm proceeds as normal
return proxied.apply(this, arguments);
}
}
//HELPERS
//helper to find substrings in blacklist
function doesContain(blackList, term) {
if (blackList.some(function(v) {
return term.indexOf(v) >= 0
})) {
return true
} else {
return false
}
}
//helper to find the intersection of two arrays
function unionArr(array1, array2) {
return array1.filter(function(n) {
return array2.indexOf(n) !== -1;
});
}
//helper to clean dataLayer objects into a flat structure
function cleanObject(object) {
var simpleObject = {};
for (var prop in object) {
if (!object.hasOwnProperty(prop)) {
continue;
}
if (typeof(object[prop]) == 'object') {
continue;
}
if (typeof(object[prop]) == 'function') {
continue;
}
simpleObject[prop] = object[prop];
}
return simpleObject; // returns cleaned up JSON
}
})();
</script>
for firing triggers on this tag, ensure this code runs after our first (init
) tag:
(this is important because this snippet depends upon the mixpanel library; so the sequencing matters)
deploy these two new tags and you should instantly start seeing mixpanel events in your project, under the events tab.
once you do have data flowing, for further governance (renaming stuff, altering the event schema) check out mixpanel's data administration tool, lexicon
feel free to read the "patch" comments; there are some governance features that are worth highlighting:
//events that CONTAIN the following names WILL NOT be tracked
var eventBlackList = ['gtm.init', 'gtm.dom', 'gtm.load', 'gtm.scrollDepth', 'gtm.click', 'optimize.']
//events that HAVE the following properties KEYS WILL NOT be tracked
var propertyKeyBlackList = ['foo', 'bar', 'baz']
//events that HAVE the following properties VALUES WILL NOT be tracked
var propertyValueBlackList = ['qux', 'mux', 'dux']
this code "listens" to the GTM dataLayer
and will automatically forward events to mixpanel unless:
- the event name contains one of the items on the blacklist
- a property/dimension on the event has a key on the blacklist
- a property/dimension on the event has a value on the blacklist
note: you may not wish to use all of these governance features (like ignore events by property key/value). that's fine, just set the value of those variables to an empty array []
there's a great browser extension: Tag Manager Assistant made by google that can help you to debug your current tag setup... it lets you peel back all the "data layers" of any GTM implementation, and you can use it on your production website.
before you muck around with filtering and governance features, it's a good idea to familiarize yourself with the tags you already have deployed: