Pushing multiple data simultaneously into Adobe Client Data Layer can cause its computed state to return data that you don't expect. Overcome this problem in Tags (Launch) with Direct Calls.
Preface / Background
Adobe Client Data Layer, commonly referred to by its abbreviation "ACDL", is an event-driven data layer developed by Adobe. This article assumes that you are already familiar with ACDL and know how it works, or even how to use it. Otherwise, learn more about ACDL from its wiki.
Like any event-driven data layer, ACDL's implementation is very simple: instantiate its array, then push a data object into that array, like so:
// instantiate ACDL
window.adobeDataLayer = window.adobeDataLayer || [];
// push data into ACDL
window.adobeDataLayer.push({
event: "my event",
foo: "bar"
});
After that, you can retrieve the pushed data from ACDL's computed data layer state. When using Tags (or Launch, as it is more commonly known), then you can use the Adobe Client Data Layer extension's Data Layer Computed State data element to retrieve data from ACDL. This workflow is illustrated as follows:

This is all well and good, and works perfectly for almost all use cases.
Problem: simultaneous / consecutive ACDL pushes messes up the computed data layer state
Sometimes, you may be pushing data into ACDL simultaneously or consecutively. That is, you have more-than-one adobeDataLayer.push() statements in your implementation back-to-back, with the intention that each push triggers the appropriate Rule and action in Tags.
// instantiate ACDL
window.adobeDataLayer = window.adobeDataLayer || [];
// push the first data object
window.adobeDataLayer.push({
event: "my first push",
foo: "bar"
});
// push the second data object
window.adobeDataLayer.push({
event: "my second push",
foo: "stamp"
});
// expected result from first push: "foo" computed data layer state to be "bar".
// expected result from second push: "foo" computed data layer state to be "stamp".
But when you test your implementation, you would almost always end up with incorrect computed data layer states when processing your earlier pushes. I.e.:
// instantiate ACDL
window.adobeDataLayer = window.adobeDataLayer || [];
// push the first data object
window.adobeDataLayer.push({
event: "my first push",
foo: "bar"
});
// push the second data object
window.adobeDataLayer.push({
event: "my second push",
foo: "stamp"
});
// expected result from first push: "foo" computed data layer state to be "bar".
// expected result from second push: "foo" computed data layer state to be "stamp".
// actual result from first push: "foo" computed data layer state to be "stamp". -- WRONG!
// actual result from second push: "foo" computed data layer state to be "stamp".
Here is what happened: While Tags was working on the first push, the second push had already caused ACDL's computed data layer state to be overwritten with its data. As a result, Tags got the second push's data when it was still handling the first push. This is illustrated as follows:

This is classic engineering problem: a "race condition". In this case, Tags is racing to process the first push, but ACDL has already started -- and finished -- handling the second push. It happens because the web browser needs time to execute code, causing unexpected processing delays.
But this is not really a problem with either ACDL or Tags. In a way, ACDL should not have to deal with this "race condtion" problem. Its job is compile data from several pushes into an easily retrievable data layer state. It should not have to "care" if an event has been processed completely before moving on to the next one. Likewise, Tags should not need to handle complications with delays and races, because it is designed to simply listen for triggering events and run the appropriate actions.
But this is a problem for you, the analyst, because it results in incorrect reporting of data, which can lead to incorrect insights. So this is a problem that you need to solve.
Solution: use a Direct Call that has the computed data layer state for each corresponding ACDL push
There are 2 key considerations in designing the solution:
- Minimise execution time as much as possible. This is because you need to ensure that you are retrieving data from the expected copy of the computed data layer state with each event, before that computed state gets overwritten.
- Work with a fixed computed data layer state each time. This is because you want to work with the expected computed data layer state for each event, rather than having to guess each time if you are, indeed, getting the expected state.
The best solution that I've come with is as follows:
- Set the Adobe Client Data Layer extension's Data Pushed event to be of order 1. This ensures that the Rule gets triggered before any other Data Pushed events.
- Use an undocumented feature in the Adobe Client Data Layer extension to get the computed data layer state with each push. This is described further below.
- Trigger a Direct Call with each ACDL push, including the ACDL event and computed data layer state in the Direct Call's payload.
Here's the information about the undocumented feature. First, this assumes that you are already aware that, when an Rule's event is triggered in Tags, then that Rule event almost always returns a custom event object that contains custom data that is contextual to the triggered Rule event. For example, when a Click event is triggered, that Click event returns an event object that contains a reference to the clicked DOM element in its event.element path. Learn more about this in the help documentation (although the content is quite technical to read).
With the Adobe Client Data Layer extension, when the Data Pushed event gets triggered, it returns a custom event object. This object has 2 fields that are useful for the solution:
- event.message: This contains the data that was pushed into ACDL that caused this trigger. I.e., it is the same data object that was used in adobeDataLayer.push().
- event.fullState: This contains the ACDL computed data layer state at that moment.
With this in mind, the ACDL computed data layer state and its triggering event can be obtained. My solution includes these 2 items in a Direct Call's detail. Then, I have other Rules in Tags that get triggered by this Direct Call to perform the actual tracking of data. Since the Direct Call detail's data never gets affected by subsequent ACDL pushes, I can be very confident that my tracked data that is read from the Direct Call detail's data will always be what I have expected for a particular ACDL push.
This workflow solution is illustrated as follows:

Example setup in Tags
Here's an example Rule that is triggered by a ACDL push to trigger the Direct Call:
Rule Setup:

Rule event setup:

Rule conditions setup:


Rule action:

And here's an example Rule that gets triggered by the Direct Call, where i want to handle the "my first push" ACDL event only:
Rule setup:

Rule event setup:

Rule condition setup:

Rule action setup:

_satellite.logger.log(event.detail.state);
To get the individual items from the computed data layer state, I would then use a dot-notation path to get that item from the Direct Call detail's data. For example, if I have this implementation:
window.adobeDataLayer.push({
event: "my first push",
foo: "bar"
});
Then, the Direct Call detail object would be like this:
{
event: "my first push",
state: {
foo: "bar"
}
}
Then I could use event.detail.state.foo to get the value "bar".
Solved: handling simultaneous ACDL pushes
With this entire setup, I would then be able to handle simultaneous ACDL pushes properly using Direct Calls, as illustrated below:

That is, each ACDL push results in a unique Direct Call, which has the computed data layer state that is fixed for that particular push.
Summary
Simultaneous or consecutive pushes into Adobe Client Data Layer are very likely to happen in a lot of implementations, whether by intention or not. Regardless, we need to ensure that the resuting reported data is what we expect from our implementations. To handle simultaneous / consecutive ACDL pushes:
- Get the ACDL computed data layer state using an undocumented feature from the Adobe Client Data Layer extension's Data Pushed event.
- Use a Direct Call to have a fixed and expected computed data layer state.
- Perform all tracking with that Direct Call.
I hope this solution helps you with handling simultaneous or consecutive ACDL pushes. Do you have any comments or questions about this solution? Please post them here and I'll try my best to answer them satisfactorily.
---
Yuhui
https://yuhui.sg
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.