DataLayer source
Integrates with existing Google Analytics 4 and GTM dataLayer implementations by intercepting dataLayer.push() calls.
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- Integrated
- Bundled
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
},
});Add to your flow.json sources:
"sources": {
"dataLayer": {
"package": "@walkeros/web-source-datalayer",
"config": {
"settings": {
"name": "dataLayer",
"prefix": "dataLayer"
}
}
}
}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
| Property | Type | Description | More |
|---|---|---|---|
name | string | DataLayer variable name (default: dataLayer) | |
prefix | string | Event prefix for filtering which events to process | |
filter | function | Custom filter function: (event: unknown) => boolean | Promise<boolean> |
Mapping
This package does not define custom rule-level settings. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.
Examples
Consent update
A gtag consent update is captured from the dataLayer as a walker dataLayer consent update event.
[
"consent",
"update",
{
"ad_storage": "granted",
"analytics_storage": "granted"
}
]elb({
"name": "dataLayer consent update",
"data": {
"ad_storage": "granted",
"analytics_storage": "granted"
},
"source": {
"type": "dataLayer",
"platform": "web",
"url": "https://example.com/",
"referrer": ""
}
})Direct dataLayer event
A plain object pushed directly onto the dataLayer is captured as a walker dataLayer custom event.
{
"event": "custom_event",
"category": "engagement",
"label": "video_play"
}elb({
"name": "dataLayer custom_event",
"data": {
"category": "engagement",
"label": "video_play"
},
"source": {
"type": "dataLayer",
"platform": "web",
"url": "https://example.com/",
"referrer": ""
}
})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",
"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
}
]
}
]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
}
]
},
"source": {
"type": "dataLayer",
"platform": "web",
"url": "https://example.com/",
"referrer": ""
}
})gtag purchase
A gtag purchase call pushed to the dataLayer is captured as a walker dataLayer purchase event with item details.
[
"event",
"purchase",
{
"transaction_id": "T-12345",
"value": 25.42,
"currency": "EUR",
"items": [
{
"item_id": "SKU-1",
"item_name": "T-Shirt",
"quantity": 1
}
]
}
]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
}
]
},
"source": {
"type": "dataLayer",
"platform": "web",
"url": "https://example.com/",
"referrer": ""
}
})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",
"view_item",
{
"currency": "EUR",
"value": 29.99,
"items": [
{
"item_id": "SKU_67890",
"item_name": "Sneakers",
"item_category": "Footwear",
"price": 29.99
}
]
}
]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
}
]
},
"source": {
"type": "dataLayer",
"platform": "web",
"url": "https://example.com/",
"referrer": ""
}
})How it works
The dataLayer source intercepts dataLayer.push() calls and transforms them into walkerOS events:
- Intercepts existing
dataLayer.push()calls - Filters events based on prefix or custom filter function
- Transforms dataLayer format to walkerOS event format
- 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 eventEvery event carries the page context in source, like browser source events:
{ type: 'dataLayer', platform: 'web', url, referrer }, with url from
window.location.href and referrer from document.referrer. Both are read
when the event is emitted, so a push after an SPA navigation carries the new
URL, and entries queued before the source started get the URL at replay time.
Destinations that read source.url (such as Meta or Piwik PRO) use it for
dataLayer events without extra config.
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 walkerOSPhase 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({ name: 'order complete', data: { total: 99.99 } });Next steps
- Review event mapping for transforming dataLayer events
- Check GA4 destination for Google Analytics integration