Approaches to implementing Adobe Analytics via AEP Web SDK and Adobe Launch

Steve Webb
Station10
Published in
9 min readNov 27, 2023

Introduction

Implementing Adobe Analytics via the new AEP Web SDK methodology presents a number of challenges and it isn’t entirely clear what best practice looks like. There are a few different ways to approach it in Adobe Launch, so I’m going to run through some of them here and hopefully give you some good ideas for how to handle your own implementation!

Mandatory DALL-E generated image

Some assumptions

This blog assumes that…

The examples in this blog also assume you’re sending the data to Adobe Analytics using the Adobe Analytics ExperienceEvent Schema (so that your data is automatically mapped to the old evars, props, etc, without having to worry about Processing Rules.) But a lot of this blog applies to tracking data in any Schema, and should still be useful for anyone sending data to the Edge Network, be it for Customer Journey Analytics, Real-Time CDP, or other products.

The basics

What we need to achieve in Adobe Launch is to map our data layer to the XDM Schema, and send off the right data at the right time.

Assuming you’ve already got a basic set of Data Elements defined that reference your data layer or other data points, the basic building block for this is the XDM Object data element. This allows us to map Data Elements to fields in the Schema:

Mapping ‘screen url’ to eVar2

You’ll notice that we’ve already hit our first oddity, in that we now have 2 levels of Data Elements:

  • One set that reference fields in our data layer. In the example above I’m using the Google Data Layer Extension to create data elements that reference fields in the dataLayer object.
  • A second set that maps those fields to the XDM Schema. In the example above I’m mapping screen.screenURL from my data layer to eVar1 in the Schema.
Data Elements into Data Elements

This is still pretty simple though; we have our XDM object with some info about the page, which we can then send off in a Rule.

Sending our XDM Data Element off to the Edge network

This is slightly different to what you might be used to if you’re familiar with implementing Analytics using the Analytics extension: Previously you’d map your data elements to evars and props in a Rule action, whereas now you build your XDM object in a Data Element and then all you do is send off that one Data Element.

The problem with Metrics

So far this seems relatively straightforward, but things get a little more complicated when we have to start setting metrics in the Schema.

Setting the Page Views metric

We need to set web.webPageDetails.pageViews.value to ‘1’ for Analytics to treat this event as a page view (the equivalent of a legacy s.t() call). But that means I now can’t use this XDM Data Element for any other non-page view events.

Say, I’ve also got a ‘CTA Click’ event. I don’t want to set pageViews.value to ‘1’ in this scenario. And I might want to set some custom event like event1 as well. To track this properly, I need to set both _experience.analytics.event1to100.event1.value to ‘1’ and ensure that the web.webInteractions.linkClicks.value and type are set correctly.

Setting event1
Making sure Adobe treats this as a ‘custom link’ event rather than a ‘page view’ event

So now, because we need separate XDM Object Data Elements for different events, do we need one XDM Object per event? Well probably…

Suddenly we have a lot of XDM Data Elements

There are a few things we can do though, so that this doesn’t get too unwieldy.

The ‘Merge Object’ Data Element

In many implementations, there are some data points that you want to set on every event, regardless of what it is. Things like URL info, customer IDs or maybe technical details like the Launch library build date. Setting all of those in every XDM data element is a lot of repeated work and is susceptible to mistakes.

There is a way around this with the ‘Merged Objects’ Data Element type, provided by the Core extension. This takes in multiple JSON objects and merges them into a single object. And since the XDM objects are just JSON under the hood, we can use this to merge them together.

So, instead of having to set the same things all over the place, one solution is to:

  • Create a ‘global’ XDM Object that contains all the dimensions that we want to set on every event.
  • Create individual XDM objects for individual events, with the relevant dimensions and metrics set.
  • Merge them together before sending them off to Adobe.
The Merge Objects data element

Now, I’m not super happy with this solution… while it does reduce the amount of repeated work, we also end up with another layer of Data Elements.

Turtles all the way down

The new Update Variable rule action

Adobe recently added a new Variable data element and Update Variable action to the AEP Web SDK extension. To me, this is a little frustrating because it has a lot of potential but I think it’s poorly implemented (actually see edit below, changed my mind.)

This takes us back to the old Adobe Analytics extension days where we map data to dimensions in the Actions rather than the Data Elements. Firstly we create a ‘Variable’ data element, which is just a reference to a Schema.

A ‘Variable’ Data Element

Then in our actions, we can update this ‘Variable’ before sending it to off to Adobe.

This seems like a good approach, except for the fact you have to start with a blank schema every time. So while it removes the need for layers of Data Elements, we do still end up setting a lot of the same dimensions repeatedly.

I think this could be improved a lot if we could start with an existing XDM Data Element and update that, rather than starting from scratch every time. I wrote a lengthy post on the Experience League Community with suggested improvements if you want to check it out and give it a thumbs up!

Edit 04/12/2023: As you might see from that Experience League thread, it was pointed out that you can actually provide an XDM data element at the root of the ‘Update variable’ action. So you can effectively start off with an existing XDM object and update that, which is very useful.

Providing an entire XDM object at the root of an ‘Update Variable’ action

Custom Code

One final option that requires a bit more skill with JavaScript but solves a lot of these issues, is to just do a lot of the work in custom code. Normally I try to avoid too much custom code in my Launch implementations because it makes them less transparent and harder to maintain, but I think it makes sense here given the lack of better solutions.

One of the things we can do in the XDM Data Element fields is to just ‘provide entire object’. This means we can use a Custom Code Data Element here to provide chunks of the Schema, so long as it returns a JSON object in the correct format.

An area where custom code makes a lot of sense is for tracking ecommerce dimensions and events. It’s likely you’ll need to write custom code anyway to transform your data layer into the right format for the productListItems object, so we might as well make good use of it.

As an example, here’s some script that converts a standard GA4 ecommerce.items data layer object into the right format for the XDM Schema and sets some additional merchandised eVars:

function convertEcommerceItems(eventModel) {
const ecommerce = eventModel.ecommerce;

if (!ecommerce || !ecommerce.items) return [];

return ecommerce.items.map(item => {
let quantity = item.quantity
let productDetails = {
SKU: item.item_id,
productCategories: [{ categoryID: item.item_category }],
quantity: quantity,
priceTotal: item.price * quantity,
_experience: {
analytics: {
customDimensions: {
eVars: {
eVar20: item.item_name, // merchandised evar
eVar21: item.item_brand, // merchandised evar
}
}
}
}
};

return productDetails;
});
}

return convertEcommerceItems(event.event.eventModel);

This script makes use of the event.event.eventModel object that’s provided by the Google Data Layer Extension, and is one that we can reuse across different e-commerce events.

Likewise, we can also use custom code to set our events. Again, this is particularly useful in e-commerce scenarios to set the XDM commerce object, with all the default fields that get mapped to the old Analytics e-commerce events.

function produceCommerceObject(eventModel) {
const eventType = eventModel.event;
const ecommerce = eventModel.ecommerce;

if (eventType === 'view_item' || eventType === 'view_item_list') {
return { productViews: { value: 1 } }; // Increments the Product Views metric

} else if (eventType === 'remove_from_cart') {
return { productListRemovals: { value: 1 } }; // Increments the Basket Removals metric

} else if (eventType === 'add_to_cart') {
return { productListAdds: { value: 1 } }; // Increments the Basket Adds metric

} else if (eventType === 'view_cart') {
return { productListViews: { value: 1 } }; // Increments the Basket Views metric

} else if (eventType === 'begin_checkout') {
return { checkouts: { value: 1 } }; // Increments the Checkouts metric

} else if (eventType === 'purchase') {
return {
purchases: { value: 1 }, // Increments the Orders metric.
order: {
currencyCode: ecommerce.currency, // Sets the currencyCode variable
purchaseID: ecommerce.transaction_id, // Sets the purchaseID variable
}
};

} else {
return {}; // default return if event type doesn't match any known types
}
}

return produceCommerceObject(event.event.eventModel);

Again, this script makes use of the event.event.eventModel object and maps the standard GA4 e-commerce data layer events to Adobe’s Analytics Schema.

Taking this approach can reduce the number of XDM Data Elements that we need, as the custom code can handle setting the right events depending on which dataLayer event triggered the Rule.

Wrapping Up

To be honest I’m not entirely happy with any of these approaches, they all have slight drawbacks and none of them are as neat as I’d like. Am I over-complicating this and is there a simpler approach that I’ve missed? I’m not sure there is, but let me know if you disagree!

Either way, hopefully, this has been useful to outline some different techniques that you can put to good use in your own implementations.

Station10 believe in open source and sharing knowledge and our Medium content is never paywalled, so please leave a clap if you’ve found this useful. This helps motivate us to write more content and gives us a better idea of what to write more about.

--

--