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

Update:
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"){
  digitalData={}
}

//create fake DOM item to bind the event to
var fakeDiv = document.createElement('div');
fakeDiv.setAttribute('id', "dtmHolder");
fakeDiv.setAttribute('height','1');
fakeDiv.setAttribute('width','1');
fakeDiv.setAttribute('style','display:none');
document.body.appendChild(fakeDiv);

//define custom event
digitalData.userAction=function(n,details){

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

  // First create the event
  var dtmEvent = new CustomEvent(n, {
    detail:""
  });

  jQuery("#dtmHolder").attr("detail",details)
  
  // Trigger it!
  document.getElementById("dtmHolder").dispatchEvent(dtmEvent); 
}

(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:

2016-04-20_12-38-12

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):

2016-04-20_12-52-49

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

Conclusion

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!

4 thoughts on “Setting up an Event-based Rule that be fired directly like a Direct Call Rule”

  1. Great article… food for thought.

    I’m in the middle of a digital data layer – DTM – Analytics project, and investigating on 3 different methods for triggering the events. The philosophy behind the project is to have the application (web site) generate digital data and events and to decide in DTM whether the events will be passed to Analytics; on top I want to minimize javascript coding in DTM.

    The three methods:

    1. use _satellite.track DCR’s
    2. use CustomEvent in the web site to generate an event, and use an EBR with ‘custom’ Event Type to trigger the rule.
    3. put an ‘eventAction’ field in de data layer and use dataelementchanged in an EBR to trigger the rule.

    I have multiple beacons on the page, which might be of the same type, and they can fire fast after each other.

    The first option seems to be the less interesting, since you can’t put additional conditions on the firing rule, which makes it unsuitable for the ‘decision in DTM’ premise.

    The second and third option seem to work pretty well in testing, but leaves me with a race condition question. I’m retrieving the extra parameter fields for the events through my digital data layer object which is mapped on Data Elements in DTM. This seems to work fine; I don’t see wrong mappings (e.g. second beacon is overwriting data from first beacon), but I’m wondering if I’m just lucky.

    Does anyone has experience with the timing of firing rules and reading Data Elements?
    In the second option, you have the advantage of being able to pass data through the event object. Is there a way to read this data directly from the event in DTM? (the option in this article with putting the event data on an attribute of the listener tag would introduce race issues when firing beacons of the same type, unless you would make this attribute unique in some way…).

    Stefan

    Reply
    • Thanks for the wonderful comment! You basically summed it up REALLY well- from the available options and the drawbacks of DCRS, to the concerns about using EBRs… not sure I have too much more to add. For me, I think the biggest difference between the two Event Based rule options is- would you ever want to track the same eventAction twice in a row? Because it won’t count as a data element changed if your eventAction goes from “link clicked” to “link clicked”. Whereas it could count two custom events that happen with the same value twice in a row. Aside from that, I think if you are careful about timing, either option can work.

      Reply
      • Hi,

        I have the use case where e.g. different promotion blocks are on the site, and their ‘user view’ event should be tracked. For products most analytics have the notion of lists, so you can pack multiple products viewed within one event. However in our approach, the promotion block just acts as a widget on the site, and fires it’s own ‘view’ event, and we can have multiple of these promotion widgets on one page. So actually I’m firing multiple events of the same type, but with different parameter settings: each widget instance has a unique ID – and this is passed through the digital data layer to the Data Element.
        That’s why I’m so much concerned about timing between event call and reading the parameters from the Data Elements.

        Stefan

        Reply

Leave a Comment