DTM CustomEvent Rules

DTM can react to things that happen on pages, like when people click or something comes into view.

A relatively new feature is that it can also react to custom events (of the CustomEvent variety), and I want to show you how to make it do that.

I’d also like to add a slightly convoluted solution that perfectly fits what Wazowski would call “simple – yet insane!


The use case, in case your friendly marketer wants you to explain it, is that sometimes, things happen on your site that are not triggered by a click or an interaction, and that DTM needs to be able to detect those.

An online shop in Germany that I work with uses events because some of the information they track is not available at page load time. Instead, the page loads some product data asynchronously.

When the data has finished loading, the page triggers an event using jQuery’s trigger() method, which I guess is a common scenario. That event pretty much signals “all data is available now.”

Our challenge is that the usual “Bottom of Page” timing for Page Load Rules is likely (but not always!) going to be too early.

So how do we track that?

Yes, we can!

We can use an Event-based Rule, as I will show you. Alternatively, we could use custom code that is loaded in a Page Load Rule, but executed at a later stage (setTimeout, anyone?). I think using an Event-based Rule is the better solution. It allows your friendly marketer to work with the rule as she’d usually do, whereas with custom code, she’d have to come to you for changes.

So let’s make an Event-based Rule.

There are two things about this rule that set it apart:

  • The Conditions, and
  • the “Tracking” settings in the Analytics section.

Let’s start with the Conditions section.

Conditions on the Event-based Rule
I have selected “custom” as the “Event Type”, then invented a name “myCustomDelayedPageLoadEvent”. I have also specified “#content” in the “Element Type or Selector” field, because that field is where I will dispatch my event on. Note the little “[x] Apply event handler directly to element” tick box… for me that was a prerequisite, the rule wouldn’t fire without it.


What I have done so far: told the rule to fire when a CustomEvent called “myCustomDelayedPageLoadEvent” is detected.

Now let’s take a look at the “Analytics” section of the rule.

Analytics Section in Event-based Rule
This is a departure from normal best practice. Event-based rules are often used to track actions, and they almost invariably use s.tl() for that, precisely because it “does NOT increment a pageview”.

But in this case, the Event-based rule is tracking the page load for me, so I set it to use s.t() instead.

But Jan, you’ll say, won’t I have two page views then, every time the page loads?

Yes, you will. But I’ll show you how to suppress the original tracking that DTM wants to send on each page. We’ll get to that next week.

For now, all I want to say is that you can now treat the Event-based rule as your normal Page Load rule, with everything that means. Go ahead and fill in the analytics section, set “variables” to your hearts delight. Go and add custom scripting, if you feel the need to! Go and implement!

The Missing Piece

Something is missing, isn’t it?!

How does the Event-based rule ever fire?

Well, that’s your job. You have to put the code into your side that creates and dispatches the event. As simple as that. Think about it like adding code that calls Direct Call Rules, but more versatile.



If you want to test your rule, or just the firing mechanism, you can do so in the console.

var myev = new CustomEvent("myCustomDelayedPageLoadEvent"); 

This should do the trick.

The Final Frontier

Let’s take this further. On a site that asynchronously loads content or data on all pages, we can build a mechanism based on the above that sort of allows us to track almost normally.

Next week, I’ll post an article that will describe the end-to-end solution. I have split this up because otherwise this would have been awfully long, and because both articles would have been less clear.


A question? How is this better than just calling a Direct Call Rule? Well…

For once, you have separation of tools. The web site code fires events, it doesn’t call _satellite.track(). That in itself is worth it, if you ask me.

Secondly, you can have multiple rules trigger on a single event, doing such things as tracking a purchase with Analytics, affiliates, and other tools. The site developer has to fire the event, that’s all. What you do with it in DTM is your thing.

I would also venture that some sites do already use events, so all you have to do with DTM is “hook into them”. The alternative would be to ask your front-end developers to add _satellite.track() calls. Try see how much they like that…

Frankly, there is no need for Direct Call Rule usage outside other rules anymore, but I’ll get back to that.

A very, very long time ago, I read an interview in a German music magazine. The people behind The Art of Noise were describing how they got their hands on a Fairlight sampler, locked themselves into a studio, and subsequently spent a lot of time doing things with it that were not in the manual. I like that spirit, and I hope my colleagues in engineering, product management, and support forgive me for treating DTM the way I do.

28 thoughts on “DTM CustomEvent Rules

  1. Chapeau Jan! That’s what I need, but still wer’re not on DTM and since we cannot wait – and so also not eventbased – to fire the servercall until load is done, we have to use two calls on every page, uuhhh 😦


  2. 1) According to my current knowledge, CustomEvent is nit do well supported in older browsers.
    2) It looks like there isn’t any support for accessing custom data tied to that CustomEvent.

    So from this perspective I am not really sure about this feature.


    1. Good point.

      How old is Safari 5.1 (533.3)?

      IE supports it in 9+, FF since 6, Opera since 11.

      If your site has to support older browsers, you should either not do this, or test thoroughly.


  3. Found a small issue using CustomEvent rules and figured this is a good place to share…

    We have an application emitting multiple events (5 of them) off of the same html element (). In DTM I created 5 event based rules using the custom event as the trigger in the conditions section all pointing at body as the CSS Selector / HTML Element.

    When I open Chrome DevTools I see that only 1 of the five Event Listeners is actually attached to the element. The other 4 get attached to the document root.

    This seems like a bug in the way DTM deploys Event Listeners.

    To get around the issue, I created a page load rule and I add the 5 Event Listeners to the manually with custom javascript. Then in those listeners I call a DTM direct call rule specific for each so at least there’s a work around.

    I have a support ticket open with Adobe so hopefully this will get addresssed in a future release of DTM.


  4. Of course! It’s pretty easy to replicate if anyone’s interested in attempting it.

    1. Create 2 event based rules as follows:
    a. EventType = custom
    i. Triggered = customTrigger1 (for 1st rule) and customTrigger2 (for 2nd rule)
    b. Element Tag / Selector = body (for both rules)
    2. Inspect the body element using Chrome Developer Tools
    a. You should be able to see where the Event Listeners were added (1 to body and 1 to document).


  5. Has anyone found a way to attach these CustomEvents to document rather than to a specific DOM element? It would make much more sense to me.

    My tests give me really weird results.

    DTM in debug is able to tell me that it detects the CustomEvent on the document element (“SATELLITE: detected test on #document” where test is the name of my CustomEvent), but when I try to specify the Event Based Rule (Event Type: custom, for: test, Element tag: document), it won’t fire.


      1. Now I have to fire it on body instead and it doesn’t look cool, you know:

        document.getElementsByTagName(“body”)[0].dispatchEvent(new CustomEvent(event, data));

        This would look much cooler:

        document.dispatchEvent(new CustomEvent(event, data));


    1. Sadly, there’s no way to configure a DTM rule to watch for custom events being triggered on document. We (Adobe) are aware of it and agree that it should be supported. We plan on adding support for it in the future as priorities allow.


  6. Hopefully this helps someone in the future FWIW… One thing I struggled with is that the custom event was firing off if the body element before DTM was apparently ready or maybe even the DOM. I threw this conditional in and it worked 100% so far…

    var dtmEvent = new CustomEvent(action, data);

    var readyStateCheckInterval = setInterval(function() {
    if (_satellite && _satellite.domReadyFired) {
    }, 500);

    And in this case, it is safe for setInterval vs setTimeout because I’m clearing the interval once it passes so there are no possibilities of overlapping tasks.


  7. Hi Jan,

    I noticed in the article you state “Note the little “[x] Apply event handler directly to element” tick box… for me that was a prerequisite, the rule wouldn’t fire without it.”

    When that checkbox is unchecked, DTM will add event listeners to document which will catch events “bubbling up” from descendant elements. The reason why it wasn’t working without checking the checkbox is because, by default, custom events don’t bubble. The result is that the event handler on document doesn’t ever hear about the custom event being triggered on the descendant element.

    You can make the custom event bubble as follows:

    new CustomEvent(“myCustomDelayedPageLoadEvent”, { bubbles: true });

    Doing so should allow you to not have to check the “Apply event handler directly to element” checkbox.

    Thanks for the article BTW!


  8. Excellent Post.

    However, I am curious to find the element where the developer has dispatched the event!
    Is there a way to find that if I am not a front-end developer?



  9. Does anyone know if you can include an “OR” list of events in the “for triggered event type:” field? I’d like to trigger a delay for 10-15 events that can happen within a site we are tracking, and I don’t want to create 10-15 rules that are virtually identical. Thanks!


    1. Hi Kevin,

      No OR, no..

      I think the easiest way would probably be to write a listener that listens to those 10 – 15 events, then fires one event in turn. Payload on that one event would include the name of the original event.
      You can then write an EBR listening to the one event, which deducts the original event from the payload.

      Does that make sense?


Leave a Reply to Jan Exner Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

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