Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
102 lines (85 sloc) 5.16 KB
<script title="gtm:ga-spy-to-datalayer">
/**
* Expose all non-GTM-based ga commands to GTM via the data layer.
*/
var dataLayer = window.dataLayer=window.dataLayer||[],
dataLayerNamespace = 'spy.ga';
(function(b){var d,e,c=function(a){if(b=null,!a.callback||"function"!=typeof a.callback)throw new Error("["+a.debugLogPrefix+"] Aborting; No listener callback provided.");return a.gaObjName=a.gaObjName||window.GoogleAnalyticsObject||"ga",a.debug=!!a.debug,a.debugLogPrefix=a.debugLogPrefix||"gaSpy",a}("function"==typeof b?{callback:b}:b),f=c.gaObjName,g=window[f],h=window.console&&c.debug?function(){var a=[].slice.call(arguments);a.unshift("["+c.debugLogPrefix+"]"),console.log.apply(console,a)}:function(){},i=function(a){var b,d={args:a,the:{}},e=d.the;return c.debug&&function(b,c){for(b="Intercepted: ga(",c=0;c<a.length;c++)b+="string"==typeof a[c]?'"'+a[c]+'"':a[c],c+1<a.length&&(b+=", ");b+=")",h(b)}(),"function"==typeof a[0]?e.callback=a[0]:a[0]&&a[0].split&&(b=a[0].split("."),e.trackerName=b.length>1?b[0]:"t0",e.command=b.length>1?b[1]:b[0],b=b[b.length-1].split(":"),e.pluginName=b.length>1?b[0]:void 0,e.pluginMethodName=b.length>1?b[1]:void 0,"require"===e.command||"provide"===e.command?(e.pluginName=a[1],"provide"===e.command&&(e.pluginConstructor=a[2])):("send"===e.command&&(e.hitType=a[a.length-1].hitType||a[1]),"object"==typeof a[a.length-1]&&(e.trackerName=a[a.length-1].name||e.trackerName))),h("Run listener callback",e),!1!==c.callback(d)||(h("Block hit")||!1)},j=function(){var a=[].slice.call(arguments);if(c.debug){if(!i(a))return}else try{if(!i(a))return}catch(a){}return j._gaOrig.apply(j._gaOrig,a)},k=function(){var a,b=j._gaOrig=window[f];h("Hijack",b._gaOrig?"(already hijacked)":""),window[f]=j;for(a in b)b.hasOwnProperty(a)&&(window[f][a]=b[a])};if(h("Config:",c),g||(h("Instantiate GA command queue"),g=window[f]=function(){(window[f].q=window[f].q||[]).push(arguments)},g.l=1*new Date),g.getAll)h("GA already loaded; cannot see previous commands"),k();else{if(!g.l)throw new Error("["+c.debugLogPrefix+"] Aborting; `"+f+"` not the GA object.");if(h("Command queue instantiated, but library not yet loaded"),g.q&&g.q.length){for(h("Applying listener to",g.q.length," queued commands"),d=[],e=0;e<g.q.length;e++)i([].slice.call(g.q[e]))&&d.push(g.q[e]);g.q=d}else g.q=[];g(k),k()}}
)( function _gaSpy_cb_( ev ){
var scope = '', frame = {}, frameNamespace, the = ev.the, a = ev.args;
// If last argument is object, use as fields object.
var fields = typeof a[a.length-1] == 'object' ? a.pop() : {};
// Ignore callbacks.
if( the.callback ) return;
// Ignore commands from GTM.
//TODO: Does this work when gtm loads ga plugins (i.e. autolinker)?
if( the.trackerName && the.trackerName.substr( 0, 3 ) == 'gtm' ) return;
if( the.pluginName ){
scope = 'plugin.'+the.pluginName;
if( the.command === 'provide' )
fields = a[2]; // plugin constructor
else {
//TODO: provide generic data layer structure for custom arguments
// if( command === 'require' ){ }
}
}
else switch( the.command ){
case 'create':
fields.trackingId = fields.trackingId || a[1];
fields.cookieDomain = fields.cookieDomain || a[2];
fields.name = fields.name || a[3];
break;
case 'set':
if( a[1] ) fields[ a[1] ] = a[2];
break;
case 'send':
scope = 'hit';
switch( fields.hitType = fields.hitType || a[1] ){
case 'pageview':
fields.page = fields.page || a[2];
break;
case 'event':
fields.eventCategory = fields.eventCategory || a[2];
fields.eventAction = fields.eventAction || a[3];
fields.eventLabel = fields.eventLabel || a[4];
fields.eventValue = fields.eventValue || a[5];
break;
case 'social':
fields.socialNetwork = fields.socialNetwork || a[2];
fields.socialAction = fields.socialAction || a[3];
fields.socialTarget = fields.socialTarget || a[4];
break;
case 'social':
fields.timingCategory = fields.timingCategory || a[2];
fields.timingVar = fields.timingVar || a[3];
fields.timingValue = fields.timingValue || a[4];
fields.timingLabel = fields.timingLabel || a[5];
break;
}
break;
case 'remove':
break;
default:
scope = 'unknown';
}
// Push command data to data layer.
frameNamespace = dataLayerNamespace+(dataLayerNamespace?'.':'')
+the.trackerName
+(scope?'.':'')+scope;
frame[frameNamespace] = fields;
frame.event = frameNamespace;
dataLayer.push( frame );
// The values specified in a send command apply only to the hit; clear them
// immediately after so data layer more closely reflects data in tracker
// object, and so subsequent hits will not be polluted by prior values.
// Instead of this (which adds generic message for every command), it's cleaner
// to accomplish this using a low priority -firing tag (or cleanup tag) that runs:
// `google_tag_manager[{{Container ID}}].dataLayer.set(dataLayerNamespace,undefined);`:
if( 'send' === the.command ){
frame = {};
frame[frameNamespace] = undefined;
dataLayer.push( frame );
}
// return false; <-- Uncomment to block non-GTM commands.
} );
</script>