Skip to content

Configurable Data Layer

Gabriel Walt edited this page Mar 2, 2022 · 11 revisions

What

This is about making configurable the data that the Core Components expose in the Adobe Client Data Layer (ACDL). The objective is to allow for improving the data format so that it simplifies integrations with analytics and tracking solutions such as Adobe Analytics and Adobe Target, but so that it also doesn't break implementations that rely on the current data format. This configuration would allow to control how the Core Components hydrate the ACDL with data, but it would not change the ACDL script itself.

Why

The objective of the Core Components in general is to accelerate the time-to-value of sites, aiming to deliver a rapid and tangible value from newly created sites, and to lower subsequent maintenance effort. The value that a site provides to visitors however only can be perceived by the site owners if they are given some means to measure it, which is why the capability to integrate with analytics solutions is instrumental for time-to-value. In order to achieve that, the Core Components use the ACDL to offer an out-of-the-box data API that tracking solutions can use. In addition to simplifying analytics integrations, the data API also greatly benefits other integrations that require page data, such as targeting solutions.

The reason the data format exposed by the Core Components must be made configurable is because the current data format has important issues that strongly impede the aimed objective. The next section provides a detailed description of these issues.

Top issues

1. Page properties are not directly accessible

Currently, the biggest hurdle preventing Core Component implementors from using the data layer as provided is that the page properties are stored on an object that doesn't have a stable name: the name of the page object corresponds to the HTML ID of the page, which is unique to every page.

This is how complex it can currently get to reliably access the page object from the Core Components:

adobeDataLayer.addEventListener("cmp:show", function (eventData) {
    if (eventData.eventInfo.path.startsWith("page.page-")) {
        var pageData = adobeDataLayer.getState(eventData.eventInfo.path);
        console.log(pageData);
    }
});

This is how simple it should be instead:

var pageData = adobeDataLayer.getState("page");
console.log(pageData);

The current pattern was chosen in order to be consistent with other the components on the page. However, the page object is a singleton (an object that is only instantiated once), so a unique ID to access it is not required. Since the page object contains the properties that are by far the most used for any implementation, this issue is considerably impeding the value and the usage of data layer.

Changing this would be breaking existing implementations, which could be solved with applying the change on a new component version. However, introducing a breaking change is defeating the very purpose of the data layer, which is to provide integrations with a stable API to access the page data. The best option therefore would be to make name of the page object configurable, so that implementors can choose whether they want the page data directly beneath the page object, in a custom object name, or like it is currently on the page ID.

2. Events don't include the component properties

The second biggest hurdle preventing customers from using the data layer is that the event payload only contains a reference path to the originating component, which must then be manually resolved.

This is how to currently access the component data that originated an event:

adobeDataLayer.addEventListener("cmp:show", function(eventData) {
    var componentData = adobeDataLayer.getState(eventData.eventInfo.path);
    console.log(componentData);
});

This is how it should be instead:

adobeDataLayer.addEventListener("cmp:show", function(eventData) {
    console.log(eventData.eventInfo.component);
});

While the the current state doesn't look that bad in that case, being able to access the component data directly on events without having to call getState does substantially simplify the use of tag management solutions (such as Adobe Launch for example). The current state makes writing custom tracking scripts systematically required, while direct access to component data allows in most cases to configure the tracking of events without by just using the UI of the tag management solution (no code).

Changing this could be done without causing compatibility issues if the event provides both properties: on the eventInfo payload, the component data can be provided in addition to the component path. Providing both probably wouldn't cause any noticeable overhead.

3. The data format cannot be optimized

The third biggest complaint from implementors is that the Core Components hydrate a massive amount of data that cannot be customized and tailored to the needs. This frequently requires to rewrite the name of individual properties in the tag management layer, and also impacts the performance of pages (resulting in slower load times).

Customers would have a much leaner use of the data layer if a configuration allowed them to control which components should be enabled in the data layer, and which properties they expose under what name.

Proposed solution

User story

As a front-end developer, I want to be able to configure what component data is exposed in the data layer, and how it is exposed, so that my data tracking integrations are simple and lean.

Requirements

  1. The configuration must be site-specific to allow multi-site scenarios.
  2. The configuration must not be repeated on every page template policy.
  3. The configuration must be editable by a front-end developer persona.
  4. The configuration must define what components are available in the data layer.
  5. The configuration must define at what path the components are made available.
    • under a fixed path (examples: page, page.cmp, my-page).
    • under a path that contains the component ID (examples: page.${id}, component.${id}, mynamespace.mypage.${id})
  6. The configuration must define what data the components expose, and under which property names.
  7. AEM must provide a default configuration that remains compatible with the current implementation.
  8. The Project Archetype must provide a simplified configuration fixes the top issues (page properties not being directly accessible).
  9. The events fired by the Core Components must always include the component data under eventData.eventInfo.component.

Developer experience

A Sling context-aware configuration is suggested to satisfy the requirements 1 and 2.

A capability to update the context-aware configuration via a file deployed through the Cloud Manager Front-End Pipeline is suggested to satisfy the requirements 3. This would however be limited to Cloud Service, but creating a specific UI to edit this configuration would inflate the scope of this effort beyond what is possible. The wcm.io Configuration Editor might be able to used for 6.5 customers, as well as for Cloud Service in case a UI is required.

So, in the front-end module that is deployed via the front-end pipeline, a file named for example configs/data-layer.json would allow to update the /conf/SITENAME/sling:configs/com.adobe.cq.wcm.core.components.internal.DataLayerConfig node structure correspondingly.

To satisfy the requirements 4, 5 and 6, a configuration format roughly along the lines of the example below would allow to control which components are available in the data layer, as well as the properties that they provide under which path and property name:

{
    "enabled": true,
    "components": {
        "page": {
            "type": "core/wcm/components/page/v2/page",
            "path": "page",
            "properties": {
                "my:type": "${page.type}",
                "my:path": "${page.url}",
                "my:title": "${page.title}",
                "my:description": "${page.description}",
                "my:modifyDate": "${page.lastModifiedDate}"
            }
        },
        "image": {
            "type": "apps/core/wcm/components/image/v3/image",
            "path": "component.${image.id}",
            "properties": {
                "my:type": "${image.type}",
                "my:modifyDate": "${image.lastModifiedDate}",
                "my:asset": {
                    "my:type": "${image.assetData.mimeType}",
                    "my:path": "${image.assetData.url}",
                    "my:modifyDate": "${image.assetData.lastModifiedDate}"
                }
            }
        }
    }
}