Skip to main content
Source code Package

DataLayer source

Integrates with existing Google Analytics 4 and GTM dataLayer implementations by intercepting dataLayer.push() calls.

Where this fits

The DataLayer source is a web source in the walkerOS flow:

It bridges existing GA4/GTM implementations to walkerOS destinations.

Installation

npm install @walkeros/web-source-datalayer
import { startFlow } from '@walkeros/collector';
import { sourceDataLayer } from '@walkeros/web-source-datalayer';

const { collector, elb } = await startFlow({
sources: {
  dataLayer: {
    code: sourceDataLayer,
    config: {
      settings: {
        name: 'dataLayer', // Name of global dataLayer array
        prefix: 'dataLayer', // Event prefix for filtering
      },
    },
  },
},
destinations: {
  // Your destinations
},
});

Configuration

This source uses the standard source config wrapper (consent, data, env, id, ...). For the shared fields see source configuration. Package-specific fields live under config.settings and are listed below.

Settings

PropertyTypeDescriptionMore
namestringDataLayer variable name (default: dataLayer)
prefixstringEvent prefix for filtering which events to process
filterfunctionCustom filter function: (event: unknown) => boolean | Promise<boolean>

Mapping

Per-event rules under config.mapping. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.

PropertyTypeDescriptionMore
commandanyMapping.Value evaluated against the raw dataLayer arguments to build walker command data (e.g. consent updates).

Examples

Consent update

A gtag consent update is captured from the dataLayer as a walker dataLayer consent update event.

Event
[
  "consent",
  "update",
  {
    "ad_storage": "granted",
    "analytics_storage": "granted"
  }
]
Out
elb({
  "name": "dataLayer consent update",
  "data": {
    "ad_storage": "granted",
    "analytics_storage": "granted"
  }
})

Direct dataLayer event

A plain object pushed directly onto the dataLayer is captured as a walker dataLayer custom event.

Event
{
  "event": "custom_event",
  "category": "engagement",
  "label": "video_play"
}
Out
elb({
  "name": "dataLayer custom_event",
  "data": {
    "category": "engagement",
    "label": "video_play"
  }
})

gtag add_to_cart

A gtag add_to_cart call pushed to the dataLayer is captured as a walker dataLayer add_to_cart event.

Event
[
  "event",
  "add_to_cart",
  {
    "currency": "EUR",
    "value": 15.25,
    "items": [
      {
        "item_id": "SKU_12345",
        "item_name": "T-Shirt",
        "item_variant": "red",
        "quantity": 1,
        "price": 15.25
      }
    ]
  }
]
Out
elb({
  "name": "dataLayer add_to_cart",
  "data": {
    "currency": "EUR",
    "value": 15.25,
    "items": [
      {
        "item_id": "SKU_12345",
        "item_name": "T-Shirt",
        "item_variant": "red",
        "quantity": 1,
        "price": 15.25
      }
    ]
  }
})

gtag purchase

A gtag purchase call pushed to the dataLayer is captured as a walker dataLayer purchase event with item details.

Event
[
  "event",
  "purchase",
  {
    "transaction_id": "T-12345",
    "value": 25.42,
    "currency": "EUR",
    "items": [
      {
        "item_id": "SKU-1",
        "item_name": "T-Shirt",
        "quantity": 1
      }
    ]
  }
]
Out
elb({
  "name": "dataLayer purchase",
  "data": {
    "transaction_id": "T-12345",
    "value": 25.42,
    "currency": "EUR",
    "items": [
      {
        "item_id": "SKU-1",
        "item_name": "T-Shirt",
        "quantity": 1
      }
    ]
  }
})

gtag view_item

A gtag view_item call pushed to the dataLayer is captured as a walker dataLayer view_item event with item data.

Event
[
  "event",
  "view_item",
  {
    "currency": "EUR",
    "value": 29.99,
    "items": [
      {
        "item_id": "SKU_67890",
        "item_name": "Sneakers",
        "item_category": "Footwear",
        "price": 29.99
      }
    ]
  }
]
Out
elb({
  "name": "dataLayer view_item",
  "data": {
    "currency": "EUR",
    "value": 29.99,
    "items": [
      {
        "item_id": "SKU_67890",
        "item_name": "Sneakers",
        "item_category": "Footwear",
        "price": 29.99
      }
    ]
  }
})

How it works

The dataLayer source intercepts dataLayer.push() calls and transforms them into walkerOS events:

  1. Intercepts existing dataLayer.push() calls
  2. Filters events based on prefix or custom filter function
  3. Transforms dataLayer format to walkerOS event format
  4. Forwards to collector for processing
// Existing dataLayer code (unchanged)
window.dataLayer = window.dataLayer || [];
dataLayer.push({ event: 'purchase', value: 99.99 });

// Automatically captured and transformed by sourceDataLayer
// → Sent to walkerOS collector as standard event

Custom filtering

Filter which dataLayer events get processed:

const { elb } = await startFlow({
sources: {
  dataLayer: {
    code: sourceDataLayer,
    config: {
      settings: {
        filter: (event) => {
          // Only process purchase and add_to_cart events
          if (typeof event === 'object' && event !== null) {
            const e = event as { event?: string };
            return e.event === 'purchase' || e.event === 'add_to_cart';
          }
          return false;
        },
      },
    },
  },
},
});

Source-level mapping

The source emits walkerOS events whose name is "<prefix> <gtag-action>". The collector splits name on the first space into entity and action, so the prefix becomes the entity and the gtag action becomes the action. Source-level mapping rules key on that pair:

"sources": {
"dataLayer": {
  "package": "@walkeros/web-source-datalayer",
  "config": {
    "settings": { "prefix": "dataLayer" },
    "mapping": {
      "dataLayer": {
        "add_to_cart": {
          "name": "product add",
          "data": {
            "map": {
              "id": "items.0.item_id",
              "name": "items.0.item_name",
              "price": "value",
              "currency": "currency",
              "quantity": "items.0.quantity"
            }
          }
        },
        "purchase": {
          "name": "order complete",
          "data": {
            "map": {
              "id": "transaction_id",
              "total": "value",
              "currency": "currency"
            }
          }
        }
      }
    }
  }
}
}

For the gtag commands consent, config, and set, the action equals the command name (any trailing token such as update or a measurement ID is dropped by the entity/action split). Branch on the dropped value via rule-level condition or event.data if you need to distinguish, for example, consent default from consent update.

If you set a custom prefix (for example "gtag"), use that string as the entity key: mapping.gtag.add_to_cart.

Migration strategy

Use the dataLayer source for gradual migration from GA4/GTM:

Phase 1: Add walkerOS alongside existing dataLayer

// Existing code continues to work
dataLayer.push({ event: 'purchase', value: 99.99 });
// Now also captured by walkerOS

Phase 2: Map dataLayer events to walkerOS destinations

destinations: {
ga4: {
  code: destinationGtag,
  config: {
    mapping: {
      // Map dataLayer purchase to GA4 format
    }
  }
}
}

Phase 3: Gradually replace dataLayer.push with elb()

// Old
dataLayer.push({ event: 'purchase', value: 99.99 });
// New
elb('order complete', { total: 99.99 });

Next steps

💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)