DTM – How to Amend an Existing Analytics Setup

(Let me state right here at the beginning that judging by the feedback I got from my beta testers editors, this article may not be for the faint of heart. If you think Javascript should be treated with respect, you might want to stop reading.)

Have you ever seen the ‘[x] Page code is already present’ in the setup of the Adobe Analytics Tool in DTM?

[Screenshot]
Page code is already present
Ever wondered what that does?

You probably guessed (correctly), that it is meant for situations where your web site has a working deployment of Adobe Analytics (or “SiteCatalyst” or “Omniture” or whatever you are calling it) in place and you want to put DTM on it. You would then at some point remove the legacy code and rely fully on DTM.

While both, Analytics and DTM, are live on your site, you can build Page Load Rules (PLRs) that mimic the existing implementation, so that when you take away the legacy code, all you have to do is switch off the “[ ] Page code is already present” option and your done.

Why do you have to switch it off?

Well, as long as the box is ticked, Page Load Rules will execute, all right, but they won’t actually have any effect on your tracking.

With the option enabled, DTM sort of executes all PLRs “in a sandbox”, meaning whatever events or “variables” it sets will be on a “shadow s object”, not connected to your page-level s object at all.

Note: Event-based Rules (EBRs) and Direct call Rules (DCRs) are working fine, you can use them as you usually would. The switch only affects PLRs.

But…

What if you want to use DTM to amend your existing tracking?

I can think of two ways of doing that, and I freely admit there may be more.

  1. Set events and “variables” via Javascript
  2. Copy events and “variables” from DTM

We have all done the first method for some time now. It works fine, but it has one big problem: you must know Javascript to implement, maintain, and change it.

I therefore proudly present method 2: copying values from DTM.

Method 2

If you debug what DTM actually does with the ‘[x] Page code is already present’ option turned on, you’ll realise that it really acts as usual, meaning it happily goes through all the PLRs and does everything you tell it to do.

It does, however, apply it all to an s object that is not the one already present on the page.

Bummer, hm?

It would be great to be able to use DTM’s graphical UI to amend the existing tracking…

So let’s see: DTM does actually execute the PLRs… we also still have the s.doPlugins method… oh!

Why don’t we copy all the values from DTM into the page-level s object using the s.doPlugins method?

Would that work?

Oh, yes!

Prerequisite

You have to find out the ID of your Analytics Tool first.

Go to your page, open a console, then type

_satellite.getToolsByType("sc");

[Screenshot]
getToolsByType call in FF
If you now click the “more” link of the result you got, you’ll see an “id” attribute somewhere.

Copy the id.

[Screenshot]
The id as seen in FF
That’s all you need.

Please note that this thing only works if your _satellite.pageBottom() call is above the call to s.t()!

Code

Now put the following code into your s.doPlugins method:

s.usePlugins=true;
function s_doPlugins(s) {
    // ugly hack ahead!
    var g = _satellite.tools.c7b417741f9f0d2435c6dd064ad9fc12;
    var gev = g.events;
    var gvb = g.varBindings;
    if (gev && gev.length > 0) {
        for (i in gev) {
            s.events = s.apl(s.events,gev[i],",",1);
        }
    }
    if (gvb) {
        for (b in gvb) {
            s[b] = gvb[b];
        }
    }
}
s.doPlugins=s_doPlugins;

Make sure you are loading the apl plugin!

Explanation?

The _satellite object in the DOM contains data about all the configured tools. Inside the Adobe Analytics Tool, there are two arrays that are interesting for us: events & varBindings.

[Screenshot]
Events & varBindings
Those two arrays contain the events and “variables” set by DTM at page load, so this is where we’ll copy them from.

Lines 7 — 11 copy the events, while lines 12 — 16 copy all “variables” (props and eVars).

More

Since the code is pretty generic, it should really be turned into a plugin, don’t you think?

While we’re at it, why not add a couple of bells, and a whistle?

Overwrite Switch

With the first version of the code, we’re simply copying every “variable” that has been set in DTM. There may be situations where we might not want to overwrite existing values, right?

So let’s add a switch!

We’ll also turn the code into a function while we’re at it. And, just because we can, we’ll add two checks: a) that DTM is actually there, and b) that the ‘[x] Page code is already present’ switch is indeed enabled.

The code then looks like this:

s.mergeDTMShadowData = function(toolID, overwrite) {
	// overwrite defaults to true
	if (typeof overwrite === 'undefined' || overwrite === null) {
		overwrite = true;
	}
	// check if DTM is present
	if (typeof _satellite !== 'undefined') {
		var analyticsTool = _satellite.tool[toolID];
		// is the analytics tool enabled?
		var enabled = true;
		if (analyticsTool.settings.initTool !== undefined && analyticsTool.settings.initTool === false) {
			enabled = false;
		}
		if (enabled === false) {
			// copy events
			var eventArray = analyticsTool.events;
			if (eventArray && eventArray.length > 0) {
				for (ev in eventArray) {
					s.events = s.apl(s.events, eventArray[ev], ',', 1);
				}
			}
			// copy props & eVars
			var varArray = analyticsTool.varBindings;
			if (varArray) {
				for (variable in varArray) {
					if (overwrite || typeof s[variable] === 'undefined' || s[variable] === null) {
						s[variable] = varArray[variable];
					}
				}
			}
		}
	} else {
		console.log('DTM not found, bailing out...');
	}
}

And when we turn it into a plugin, it looks like this:

s.mergeDTMShadowData=new Function("t","o",""
+"if(typeof o==='undefined'||o===null){o=true;}if(typeof _satellite!="
+"='undefined'){var a=_satellite.tool[t];var e=true;if(a.settings.ini"
+"tTool!==undefined&&a.settings.initTool===false){e=false;}if(e===fal"
+"se){var b=a.events;if(b&&b.length>0){for(c in b){s.events=s.apl(s.e"
+"vents,b[c],',',1);}}var d=a.varBindings;if(d){for(f in d){if(o||typ"
+"eof s[f]==='undefined'||s[f]===null){s[f]=d[f];}}}}}else{console.lo"
+"g('DTM not found, bailing out...');}");

Feel free to copy the plugin. You can use it in your s.doPlugins method like this:

[Screenshot]
Call to plugin in s.doPlugins

Always more

I have one big issue with the whole thing: in order to make this work, I must edit the original s_code.js or AppMeasurement.js file: I must add the plugin and the call to it.

Not good.

I mean, yes, you can do that while you’re deploying DTM alongside your Analytics deployment, but let’s be honest: we didn’t think of that back when we did that, right? DTM is already there, and there are no slots in any of the next milestones.

What I really want is to inject all of this into an existing page with DTM.

Hm…

The top answer on http://stackoverflow.com/questions/9134686/adding-code-to-a-javascript-function-programatically comes to the rescue.

Since the PLRs will still execute, any Javascript in a PLR will as well.

So, we’ll write a little bit of JS that caches the original s.doPlugins method, overwrites it, then calls the plugin plus the original method in the new method.

Say again?

Well, we want the original s.doPlugins to run, but we want to add a call to the plugin before it does, correct?

We can build a function that does exactly that. How will that function be called? Because we’ll call it “s.doPlugins“, of course.

The complete solution now looks like this:

s.mergeDTMShadowData=new Function("t","o",""
+"if(typeof o==='undefined'||o===null){o=true;}if(typeof _satellite!="
+"='undefined'){var a=_satellite.tool[t];var e=true;if(a.settings.ini"
+"tTool!==undefined&&a.settings.initTool===false){e=false;}if(e===fal"
+"se){var b=a.events;if(b&&b.length>0){for(c in b){s.events=s.apl(s.e"
+"vents,b[c],',',1);}}var d=a.varBindings;if(d){for(f in d){if(o||typ"
+"eof s[f]==='undefined'||s[f]===null){s[f]=d[f];}}}}}else{console.lo"
+"g('DTM not found, bailing out...');}");

s.doPlugins = (function() {
  return function() {
	  s.mergeDTMShadowData("c7b417741f9f0d2435c6dd064ad9fc12",true);
  
	  // now call the orignal
  	var result = s_doPlugins.apply(this,arguments);
  	return result;
  };
}());

Put that into the third-party/Javascript section of a PLR and you’re done. No changes are needed to the existing legacy code! None!

Always more after that

Call me a perfectionist, but I could give you a couple of improvements off the top of my head.

The easiest one: the “true” in the call to our plugin should not be a constant, but rather be a Data Element (_satellite.getVar("Overwrite Existing Vars")), shouldn’t it?

And while we’re at it: do you always deploy the whole site in one go? I have seen people add parts to it, and those parts would be different, use different templates and such.

It is entirely thinkable that parts of your site use legacy tracking, while other parts track solely with DTM.

So the aforementioned Data Element should itself take into account the template, maybe URL, maybe something in the data layer…

Plus you’d be well-advised making a second DE; one that enables or disables the whole mechanism in a similar way.

And do we really need the plugin?

I made it because I wanted to plug it into an s_code.js file. Now that the code sits in DTM, I could just put it straight in, no? And it really wouldn’t have to be minified beyond recognition.

Ah, too many things to do, too little time.

4 thoughts on “DTM – How to Amend an Existing Analytics Setup

  1. And do we really need the plugin?

    Oh yes i do / did. 🙂

    I made it because I wanted to plug it into an s_code.js file

    *harrumph* 😉

    Thanks for doing this, it saved me time and energy. Two notes:

    1.You can’t use Adobe Analytics Custome code in PLR
    2. If you try to use Data Elements in PLR it must be DOM ready or Onload. At Bottom of Page the Data Element will be empty (don’t know why yet)

    Like

  2. Well, this is interesting and really useful workaround for websites with long release cycle and painful migration process, but I am not fan of mixing DTM Analytics architecture with legacy page code. If not necessary, I would rather avoid using this solution – my personal preference 🙂

    Like

    1. Same here.

      I would avoid this like the plague!

      But reality sometimes makes hacks necessary, and it is good to be able to go back then and just use the hack off the shelf, so to speak.

      Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.