Building the ultimate auto tracking implementation with Adobe Experience Platform and Web SDK

I think it’s no secret that a lot of companies, agencies, and analyst dread the amount of effort it takes to implement a sophisticated analytics tool like Adobe Analytics. That may come in part from the correlation between company size (and thereby business complexity) and choice of analytics tool, but it is quite clear that implementing Adobe Analytics in a way that fully utilizes both all of its countless features and what can be collected from a page is a challenge to even the most experienced specialists.

This is where other tools like Google Analytics or smaller solutions like Matomo have their place. If your use case and business situation are right, they may be a quicker solution for you. The simplicity is quite tempting but would not be enough for larger businesses. That leads to a funny situation when people from agencies or small companies join a large corporate and take that notion of “Why is this so complicated? There must be a simpler way. Why don’t we just use Google?” with them.

One thing that especially smaller tools offer is autotagging. Their promise is quite simple: “Just drop our script on your page and you’re done! We’ll track any page view, link click, content interaction, page scrolling, or bowel movement of your users automatically! No tag management or data layer needed!” They usually try to achieve this by listening to a lot of events and scraping the DOM to gather information about the page. As a result, you will get a lot of useless interactions and meaningless event descriptions in those tools, since they try to infer from technical identifiers to human-understandable event names.

A few discussions on Twitter and the Measure Chat made me think if something similar would be possible (whether maybe not sensible) with the Adobe stack. And while Adobe Analytics would require too much setup, I couldn’t stop thinking if this was possible with my new 2nd favorite set of toys, Adobe’s Experience Platform, Query Service, and Customer Journey Analytics. This led to a little side project and some cool findings that I want to tell you about today.

Setup: Tracking without Adobe Analytics

This headline almost makes me shudder. To circumvent some of the shortcomings of Adobe Analytics (amount of up-front setup, variable limitations, data processing, etc.) we will not use Adobe Analytics at all! Instead we are going to use the new Web SDK (also called Alloy) to write data directly to an Experience Platform dataset! That gives us all the flexibility we want in terms of what can be included in the data.

So first, let’s create that dataset! But before we can do that, we need to define the schema we want to use. A schema is basically what defines which dimensions and metrics are available in the associated datasets. We are going to use one of the unique features of those schemas: They can be extended later, even if they are already used in a dataset, which is a feature we are going to use a lot! We start with an empty ExperienceEvent schema and add the AEP Web SDK Mixin:

Creating our base schema

From that simple schema, we now create a dataset to actually hold our data. I named mine “Autotagging Dataset” (I hope you see why I could never work in marketing).

Next, we need to tell Adobe Launch to push our data from the frontend to that AEP dataset. Just as last time, we head to the Edge Configuration and enter our dataset there under the Adobe Experience Platform section:

Telling Launch where to push our data to

In our Launch property, we use this Edge configuration in the Web SDK extension. Now all we need to add is the XDM Data Element that will hold all the details about our users’ interactions. Once we select our AEP XDM schema, it will show all the fields that Launch and Alloy will auto-populate for us with a little asterisk:

With the Web SDK mixin, a lot of fields are auto-populated!

That’s all the setup we need! Compared to the effort of configuring Report Suites in Adobe Analytics, this was super easy to do. But we are not collecting any data yet, so let’s configure some rules!

Tracking basic page loads

First, we want to know which pages are loaded, right? This is super easy to do: Just add a rule, have it fire on Library Load, and configure a Web SDK action to send an event like this:

Sending a page load event

This rule will now fire every time our page loads and track the data to AEP. If we wanted, we could also make this rule fire on History Change to include Single Page Applications as well. With this little effort, we already have a few things happening in our browser’s network tab:

Network traffic

Our page loads, then Launch gets loaded and we immediately send our tracking request. Once we take a look at this request, we can see all the work that Launch and Alloy have done for us:

Auto-populated variables

That’s quite a lot! From this information alone, we could already tell how often a URL was loaded, what the referrer was, where the user was located, and which browser config was used. If we head over to Platform again, we can take a look at the data we just collected. Just go to your dataset and click the Preview Dataset button:

Viewing our data in Experience Platform

And there it is! For a few minutes of setup, this is quite an amazing result! With this basic data collected, we could easily process some more information with Query Service and visualize the result in Customer Journey Analytics. But what about click interactions on that page?

Tracking every single click

In Launch, it is quite easy to create a rule that listens for each and every click on a page. All we need is the Core – Click event without any element restrictions like this:

This will give us a firework of events, since each and every click (even on the plain white space on a page) will trigger the rule. As action, we can simply use the same Web SDK Send Event as shown above. But there is one small issue: The event does not contain any information about the content which has been clicked. How can we get that?

Let’s have a look at what information Launch is giving us together with those click events. As we know from before, Launch has a lot of details about which event happened in the event variable. For demo purposes, I added a quick console.log(event) to our rule above, which prints something like this:

Click event information in Launch

There is plenty of information there! We already knew about the $rule and $type elements from a previous post. But the element property looks really interesting, as it contains exactly the element that has been clicked! We can then work our way from that element trough the DOM. I found a nice thread on Stackoverflow that shows how we can iterate through the DOM, so I will spare you the additional explainations. Instead, here is just the code that I used:

var el = event.element;  
 var stack = [];
   while ( el.parentNode != null ) {
     var sibCount = 0;
     var sibIndex = 0;
     for ( var i = 0; i < el.parentNode.childNodes.length; i++ ) {       
          var sib = el.parentNode.childNodes[i];       
          if ( sib.nodeName == el.nodeName ) {         
              if ( sib === el ) {           
                   sibIndex = sibCount;
              }
         sibCount++;
       }
     }
     if ( el.hasAttribute('id') && el.id != '' ) {
       stack.unshift(el.nodeName.toLowerCase() + ': ' + el.id);
     } else if ( sibCount > 1 ) {
       stack.unshift(el.nodeName.toLowerCase() + ' ' + (sibIndex + 1));
     } else {
       stack.unshift(el.nodeName.toLowerCase());
     }
     el = el.parentNode;
   }
 return stack.join(' > ');

Notice how in the first line, I take the event element from Launch and take it’s element property. Now all we need is a Data Element with the above code and the event element itself. For the latter, we just need two Data Element that contain a bit of custom code, which is just “return event.$rule” and “return event.$type” for now.

Before we can capture those in Launch, we need to create the respective nodes in our AEP XDM schema. For this use cases, I quickly created a custom mixin that holds the Launch event details:

Custom AEP XDM mixin for Launch events

Thanks to the beauty of Launch, we can then just populate those variables from our Data Elements. Once we put those there, they show up in our data quite nicely:

Mapping the AEP XDM schema to Launch variables.

And there we have it! With this implementation we would already be able to somewhat tell which element a user clicked! With Query Service and CJA, we could further process this data retroactively and add calculated metrics and dimensions, even after we measured it. In AEP, the data now shows up like this:

Our events in AEP

With a setup like this, we could just throw our Launch tag on any page and would immediately be able to track page loads and every click on the page. We don’t need any data layer or other implementation to collect events. With retroactive processing and reporting, we would need to put in some effort to make the data understandable and actionable, but it would be very possible to do. Even things like multiple languages could be covered and aggregated this way!

The post you are reading could end here and all would be good. But while I was working on this, I had another thought: What if we had a data layer on the page already? What would be the easiest way to use that? At the end of the day, almost every page should have one, right? So…

Why not track the whole data layer?

If we have data in our data layer already, we should use it. For simplicity’s sake I just added the Adobe Client Data Layer extension to my Launch property. The Adobe data layer supports a few events to listen to, but we are going to create two rules, for Data Changes and all Events:

Listening to Adobe Client Data Layer events

To get all data in the data layer, we can just create a Data Element containing the computed state:

Getting the computed state of the Adobe Client Data Layer

And if we listen to the “All Events” condition, we have access to quite a few data points on every non-event datalayer.push:

Available data from the Adobe Client Data Layer extension

For this, let’s create a custom code Data Element for the event object, following this syntax:

Returning the data layer event

The structure of our data layer will be quite simple for this example and follow the W3C CEDDL convention. For our demo, my data layer will receive one data push and one event:

Our demo data layer interactions

Before we can now add this data to our XDM in Launch, we first need to add it to the actual XDM schema in Platform. I use another mixin for this. Notice how I capture everything, from the computed state, to the before-, after-, and full state and message:

Data layer schema

In Launch, we can then assign the data layer state to the schema with just one Data Element and do the same for the event object:

Assigning the data layer to XDM

Now in the frontend, we can see how the data layer is pushed into the XDM:

Data layer in our XDM object

For example, with the second dataLayer.push above, I set the component list. That means it is included in the after state but not the before state:

Capturing data layer changes

Since we have this all of this information on the same row of data in AEP now, we could easily build calculated metrics or segments in CJA based on when a certain value in the data layer changes, which is very interesting! By modeling our whole data layer in XDM, we can retroactively figure out which interactions are meaningful and have the complete context of every event ready. If we extend the data layer in the future, we just need to extend the XDM mixin, but don’t need to touch our implementation or processing. Very neat!

Conclusion

While this post started out more or less as a joke, the last part got me really excited. While it may be debatable if it makes sense to capture each and every click on a page (which could easily be limited to just links, buttons, etc.), including the whole data layer with every event might be a real keeper. Maybe we could even pair the dataLayer.push events with an event merge ID in the future to retroactively stitch all pushed events to one event in AEP. The possibilities are endless!

What we definitely succeeded on is deploying the architecture that we were going for: Capture every interaction and as much context as possible to later crunch the data with Query Service and Customer Journey Analytics. And since we have this all in one Launch property without external dependencies (except maybe the data layer type) we would be able to throw this single line of code on any website and capture user behavior without any issues!

While there might be come work needed to make this ready for prime time (no, not the Adobe product), it’s a nice result for the small afternoon project that it was. I’m can’t wait to hear your thoughts on this topic!