Category Archives: DTM

Adobe Launch’s Rule Ordering is a big deal for Single Page Apps

In November, I posted about some of the ways that Launch will make it easier to implement on Single Page Apps (SPAs), but I hinted that a few things were still lacking.
In mid-January, the Launch team announced a feature I’ve been eagerly awaiting: the ability to order your rules. With this ability, we finally have a clean and easy way to implement Adobe Analytics on a Single Page App.

The historical problem

As I mentioned in my previous post, one of the key problems we’ve seen in the past was that Event-Based Rules (EBRs) and Direct Call Rules (DCRs) can’t “stack”. Let me explain what I mean by that.

Not a single page app? Rule Stacking rocks!

For example, let’s say I have an internal search “null results” page, where the beacon that fires should include:

  • Global Variables, like “s.server should always be set to document.hostname”
  • Variables specific to the e-commerce/product side of my site with a common data layer structure (pageName should always be set to %Content ID: Page Name%)
  • Search Results variables (like my props/eVars for Search Term and Number of Search Results, and a custom event for Internal Searches)
  • Search Results when a filter is applied (like a listVar for Filter Applied and an event for User applied Search Filter)
  • Null Results Variables (another event for Null Internal Searches and a bit of logic to rewrite my Number of Search Results variable from “0” to “zero” (because searching in the reports for “0” would show me 10, 20, 30… whereas “zero” could easily show me my null results)

With a non-SPA, when a new page load loads, DTM would run through all of my page load rules and see which had conditions that were matched by the current page. It would then set the variables from those rules, then AFTER all the rules were checked and variables were set, DTM would send the beacon, happily combining variables from potentially many rules.

Would become this beacon:

If you have a Page Load Rule-based implementation, this allows you to define your rules by their scope, and can really use the power of DTM to only apply code/logic when needed.

Single Page App? Not so much.

However, if I were in a Single Page App, I’d either be using a Direct Call Rule or an Event-Based Rule to determine a new page was viewed and fire a beacon. DCRs and EBRs have a 1:1 ratio with beacons fired- if a rule’s conditions were met, it would fire a beacon. So I would need to figure out a way to have my global variables fire on every beacon, and set site-section-specific and user-action-specific variables, for every user action tracked. This would either mean having a lot of DCRs and EBRs for all the possible combos of variables (meaning a lot of repeat effort in setting rules, and repeated code weight in the DTM library), or a single massive rule with a lot of custom code to figure out which user-action-specific variables to set:

Or leaving the Adobe Analytics tool interface altogether, and doing odd things in Third Party Tag blocks. I’ve seen it done, and it makes sad pandas sad.

The Answer: Launch

Launch does two important things that solve this:

  1. Rules that set Adobe Analytics Variables do not necessarily have to fire a beacon. I can tell my rule to just set variables, to fire a beacon, or to clear variables, or any combination of those options.
  2. I can now order my rules to be sure that the rule that fires my beacon goes AFTER all the rules that set my variables.

So I set up my 5 rules, same as before. All of my rules have differing conditions, and use two similar triggers: one set to fire on Page Bottom (if the user just navigated to my site or refreshes a page, loading a fresh new DOM) and one on Data Element Changed (for Single Page App “virtual page views”, looking at when the Page Name is updated in the Data Layer).

When I create those triggers, I can assign a number for that trigger’s Order:

One rule, my global rule, has those triggers set to fire at “50” (which is the default number, right in the middle of the range it is recommended that I use, 1-100). The rule with this trigger not only sets my global variables, it also fires my beacon then clears my variables:

Most of my other rules, I give an Order number of “25” (again, fairly arbitrary, but it gives me flexibility to have other rules fire before or after as needed). One rule, my “Internal Search: Null Results” rule is set to the Order number “30”, because I want it to come AFTER the “Internal Search: Search Results” rule, since it needs to overwrite my Number of Search Results variable from “0” (which it got from the data layer) to “Zero”.

This gives me a chance to set all the variables in my custom rules, and have my beacon and clearVars fire at the end in my global rule (the rule’s Order number is in the black circles):

I of course will need to be very careful about using my Order numbers consistently- I’m already thinking about how to fit this into existing documentation, like my SDR.


This doesn’t just impact Single Page Apps- even a traditional Page Load Rule implementation sometimes needs to make sure one rule fires after another, perhaps to overwrite the variables of another, or to check a variable another rule set (maybe I’m hard coding in one rule, and based on that value, want to fire another rule). I can even think of cases where this would be helpful for third party tags. This is a really powerful feature that should give a lot more control and flexibility to your tag management implementation.

Let me know if you think of new advantages, use cases, or potential “gotchas” for this feature!

Adobe DTM Launch: Improvements for Single Page Apps

For those following the new release of Adobe’s DTM, known as Launch, I have a new blog post up at the Cognetik blog, cross-posted below:

It’s finally here! Adobe released the newest version of DTM, known as “Launch”. There are already some great resources out there going over some of the new features (presumably including plenty of “Launchey Launch” puns), which includes:

  • Extensions/Integrations
  • Better Environment Controls/Publishing Flow
  • New, Streamlined Interface

But there is one thing I’ve been far more excited about than any other: Single Page App compatibility. I’ve mentioned on my personal blog some of the problems the old DTM has had with Single Page Apps:

  • Page Load Rules (PLRs) can’t fire later than DOMready
  • Event-Based Rules (EBRs) and Direct Call Rules (DCRs) can’t “stack” (unlike PLRs, there’s a 1:1 ratio between rules and analytics beacons, so you can’t have one rule set your global variables, and another set section-specific variable, and another set page-specific variables, and have them all wrap into a single beacon)
  • It can be difficult to fire s.clearVars at the right place (and impossible without some interesting workarounds)
  • Firing a “Virtual Page Load” EBR at the right time (after your data layer has updated, for instance) can be tricky.

So much of this is solved with the release of DTM Launch.

  • You can have one rule that fires EITHER on domReady OR on a trigger (Event-based or Direct Call).
  • You have a way to fire clearVars.
  • You can add conditions/exclusions to Direct Call rules

There are other changes coming that will improve things even further, but for now, these changes are pretty significant for Single Page apps.

Multiple Triggers on a Single Rule

If I have a Single Page App, I’ll want to track when the user first views a page, the same as for a “traditional” non-App page. So if I’m setting EBRs or DCRs for my “Virtual Page Views”, I’d need to account for this “Traditional Page Load” page view for the user’s initial entry to my app.
In the past, I’d either have a Page Load Rule do this (if I could be sure my Event-Based Rules wouldn’t also run when the page first loaded), or I could do all my tracking with Event-Based Rules, and I’d have to suppress that initial page view beacon. I may end up with an identical set of rules- one for when my page truly loads, and one for “Virtual Page Views”.

Now, I can do this in a single rule:

Where my “Core- Page Bottom” event fires when the page first loads (like an old Page Load Rule):

…and another “Page Name Changed” event that fires when my “page name” Data Element changes (like an old Event-Based Rule):

No more need to keep separate sets of rules for Page Load Rules and Virtual page views!

Clearing variables with s.clearVars()

Anyone who has worked on a Single Page App, or on any Adobe Analytics implementation with multiple s.t() beacons on a single DOM, has felt the pain of variables carrying over from beacon to beacon. Once an “s” variable (like s.prop1) exists on the page, it will hang around and be picked up by any subsequent page view beacon on that page.

Page 1

Page 2

Page 3

Page 4



Search Results

PDP > Red Wug

Product List





s.eVar1 (search term)


Red Wug

Red Wug

Red Wug

My pageName variable is fine because I’m overwriting it on each page, but my Search Term eVar value is hanging around past my Search Results page! And on pages where I don’t write a new events string, the most recent event hangs around!

In the old DTM, I had a few options for solving this. I could do some bizarre things to daisy-chain DCRs to make sure I could get the right order of setting variables, firing beacons, then clearing variables. Or, I could use a hack in the “Custom Code” conditions of an Event-Based Rule, to ensure s.clearVars would run before I started setting beacons. Or, more recently, I could use s.registerPostTrackCallback to run the s.clearVars function after the s_code detected an s.t function was called.

Now, it’s as simple as specifying that my rule should set my variables, then send the beacon, then clear my variables:

Directly in the rule- no extra rules, no custom code, no workarounds!

Rule Conditions on ALL Rule Types (including Direct Call)

If I were using Direct Call Rules for my SPA, in the past, I’d have to account for Direct Call Rules having a 1:1 relationship with their trigger. If I had some logic I needed to fire on Search Results pages, and other logic to fire on Purchase Confirmation pages, I could have my developers fire a different “_satellite.track” function on every page:

Then in each of those rules, I’d maintain all my global variables as well as any logic specific to that beacon. This could be difficult to maintain and introduces extra work and many possible points of failure for developers.

Or, I could have my developers fire a global _satellite.track(“page view”) on every page, and in that one rule, maintain a ridiculous amount of custom code like this:

This would take me entirely out of the DTM interface, and make some very code-heavy rules (not ideal for end-user page performance, or for DTM user experience — here’s hoping your developer leaves nice script comments!)

Now, I can still have my developers set a single _satellite.track(“page view”) (or similar), and set a myriad of rules in Launch, each using that same “page view” trigger, but each with a condition so you can set different variables in different rules directly in the interface when your developers fire _satellite.track(“page view”) on your Search Results versus when they fire _satellite.track(“page view”) on your Purchase Confirmation page:

I’d love to say all my SPA woes were solved with this release, but to show I haven’t entirely drunk the Kool-aid, I will admit some of my most wished-for features (and extensions) aren’t in this first release of Launch. I know they’re coming, though- future releases of Launch will add additional features that will make implementing on a Single Page App even simpler, but for now, it still feels like Christmas came early this year.

Coming to Adobe Summit 2017

adobe-su-1024x454I’ll be at Adobe Summit in Las Vegas next week, Monday March 19th through Friday March 24th. If you happen to be out that way, shoot me a comment here and hopefully we can meet up! I’ll be attending a lot of the DTM sessions and will be ready to help folks understand what the DTM updates mean for them.
I’ll also be presenting at Un-Summit at UNLV on Monday, speaking about Marketing Innovation and Cognetik’s new tableau data connector. Come check it out!

Deploying Google Marketing Tags Asyncronously through DTM

I had posted previously about how to deploy marketing tags asynchronously through DTM, but Google Remarketing tags add an extra consideration: Google actually has a separate script to use if you want to deploy asynchronously. The idea is, you could reference the overall async script at the top of your page, then at any point later on, you would fire google_trackConversion to send your pixel. However, this is done slightly differently when you need your reference to that async script file to happen in the same code block as your pixel… you have to make sure the script has had a chance to load before you fire that trackConversion method, or you’ll get an error that “google_trackConversion is undefined”.

Below is an example of how I’ve done that in DTM.

//first, get the async google script, and make sure it has loaded
var dtmGOOGLE = document.createElement('SCRIPT');
var done = false;

dtmGOOGLE.setAttribute('src', '//');

dtmGOOGLE.onload = dtmGOOGLE.onreadystatechange = function () {
 if(!done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete")) {
 done = true;

 // Handle memory leak in IE
 dtmGOOGLE.onload = dtmGOOGLE.onreadystatechange = null;

//then, create that pixel
function callback(){
 /* <![CDATA[ */
 google_conversion_id : 12345789,
 google_custom_params : window.google_tag_params,
 google_remarketing_only : true

Why (and why not) use a Data Layer?

What’s a Data Layer?

Tag Management Systems can get data a variety of ways. For instance in DTM you can use query string parameters, meta tags, or cookie values- but in general, data for most variables comes from one of two sources:

  • To really take advantage of a tag management system like DTM, I may choose to scrape the DOM. I’m gonna call this the MacGyver approach. This uses the existing HTML and styles on a site to For instance, DTM could use CSS selectors to pull the values out of a <div> with the class of “breadcrumb”, and end up with a value like “electronics>televisions>wide-screen”. This relies on my site having a reliable CSS structure, and there being elements on the page that include the values we need for reporting.
  • If I want even more flexibility, control and predictability, I may work with developers to create a data layer. They would create a JavaScript object, such as “universal_variable.pageName”, and give it a value based on our reporting needs, like “electronics | televisions | wide-screen > product list”. This gives greater control and flexibility for reporting, but requires developers to create JavaScript objects on the pages.

Conceptually speaking, a data layer is page-specific (but tool-agnostic) metadata that describes the page and the actions a user may take on it. Practically speaking, a data layer typically consists of a JavaScript object that contains all of the values we’d want to report on for a given page or user.

Data layers are important because they save developers time by allowing them to abstract out the metadata into a tool-agnostic syntax that a TMS like DTM can then ingest and set as data elements. Whereas once I would have told IT “please set s.prop5 and s.eVar5 to the search term on a search results page, and set to event20” now I can just say “please put the search term in a javascript object such as and tell me what object it is.” Then the TMS administrators could easily map that to the right variables from there.

You can see an example data layer if you’d like, or you can pull open a developer console for this very blog and look at the object “digitalDataDDT” to see the data layer that is automatically created from Search Discovery’s wordpress plugin.

Why a Data Layer?

My friends at 33 Sticks also have a great blog post on the subject, but I’ll list out some of the reasons I prefer clients to use a Data Layer. To me, it’s an upfront investment for a scalable, easily maintained implementation going forward. It does mean more work upfront- you have to first design the data layer to make sure it covers your reporting requirements, then you’ll need developers to add that to your site. But beyond those upfront tasks, configuration in your TMS will be much simpler, and it will save you many hours of CSS guess work and DOM scraping, and it may prevent broken reporting down the line.

    Upfront LOE Maintenance LOE
Route Amount of Control Dev Analytics Dev Analytics
Old fashioned “page on code” Medium Heavy Heavy Heavy Heavy
DTM + “Macgyver” Low Minimal Heavy Minimal Heavy
DTM + Data Layer High Heavy Medium Minimal Minimal

Another potential benefit to a Data Layer is that more and more supplementary tools know how to use them now. For instance, Observepoint’s site scanning tool can now return data on not just your Analytics and Marketing beacons, but on your Data Layer as well. And one of my favorite debugging tools, Dataslayer, can return both your beacons and your data layer to your console, so if something is breaking down, you can tell if it’s a data layer issue or a TMS issue.

Ask Yourself

Below are some questions to ask yourself when considering using a data layer:

How often does the code on the site change? If the DOM/HTML of the site changes frequently, you don’t want to rely on CSS selectors. I’ve had many clients have reports randomly break, and after much debugging we realized the problem was the developers changed the code without knowing it would affect analytics. It’s easier to tell developers to put a data layer object on a page then leave it alone, than it is to tell them to not change their HTML/CSS.

How CSS-savvy is your TMS team? If you have someone on your team who is comfortable navigating a DOM using CSS, then you may be able to get away without a data layer a little more easily… but plan on that CSS-savvy resource spending a lot of time in your TMS.  I’ll admit, I enjoy DOM-scraping, and have spent a LOT of time doing it. But I recognize that while it seems like a simple short-term fix, it rarely simplifies things in the long run.

How many pages/page types are on the site? A very complicated site is hard to manage through CSS- you have to familiarize yourself with the DOM of every page type.

How are CSS styles laid out? Are they clean, systematic, and fairly permanent? Clearly, the cleaner the DOM, the easier it is to scrape it.

How often are new pages or new site functionality released? Sites that role out new microsites or site functionality frequently would need a CSS-savvy person setting up their DTM for every change. Alternatively, relying on a data layer requires a data-layer-savvy developer on any new pages/site/functionality. It is often easier to write a solid Data Layer tech spec for developers to reference for projects going forward than to figure out CSS selectors for every new site/page/functionality.

How much link-tracking/post-page-load tracking do you have on your site? If you do need to track a lot of user actions beyond just page loads, involving IT to make sure you are tracking the right things (instead of trying to scrape things out of the HTML) can be extremely valuable. See my post on ways to get around relying on CSS for event-based rules for more info on options.

What is the turn-around time for the developers? Many clients move to DTM specifically because they can’t work easily within their dev team to set up analytics. A development-driven data layer may take many months to set up, stage, QA, and publish. Then if changes are needed, the process starts again. It may be worth going through the lengthy process initially, but if changes are frequently needed in this implementation, you may find yourself relying more on the DOM.

Are there other analytics/marketing tag vendors that may use a data layer? You may be able to hit two birds with one stone by creating a data layer that multiple tools can use.

Have you previously used another tag management system? Often, a data layer set up for a different tool can be used by DTM. Similarly, if the client ever moves away from DTM, their data layer can travel with them.

Does the site have jQuery? The jQuery library has many methods that help with CSS selectors (such as .parent, .child, .closest, .is, .closest…). A CSS-selector-based implementation may be more difficult without jQuery or a similar javascript library.

Who should create my Data Layer?

Ideally, your data layer should be created by your IT/developers… or at bare minimum, developers should be heavily involved. They may be able to hook into existing data in your CMS (for instance, if you use Adobe Experience Manager you can use the Context Hub as the basis for your data layer), or they may already have ideas for how they want to deploy. Your data layer should not be specific to just your Analytics solution; it should be seen as the basis of all things having to do with “data” on your site.

Yet frequently, for lack of IT investment, the analytics team will end up defining the data layer and dictating it to IT. These days, that’s what most Tech Specs consist of: instructions to developers on how to build a data layer. Usually, external documentation on data layers (like from consulting agencies) will be based on the W3C standard.

The W3C (with a task force including folks from Adobe, Ensighten, Microsoft, IBM…) has introduced a tool-agnostic data layer standard that can be used by many tools and vendors. The specifications for this can be found on the W3C site, and many resources exist already with examples. Adobe Consulting often proposes using the W3C as a starting point, if you don’t have any other plans. However, in my experience, generally that W3C is just a starting point. Some people don’t like the way the W3C is designed and most everyone needs to add on to it. For example, folks might ask:

  • why is “onsiteSearchTerms” part of Can I put it instead in something I made up, like
  • I want to track “planType”- the W3C didn’t plan for that, so can I just put it somewhere logical like digitalData.transaction?
  • I don’t need “digitalData.product” to be in an array- can I just make that a simple object.

The answer is: yes. You can tweak that standard to your heart’s delight. Just please, PLEASE, document it, and be aware that some tools will be built with the official standard in mind.

The Phased Approach

Many folks adopt a TMS specifically because they don’t want to have to go through IT release cycles to make changes to their implementation. You can still use a TMS to get a lot of what you need for reporting without a data layer and without a ton of CSS work. It may be worthwhile to put a “bare minimum” TMS deployment on your site to start getting the out of the box reports and any reports that don’t require a data layer (like something based on a plugin such as getTimeParting), then to fill in the data layer as you are able. I’d be wary though, because sometimes once that “bare minimum” reporting is in place, it can be easy to be complacent and lose some of the urgency behind getting a thorough solution implemented correctly from the start.


I fully understand that a properly designed data layer is a lot of work, but in my experience, there is going to be a lot of effort with or without a data layer- you can choose for that effort to be upfront in the planning and initial implementation, or you can plan on more longterm maintenance.

Should I have one DTM property, or many?

It’s common for a company in DTM to have multiple sites/groups/regions they want to deploy DTM on. One of the more important decisions you can make, early on, is whether to keep those different sites as separate properties, or keep them in a single DTM property. I know future iterations of the DTM tool will make up for some of the current issues we run up against when using multiple properties, but for now my advice is to keep as few properties as possible- it’s so much easier to maintain.

Note: Your properties in DTM are NOT related to your Adobe Analytics login companies or Report Suites- one property can go to many report suites (with custom logic in the s_code) or many properties can feed into the same report suite. So instead, you should consider the following:

How similar are the implementations?

Will the sites all have the same source for data, like a data layer, or CSS selectors? Do they use the same general analytics variable map (eg, “eVar15 is always search terms”)? Will they generally use the same third party tags? Do they all use Adobe Target or other DTM tools?

If your sites are similar and you want to keep separate properties, you can in theory set up one property and get it configured just right, then copy your rules and data elements over to all the other properties. But be warned: after rules are copied, if you need to update that rule, you must update all its copies too. To be honest, this can be beastly to maintain. I’ve seen it work, but only if folks use documentation to note what changes have happened where.
Imagine you want to add a new variable to your Search Results page, and you have 6 properties that have similar Search Results rules- you’d need to make that change in all 6 properties, and approve and publish in 6 places.
If, however, of your 6 sites, only 3 have a search results page, and all of them are pulling the search term out of a different query string parameter- then you’re going to be maintaining 6 separate rules anyways, and there is no benefit to keeping one property.

Another big consideration are the tools for each site. Tools in DTM are generally intended to be deployed on ALL pages using that DTM property- meaning you can’t turn on Target or the Marketing Cloud service for just one portion of a property. For Adobe Analytics, you can suppress the tool on certain pages, but in general, plan on Tools in DTM running on every page, without being able to suppress them for certain pages.

How similar are the publication timelines?

Will one site go live with the Analytics tool sooner than another? Does another site have a lengthy QA process?  Would it be ok to publish changes in DTM that will push out to all sites at once?

If Site B will have their old Analytics implementation removed from their site and ready for DTM to take over in June, and Site B won’t be ready until August, then you’d need to plan things very carefully in DTM. If the plan to transition to DTM really varies between your sites, then you may want to keep separate properties, at least for now. Perhaps in the future you could merge them back together.

Who will be doing the DTM work for each site?

Will the person implementing/administering DTM for one site be the same as for another site? Are you concerned about someone adding third party tags for site B having access to rules that could apply to site A? 

Within a company, you can use groups to restrict Users to certain properties. So you could say “Joe should only have access to Site B” if Site B is its own property.

Within a property, you can use groups to restrict Users to certain tools (for instance, you can give someone access to Third Party Tags but not to Adobe Analytics). You cannot, however, restrict certain rules- you can’t say “Joe can edit the homepage rule, but not purchase confirmation”.

On a side note, you can not restrict Admin access- if someone needs to make changes to tools, manage users, or view embed codes, that someone will have admin access for your whole company. So you can’t say “Joe should have access to the embed options for Site A but not Site B”.


If your sites are at all similar in their implementation, I think it’s worth it to try to make a single property work, but I definitely understand there are situations in which you must keep separate properties. Hopefully this post will help you decide on the best possible arrangement for your company.

What the DTM “top down” approach means for your page performance

Any javascript framework, including all Tag Management Systems like DTM, have the potential to ADD more javascript weight to your page. But if you approach things the right way, this javascript weight  and its effect on your page performance can by mitigated by using DTM to optimize how your tools and tags are delivered. In a partner post, I’ll be talking about how to get the most out of DTM as far as Third Party Tags go, but I think one key concept is worth discussing explicitly.
You may have heard DTM be referred to as a “Top Down” TMS. For instance, this appears in some of the marketing slide decks:

While yes, it’s worth discussing this as a holistic approach to your digital analytics, it actually has a very real effect on how you set your rules up and how that affects page performance. That’s what I hope to discuss in this post.

In a different TMS, or even in DTM if I haven’t changed my mindset yet, I may be tempted to do something like this:


Where I have differing rules for different scopes as well as for different tags (we’re pretending here that “Wuggly” is a Third Party Marketing Pixel vendor).

DTM does what it can to defer code or make it non-blocking, but there are parts of the DTM library which will run as syncronous code on all pages. Some of that is because of the way the code needs to work- the Marketing Cloud ID service must run before the other Adobe tools; older Target mbox code versions need to run syncronously at top of page. But there is also the code in the library that serves as a map for when and how all of the deferred code should run. For instance, my library may include the following:


All of this logic exists to say “if the current pageType is “home page”, run this code non-sequentially”.  The name, conditions and event code for each rule run on each page as part of the overall library- these serve as a map for DTM to know which code must run, and which code it can ignore and not run.
You’ll notice the code for the two rules is completely identical, except for the rule name (in blue) and the source of the external script (in yellow). Most importantly, the conditions (in green) are identical. Whereas if they shared a rule, we might see the exact same thing as above accomplished with half as much code:


I now have ONE rule, which would be used for ALL logic that should run on the Home Page. The part of the library that runs on every page to check against conditions only has to check if the “pageType” is “home page” once, rather than twice. And DTM still loads the two scripts as separate non-sequential javascript. This doesn’t look like a major change, but when viewed across a whole implementation, where there may be dozens of rules, it can make a big difference in how many rules and conditions DTM must check on every page.

In the DTM interface, this would look like this:

If I want to know which rules contain my “Wuggly” codes, I can use the  “Tag Name” filter in the rules list, which will show me all rules that have a third party tag that includes “Wuggly”:

This is filtering based on the Tag Name specified when you add the tag code:

Using this approach, where your rules are based on their scope (or condition) and contain all logic- Analytics, Target, third party- that applies to that scope can not only lighten your library weight, but it can also keep your DTM implementation organized and scalable, but it may also require a change of mindset for how DTM is organized- if someone else needed to deploy a tag on Product Detail Pages, they wouldn’t need to create a rule, but rather, they could see a “Product Detail Page” rule already exists with the scope they need, and they need only add the third party tag.

There is one potential downside to consider, though- the approval and publication flow is based on Rules in their entirety. You can’t say “publish my changes to the analytics portion of this tool, but not to the third party tag section”. Still, if you are aware of this as you plan the publication of new features, this potential drawback rarely overrides the advantages.

Get the most out of DTM for deploying Third Party Tracking

One of the benefits of using a tag management system like DTM is the ability to lighten the load on your page by moving tracking pixels into DTM. Now, simply moving code into DTM may not improve page performance- there are best practices you need to follow to get the most out of what DTM can offers.

1. Decide on the scope

When the DTM library loads, it defers as much code as possible to later in the page. In order to map out what should run where it must run through each of your rule conditions and see which conditions are currently met. That means that additional rules and additional conditions will actually slow down the synchronous part of your DTM library. When possible, don’t create a new rule for each new tag, but rather, have rules be specific to their condition. I have a partner post about how to improve page performance when planning out your rules, but for now, try to start thinking of your rules in terms of the user action- have one rule for when the user sees a product details page, for example, rather than a series of Product Details Page rules, each with a different tag.

2. Decide which type of DTM script to use

Since 3rd party Tag vendors generally deliver their code in HTML form, intended to be pasted directly into your page, there are usually a few changes you need to make before DTM can fire the code non-sequentially.  What you do varies by the tag.
Before proceeding, you need to decide: should you use non-sequential HTML or non-sequential javascript? DTM loads non-sequential HTML by setting it in a side <iframe> so it can load the content without blocking anything else. This can work well, but has some downsides: that iframe can’t get all the same information the parent page can. This includes many data elements- for security reasons, it can’t reference a data element that pulls from Custom JS or JS objects. If you’re referencing a data element, you need to use “%dataElementName%” rather than “_satellite.getVar(“dataElementName”)”. This isn’t the most supported usage, so definitely test it thoroughly.

3. Remove unneeded pieces

Next, remove any <noscript> tags: they won’t do any good in a Javascript-based framework like DTM. These days, these tags aren’t really needed and may actually inflate your data because the only folks who don’t have JavaScript enabled are bots.

4. Convert the code to suit your script type

Next, convert the code to the appropriate format (see below) and add it in a rule as a Third Party Tag.

Purely Script

Some tags are already just javascript. For instance, take this code from facebook:

<!-- Facebook Pixel Code -->

fbq('init', '123456789123');
fbq('track', 'PageView');

<img height=""1"" width=""1"" style=""display:none""

<!-- End Facebook Pixel Code -->

I would remove the <script> tags, the <noscript> portion, and HTML comments, and paste it directly as JavaScript:


fbq('init', '123456789123');
fbq('track', 'PageView');

I know Facebook and Chango are two tag types that fall in this category.

Simple Pixel

The easiest of pixels are those that just require the loading of a tiny invisible image. For instance, let’s say I got the following Yahoo dot code:

<img src="" height="0" >

If I want to load an image like this asynchronously, I could paste it in, unchanged, as a non-sequential HTML third party tag. As mentioned earlier, this would create an iframe that loads on the side of the page, so as to not slow down page performance.

I could also add it as a non-sequential javascript third party tag using document.body.appendChild to append it to the body, whether it has finished loading or not. This also makes it so you can add these pixels in event-based rules on SPAs or post-page-load user actions.

var dcIMG = document.createElement('img');
dcIMG.setAttribute('src', '');

To my knowledge, Yahoo Dot, Bing, Vibrant/Intellitxt, Gumgum are examples of simple pixel code vendors.

Pixel with query params

Some vendors have simple pixels, with query parameters in the src url that helps tell the vendor what they need to know. (Coincidentally, this approach is the approach used by Adobe Analytics.) Let’s say I got this code from Doubleclick:

<!--<script type="text/javascript">
var axel = Math.random() + "";
var a = axel * 10000000000000;
document.write('<iframe src="//;src=123456789;type=clientsale;qty=1;cost=[Revenue];ord=[OrderID]?" width="1" height="1" frameborder="0" style="display:none"></iframe>');

<iframe src="//;src=123456789;type=clientsale;qty=1;cost=[Revenue];ord=[OrderID]?" width="1" height="1" frameborder="0" style="display:none"></iframe>
<!-- End of DoubleClick Floodlight Tag: Please do not remove -->

I could add this to my site like this, using data elements in place of [Revenue] and [OrderID]:

var axel = Math.random() + "";
var a = axel * 10000000000000;

var dcIMG = document.createElement('iframe');

dcIMG.setAttribute('src', "//;src=123456789;type=clientsale;qty=1;cost="+ _satellite.getVar('purchase: revenue') +";ord="+ _satellite.getVar('purchase: order id') +"?");


Pixels with Script tags

Many vendors require you to add their javascript file to your site, as well as set some variables.

For instance, I might get this code from twitter:

<!-- Twitter single-event website tag code -->

<script src="//" type="text/javascript"></script>

<script type="text/javascript">twttr.conversion.trackPid('123456', { tw_sale_amount: 0, tw_order_quantity: 0 });</script>


<img height="1" width="1" style="display:none;" alt="" src="" />

<img height="1" width="1" style="display:none;" alt="" src="//" />


<!-- End Twitter single-event website tag code -->

So there is a script that needs to run, then script that needs to fire afterwards. We can remove the noscript portions, but we still need to figure out a way to get the .js script to run before I fire twitter.conversion. There aren’t a lot of options for running a .js file after a page has loaded- if you have jQuery, you can use $.ajax, but if you don’t have jQuery you can use the below to append the .js file, make sure it has completed, then run twttr.conversion:

var dcJS = document.createElement('SCRIPT');
var done = false;

dcJS.setAttribute('src', '//');

dcJS.onload = dcJS.onreadystatechange = function () {
     if(!done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete")) {
          done = true;
           // Handle memory leak in IE
           dcJS.onload = dcJS.onreadystatechange = null;
 function callback(){
                tw_sale_amount:_satellite.getVar('purchase: total revenue'), 
                tw_order_quantity:_satellite.getVar('purchase: total units') 

Google Adwords/Remarketing, Twitter, Linkedin, and Eloqua can all fit this general idea.

5. Validate the tag

There are many tools on the internet for validating tags are working. Some vendors, like Google, may have their own tool, but most tools can be validated either within a Developer Console or by using tool-agnostic tools like Ghostery or the chrome Observepoint plugin. Most methods require opening a developer console. An easy way to do this in most browsers is to right-click anywhere on the page and select the “Inspect” option. For instance, in Chrome:


First, check there are no errors in the console. Then, to validate a specific tag:

Using the Observepoint plugin: Within the developer console, go to the “Observepoint” tab:


Click the “Recording” button, then refresh the page. Observepoint should show every tracking technology running on the page, including the one you are validating.

Using the built-in tools in your browser: Open the network tab, then refresh the page. Often you can search for the name of the tag- for instance, here I’m searching for “twitter”, and it shows me that data was sent to twitter:


Other vendors use slightly more disguised names. Check with the vendor if you need more details on how to validate.

How do I use DTM for a Single Page App?

The question of how to use DTM on Single Page Apps (SPAs) is a VERY hot item right now. By Single Page App, I’m referring to a full user flow contained on a single web page, so as to provide the user a more seamless experience. Often, these pages act like typical web pages, but they don’t always change URLs or load new resources. Many common web development technologies, such as Angular.js, Ember.js, and AJAX use SPA principles.

Unfortunately, there isn’t a single great answer for how to deploy DTM- it depends on many things. I’ll work through some of the options and the limitations to be aware of.

Suppressing Page View Beacons

Whatever method you take for tracking page views in a SPA, keep in mind most SPAs do have one true “page view” when the DOM first loads. If you are going strictly with the DCR or EBR route, you may need to suppress the initial page view beacon the Analytics tool will want to set by default. Otherwise, in the example below where the developers are firing a direct call rule on all page views, you’d get TWO beacons on the first page and 1 on all subsequent pages.


Data Layer Considerations

You’ll need to make sure that whatever the sources of your Data Elements are (CSS selector, javascript objects, cookies…) have the correct values BEFORE your rule is triggered. I have an example site showing one way you might do this for a data layer (though you’ll need to look in the source code), but ultimately it’s going to depend on your site.

Variable Persistence

One last consideration is that once your Analytics object exists (as in, the “s” in “s.pageName”), variables set on it will continue to exist unless specifically overwritten. In most cases, you’d overwrite s.pageName with a new value so it isn’t a problem, but something like s.eVar5 may be set on the first beacon in your SPA, and not desired on subsequent beacons. You can use s.clearVars() to “refresh” your “s” object, but you have to make sure it fires at the right time- for example, after the beacon on Page A, but before DTM starts mapping Data Elements to variables for the beacon on Page B. How you do this will depend on the overall deployment method you choose.

Deployment Methods

1) Direct Call Rules

Perhaps the most straight-forward approach is to have developers fire a Direct Call Rule, like _satellite.track(“page view”) on every thing YOU consider a page view, whether it’s a fresh new DOM or not.

Advantages: Disadvantages: 
  • You have ultimate control over when a page view in considered a page view.
  • If you need to clear out variables between beacons (for instance, you set s.eVar5 in the first beacon in the SPA, and don’t want it in the second beacon), Direct Call Rules don’t provide a great place to use something like s.clearsVars(). There are some potential work-arounds, but none are ideal.
  • Developers need to add more DTM-specific code (satellite.track) to your pages.
  • Direct Call Rules don’t allow for extra conditions (like “fire THIS logic on pageA, and THAT logic on pageB”) in the interface.
  • Direct Call Rules don’t “stack”- if multiple rules have conditions that are met, multiple rules will fire.

2) pushState or hashChange

Many SPA frameworks, like Angular, use a certain flag to let the browser know the user is viewing a new “page”.


DTM can listen for this flag in an Event Based Rule using a pushState or hashChange condition.

  • No additional code is needed- most SPA frameworks are already firing something DTM can listen to
  • It’s an Event Based Rule, which allows you to fire clearVars(), and set extra conditions
  • Because you are listening for an event set by the framework, you have less control over timing. Updating a data layer BEFORE the “pushState” event is detected would be critical.
  • Event Based Rules don’t “stack”- if multiple rules have conditions that are met, multiple rules will fire.

3) Custom Event EBR

Another option, which feels a bit like a blend of the first two options, is to use a Custom Event-based Event Based Rule (and no, that’s not a typo- it’s an EBR based on the JavaScript Concept of a Custom Event). It’s possible Developers are already using this Custom Event concept for their own code and purposes, and DTM can just listen for it… or you can have developers set one specific to our DTM needs by using something like my digitalData.userAction hack.

  • You have a little more control over timing
  • It’s an Event Based Rule, which allows you to fire clearVars(), and set extra conditions
  • May require more developer work- similar level of effort as DCRs
  • Event Based Rules don’t “stack”- if multiple rules have conditions that are met, multiple rules will fire.

 4) (NEW OPTION!) “dataelementchanged” Event Based Rule

Just in the last few weeks, a new option emerged as part of the AEM Context Hub integration. This allows DTM to listen for changes to certain data elements- for instance, you could have a rule fire whenever the “pageName” has changed. My friends at 33 sticks have a great blog post about this already for more info.

  • You have a little more control over timing
  • It’s an Event Based Rule, which allows you to fire clearVars(), and set extra conditions
  • Requires careful consideration of when the data layer changes/loads
  • Event Based Rules don’t “stack”- if multiple rules have conditions that are met, multiple rules will fire.

Setting up an Event-based Rule that be fired directly like a Direct Call Rule

As proud as I am of this solution/workaround, it may be far less needed now that you can use the dataelementchanged  condition to fire an Event Based Rule. Instead of using custom events, you can just have DTM listen for when your pageName Data Element has changed. 

The current limitations

If developers want to fire a DTM rule directly from their code (say, they want to make sure a beacon fires only after their data layer is ready), typically they would fire a Direct Call Rule, with its very specific syntax: _satellite.track(“rule string here”). There are, however, some limitations to this method.

Direct Call Rules:

  • Don’t allow for multiple conditions (you can’t say “if _satellite.track(“cart add”) is fired AND the current page has “/products” in the URL“)
  • Don’t allow for multiple arguments (you can’t pass _satellite.track(“cart add”,”sku1″) to attach the added SKU to the rule)
  • Don’t allow for firing s.clearVars() before your rule sets up your analytics variables (to clear out variables from previous beacons on the same DOM).
  • Require very specific syntax- they MUST be “_satellite.track()”

And unfortunately, both Direct Call Rules and Event-based rules don’t “stack”- if a certain condition triggers multiple similar rules, each rule will fire its own beacon. This is different from Page Load Rules, where if multiple rules have conditions being met by the current page, they all wrap nicely into a single page view beacon.

An alternative

To get around some (but maybe not all) of these limitations, I’ve been playing with another possible option, where we use the Custom Event conditions of an Event Based Rule to accomplish nearly the same thing. After getting it set up, I can fire something like this:

digitalData.userAction("cart add","sku1")

…to fire an Event-Based Rule in place of a Direct Call Rule. There are a few things I need to do in DTM to make this digitalData.userAction work.

Set Up the Logic

First, I have to set up the logic in a Page Load Rule- set to fire on DOMReady (no need for it to be sooner)- that will merely hold the following as a Sequential Javascript Third Party Tag:

//make sure digitalData is defined to prevent errors
if(typeof digitalData=="undefined"){

//create fake DOM item to bind the event to
var fakeDiv = document.createElement('div');
fakeDiv.setAttribute('id', "dtmHolder");

//define custom event

 document.getElementById("dtmHolder").addEventListener("dtmEvent", function(e) {"Event is: ", e);

  // First create the event
  var dtmEvent = new CustomEvent(n, {

  // Trigger it!

(Update: note that this code should not run before the DOM is created- it will create an error if you try to run it at page top because you are trying to append something to a body that doesn’t exist yet).
Now, whenever a developer fires digitalData.userAction(“string here), you can listen for that string as the Triggered Event Type in a Custom Event Event Based Rule. Obviously, you can alter the above code if you want a function named something other than digitalData.userAction.

Set Up an Event Based Rule

The rule will need to be bound to the CSs selector of the tiny fake div (“#dtmHolder”) we created for the custom event to bind to:


You can create as many of these rules as you want, for whatever different strings you pass into digitalData.userAction()where the “triggered event type” reflects that string.

Pass Additional Info

If you want to pass a second argument ( e.g. digitalData.userAction(“cart add”,”sku1″)) I currently have that second argument  passing as a new attribute (“detail”) on the tiny invisible div, so you can access it off the “this” object directly in the rule:2016-04-20_12-41-52

You can give this a try at my ugly test site– open a developer console, turn on DTM debugging, and fire either digitalData.userAction(“cartAdd”,”sku123″) or digitalData.userAction(“pageView”) to see two example rules at work.

Run ClearVars

This opens the ability to run s.clearVars on s.t() beacons in cases where multiple beacons may be firing on a single DOM. (As a reminder, if you’re using the old DCR route, there are some hack-ish options for doing this- we call it daisy-chaining).

In an Event Based Rule, there IS a code block that runs before the Analytics tool, giving you a perfect opportunity to make sure you are starting with a ‘clean slate’ of variables: the Conditions Custom Code block. Just create a new Rule Condition with “custom” criteria, then put “s.clearVars()” in the code block, followed by “return true” (so that DTM doesn’t think some condition didn’t pass):


You can also apply additional conditions, like “only fire this “cart add” rule on certain pages”, by adding more criteria under Rule Conditions.


I’m very open to suggestions and feedback on this- maybe we can crowdsource a better way, but for now, this seems to be a reasonable alternative to Direct Call Rules. Let me know what you think!