perpetua.digital
Published on

Adding click tracking to shadow DOM web components with Adobe Tags/Launch

Authors

The good ole DOM

The DOM used to be a reliable place. Every element on you page could be found within it. Those days are fading, or at least becoming trickier thanks to modern web components and their concept of a shadow DOM. Not to be confused with the shadow realm. Web components are useful, but present a problem for tag managers like Launch that rely on the regular DOM to trigger rules. Lets take a look at a web component that exists in a shadow dom:

red and blue button

The red button is a regular element, and the blue button is a web component that is encapsulated in the shadow dom.

shadow dom html

"shadow root (open)" signifies that this element is a web component that lives in the shadow dom. It cannot be accessed via regular document.querySelector

Here is the code for the page above. The blue button is a custom defined HTML element known as a web component

<!DOCTYPE html>
<html>
  <head>
    <title>Buttons</title>
    <style>
      .button {
        width: 200px;
        height: 200px;
        border: none;
        color: white;
        font-size: 16px;
        font-weight: bold;
        text-align: center;
        line-height: 100px;
        cursor: pointer;
        margin: 10px;
      }

      .regular {
        background-color: red;
      }
    </style>
  </head>
  <body>
    <button id="redButton" class="button regular">Regular DOM Element</button>

    <script>
      // This is a web component
      class ShadowButton extends HTMLElement {
        constructor() {
          super()
          const shadow = this.attachShadow({ mode: 'open' })

          const button = document.createElement('button')
          button.setAttribute('id', 'blueButton')
          button.setAttribute('class', 'button shadow')
          button.setAttribute(
            'style',
            'width: 200px; height: 200px; border: none; color: white; font-size: 16px; font-weight: bold; text-align: center; line-height: 100px; cursor: pointer; margin: 10px;background-color:blue'
          )
          button.textContent = 'Shadow DOM Element'

          shadow.appendChild(button)
        }
      }

      // Register the web component
      customElements.define('shadow-button', ShadowButton)
    </script>

    <shadow-button class="button shadow"></shadow-button>
  </body>
</html>

Everything renders and looks normal, but the issue occurs when you try to select these elements from the DOM.

shadow dom null

The blue shadow dom button cannot be found...

Where does this cause problems in Launch?

I usually run across this issue when trying to add click tracking to these web components. Just adding a regular Launch click trigger to a rule doesn't work. For example:

blue button rule

Web component

red button rule

Regular element

button rule gifs

The blue button rule, she no work :(

Workarounds

So there isn't really an out of the box solution for this in Launch. Maybe someone should make an extension 🤔 Anyway, I really only see 2 options:

  • Build a direct call event or datalayer push into the code that builds the web component
  • Write custom code in Launch that reaches into the shadow root and adds direct call/datalayer push on the click event

Integrating into the web component

Although web components are special as mentioned above, they are still just regular HTML & JS, and thus, can have event listeners added to them. Because of this, you can bake a direct call or data layer push event right into an event listener. If I wanted to track clicks on the blue button for example:

// ...
button.addEventListener('click', () =>
  _satellite.track('shadow element click!!!', { extra: 'data' })
)
shadow.appendChild(button)

direct call rule

I didn't set up a direct call rule, but you get the point, it works

or

// ...
button.addEventListener('click', () =>
  datalayer.push({ event: 'shadow element click', extra: 'data' })
)
shadow.appendChild(button)

data layer push

I don't have a data layer extension setup on this fake site, but again, you see where I am going with this

Adding your own event listeners via custom code

This option is less than ideal given that you need to manually traverse into the shadow dom with specific selectors, but nevertheless, it works. In my rule, I'm waiting for the <shadow-button> element to exist, then reaching into it and adding my own event listener to the #blueButton web component.

shadow element exists

Launch rule that fires when the element containing the web component exists

shadow button custom code

Manually adding an event listener to a web component with custom code

shadow custom code gif

Click events tracking is now possible.

Wrap up

So that is how you can add tracking to a web component element in the shadow dom. In this case, I added click tracking via event listeners, but if you should be able to write any kind of activity tracking needed provided you do it in custom code. If anyone has a better way to do this, please reach out!