Tagging & Measurement

The Independent Event-Driven Data Layer – A Practical Guide

This guide shows you how to set up an independent "vendor-agnostic" Event Driven Data Layer (EDDL) and how to process events within this data layer. Example code is provided, so you can build your own data connectors.

  • Learn how to set up an independent Event Driven Data Layer.
  • Learn how to attach an event listener to process the events in the data layer.
  • Using the Google Data Layer Helper library.
  • Example connectors: Simple console logs and a Tealium iQ (Tag Management) connector.

Why is this still relevant?

This article could easily been written 5 years ago. Still it's relevant today and even more important seen the recent focus on quality first-party data (which should have been a focus all along..).

Anyway, a lot of articles are written on this topic (some mentioned later on), but I felt I could add some value with some practical examples and give it some context seen recent developments regarding tracking & first-party data.

A well structured Event Driven Data Layer (EDDL) including mechanism that enables you to process and listen to events in the EDDL, can be extremely powerful when you're planning to create an abstraction layer between your website / app and TMS or other client-side data collection tool. Especially;

  • When you want to take full ownership of your data layer and don't want to depend on vendor specific code and/or requirements.
  • When not using GTM.
  • Using data collection tools or tag management systems that do not have an event driven data layer mechanism in place.
  • You want to create your own data collection library / script (for example to provide data to Google Tag Manager Server without using the gtag.js library or client-side GTM).

But what exactly is an EDDL?

The Event Driven Data Layer (EDDL)

The term EDDL gained popularity through the efforts of Jim Gorden (Jimalytics). As mentioned, there are already a lot of good articles written about the workings and benefits of the EDDL. So I would recommend to check out the following articles first:

Short recap: Many know the concept of an EDDL from Google Tag Manager (the dataLayer). Replace digitalData with dataLayer in the example below all should look familiar.

The Event Driven Data Layer itself basically is just a plain Javascript array (digitalData in the example below), containing (event) objects. Think of pageviews, clicks or purchases. The Javascript array is available at window scope.

Example:

1window.digitalData = window.digitalData || [];
2
3// Pageview event
4digitalData.push({
5  "event": "page",
6  "page_type": "product_detail",
7  "product_id": "12345",
8  "product_name": "Shiny red shoes"
9  // ...
10});
11
12// Purchase event
13digitalData.push({
14  "event": "purchase",
15  "transaction_id": "777",
16  "product_id": "12345",
17  "product_name": "Shiny red shoes"
18  // ...
19});

You can structure the events and properties any way you like, so that it nicely fits your type of business. Keep in mind, consistency is key!

When such a data layer is in place, one can write some code or use existing libraries to process the events pushed into the data layer array and attach listeners to it. The listeners can be used to build connectors or wrappers around vendor-specific tracking scripts, so you can map your data layer variables to vendor specific requirements (in one place).

Some common use cases:

  • Connect event listeners to the data layer (e.g. Tag Management Systems / tracking script connectors)
  • Connect data validators (e.g. JSON schema validation)
  • Transform data to specific formats / business requirements before data is send to data collection or TMS tools.
  • Switch listeners based on different platforms or environments, but using the same data layer. Think of parts of your website that are loaded in a Webview, for example in Hybrid apps (like Cordova)

vendor-agnostic-data-layer.PNG

The benefits of using an EDDL

But what are the benefits of an EDDL compared to (vendor specific) data layer and collection setups?

  • No vendor specific knowledge required for developers (e.g. vendor libraries), plain Javascript arrays and objects (except for building the connector itself).
  • No vendor lock-in / vendor agnostic, swap out vendors (client-side TMS / tracking solutions) more easily.
  • Data layer structure not tied to vendor specific requirements.
  • Asynchronous
  • Excellent fit for single page / event-driven applications.

Vendor Agnostic what?

As you can see in the example above, besides (optional) event object structure, there isn't much vendor-specific logic involved. Since GTM uses the same concept, you could say that GTM already uses an "independent" data layer (besides the recommended event structure).

But, Google Tag Manager isn't the only TMS used (yes, really). Think of Tealium, Adobe or Segment. But we also have data collection scripts that can be implemented without a TMS, such as the gtag.js library (and becomes relevant if you don't want to use client-side GTM to implement server-side GTM for example).

In many cases, these vendors require you to implement vender specific code. Some examples:

Tealium iQ (TMS)

A Tealium iQ pageview:

1utag.view({
2    "tealium_event": "product_view",
3    "page_type"    : "product",
4    "product_id"   : ["12345"],
5    "product_name" : ["Red shoes"]
6});

Adobe

Adobe recently (2020) launched it's own event driven data layer library, called ACDL, so bad example.

gtag.js

A gtag.js pageview:

1gtag("event'" "page_view", {
2  "page_title": "<Page Title>",
3  "page_location": "<Page Location>",
4  "page_path": "<Page Path>",
5  "send_to": "<GA_MEASUREMENT_ID>"
6})

As you can see, there is a lot of vendor specific code involved. The point here is that you don't want is to implement such vendor specific code all through your website or app. So, creating an abstraction layer would be a wise approach.

I've implemented an event driven data layer for multiple clients over the last few years (DigitalDataQueue), and it really has proved its worth. For some clients, after the EDDL implementation, we've changed the TMS multiple times (something to do with the business being sold multiple times..). It saved a lot of people a lot of work and data quality was never compromised.

Listen to and process events in the data layer

A good example of a data layer "listener" library is the Data Layer Helper library by Google (also used in GTM). We will use this library in the examples below.

Back in 2018, together with my former colleague Folkert Mudde we've rewritten added some features to the Google Data Layer Helper Library and named it DigitalDataQueue (GitHub). It's a bit outdated now and Google updated their Data Layer Helper Library in the meantime, so I will use the Google library in the examples below.

The Data Layer Helper library will:

  • Process events passed into the data layer (digitalData.push({ .. }))
  • Activate listener functions (connectors) when new events are pushed into the data layer
  • Process (historical) event already present in the datalayer before the library is activated.
  • Merges event data (object) into a data model (object)

Order of operations data-layer-helper-order-of-operations.PNG

Firstly, check out the GitHub repo of the Data Layer Helper. The library is documented pretty well.

You can add the library to you application easily;

1npm install data-layer-helper
2// or
3yarn install data-layer-helper

And import the package

1import 'node_modules/data-layer-helper/dist/data-layer-helper';

Other option is to host the minified data-layer-helper.js version of the library somewhere and include it into you application.

Let's move on to the examples.

Example 1 - Log events to the console

The first example will just log the events pushed in the data layer to the (browser) console. It nicely demonstrates the capabilities of the library.

1// Make sure to include the Data Layer Helper library first
2
3window.digitalData = window.digitalData || [];
4
5// Pageview event
6digitalData.push({
7  "event": "page",
8  "page_type": "product_detail",
9  "product_id": "12345",
10  "product_name": "Shiny red shoes"
11  // ...
12});
13
14const DigitalDataHelper = new DataLayerHelper(digitalData);
15
16function listenerLogToConsole(model, event) {
17  console.log(event);
18}
19
20const DigitalDataHelper = new DataLayerHelper(digitalData, {
21  listener: listenerLogToConsole,
22  listenToPast: true, // Process events already in the digitalData array before initializing the library.
23});

Now, when you execute the code, you should see the pageview event in your browser console.

Example 2 - Tealium iQ connector

The seconds example show you how to create a wrapper function around Tealium iQ specific code, so its activated based on events within the data layer.

Tip: It's perfectly possible to include the data-layer-helper.js script AND the listener function in a Preloader extension within Tealium itself. Benefit is that you know for sure that Tealium is loaded before activating the listener (+ easy to edit the listener function within Tealium itself).

1<!-- Data Layer Helper library -->
2<script type="text/javascript" src="data-layer-helper.js"></script>
3
4<!-- Tealium Universal Tag -->
5<script type="text/javascript">
6	// Declare datalayer
7	window.digitalData = window.digitalData || [];
8	
9	// .. Populate datalayer
10	// digitalData.push({ .. });
11	
12	// Tealium config overraide: disable default pageview `view()` on load 
13	// To prevent duplicate pageviews, since the page event will trigger a pageview
14	window.utag_cfg_ovrd = {
15		noview: true
16	};
17	
18	// Tealium Universal Base Tag
19	(function(a,b,c,d) {
20		a='//tags.tiqcdn.com/utag/ACCOUNT/PROFILE/ENVIRONMENT/utag.js';
21		b=document;c='script';d=b.createElement(c);d.src=a;
22		d.type='text/java'+c;d.async=true;
23		a=b.getElementsByTagName(c)[0];a.parentNode.insertBefore(d,a)})();
24
25	// Data layer listener function: Tealium connector
26	// Tip: You can implement this code directly in the front-end OR add the code as a preloader extension within Tealium
27	function listenerTealium(model, event) {
28	   
29		// Declare utag_data / UDO (Tealium datalayer)
30		window.utag_data = window.utag_data || [];
31	   
32		// Tealium specific transformations
33		var _event = event;
34		var _model = model;
35		
36		// Mapping digital-data-queue events to Tealium
37		if (typeof _event.event != 'undefined') {
38			switch(_event.event) {
39				case "page":
40					window.utag_data = _event;
41					window.utag.view(window.utag_data, function() { window.utag.DB("digital-data: Event: \"" + _event.event + "\" to utag.view()"); });
42					break;
43				default:
44					// Using the model (instead of event) to populate event parameters, so page properties are available within the event.
45					window.utag.link(_model, function() { window.utag.DB("digital-data: Event : \"" + _event.event + "\" to utag.link()"); });
46			}
47		} else {
48			// No event property set
49		}
50	}
51
52	// Init Data Layer Helper
53	var DigitalDataHelper = new DataLayerHelper(digitalData, {
54		listener: listenerTealium,
55		listenToPast: true, // Process events already in the digitalData array before initializing the library.
56	});
57</script>

Other interesting reads

The examples above showed you some of the possibilities using an EDDL / event listener. I'd love to hear your experiences and use cases.

Lastly, some interesting articles related to this topic not mentioned before:

Did you like this article? Stay hydrated and get notified when new articles, tutorials or other interesting updates are published. No spam and you can unsubscribe at any time. You can also check my Twitter account for updates and other interesting material.