Skip to main content

Mapping Configuration Recipes

Prerequisites

Read understanding-mapping first for core concepts.

Quick Reference

I want to...Use this pattern
Rename event{ name: 'new_name' }
Extract nested value'data.nested.value'
Set static value{ value: 'USD' }
Transform value{ fn: (e) => transform(e) }
Build object{ map: { key: 'source' } }
Process array{ loop: ['source', { map: {...} }] }
Gate by consent{ key: 'data.email', consent: { marketing: true } }
First defined value (fallback)[{ key: 'data.sku' }, { key: 'data.id' }]
Add a field to a default rule{ extend: { data: { map: { x: 'path' } } } }
Drop a field from output{ remove: ['field.path'] }

Common Recipes

GA4 / gtag

Product view → view_item:

product: {
view: {
name: 'view_item',
data: {
map: {
currency: { value: 'USD' },
value: 'data.price',
items: {
loop: [
'nested',
{
map: {
item_id: 'data.id',
item_name: 'data.name',
item_category: 'data.category',
price: 'data.price',
quantity: { value: 1 },
},
},
],
},
},
},
},
}

Order complete → purchase:

order: {
complete: {
name: 'purchase',
data: {
map: {
transaction_id: 'data.orderId',
value: 'data.total',
currency: 'data.currency',
items: {
loop: [
'nested',
{
map: {
item_id: 'data.id',
item_name: 'data.name',
price: 'data.price',
quantity: 'data.quantity',
},
},
],
},
},
},
},
}

Meta Pixel

Product view → ViewContent:

product: {
view: {
name: 'ViewContent',
data: {
map: {
content_ids: { fn: (e) => [e.data.id] },
content_type: { value: 'product' },
content_name: 'data.name',
value: 'data.price',
currency: { value: 'USD' },
},
},
},
}

Order complete → Purchase:

order: {
complete: {
name: 'Purchase',
data: {
map: {
content_ids: { fn: (e) => e.nested?.map((n) => n.data.id) ?? [] },
content_type: { value: 'product' },
value: 'data.total',
currency: 'data.currency',
num_items: { fn: (e) => e.nested?.length ?? 0 },
},
},
},
}

Custom API Destination

Transform to REST API format:

'*': {
'*': {
name: { fn: (e) => `${e.entity}_${e.action}` }, // page_view
data: {
map: {
eventName: 'name',
eventData: 'data',
userId: 'user.id',
sessionId: 'user.session',
timestamp: 'timestamp',
metadata: {
map: {
consent: 'consent',
globals: 'globals',
},
},
},
},
},
}

Conditional Mapping

Different mapping based on event data:

order: {
complete: [
// High-value orders get extra tracking
{
condition: (e) => (e.data?.total ?? 0) > 500,
name: 'high_value_purchase',
data: {
map: {
value: 'data.total',
priority: { value: 'high' },
notify: { value: true },
},
},
},
// Standard orders
{
name: 'purchase',
data: { map: { value: 'data.total' } },
},
],
}

Patching Package-Shipped Rules (extend / remove)

Some packages (such as @walkeros/transformer-ga4) ship default mapping rules. Normally a user rule at the same key replaces the default in full. Use extend or remove to patch instead.

Two layers, two keywords:

  • extend runs at init (config layer): deep-merges a partial rule onto the shipped default. A null value clears an inherited field.
  • remove runs after evaluation (output layer): strips dotted paths from the final data payload. Applied last, always wins.

A rule with neither keyword keeps the existing replace behavior.

{
"purchase": {
"extend": {
"data": { "map": { "affiliation": "params.ep.affiliation" } }
},
"remove": ["currency"]
}
}

This keeps all fields the package ships for purchase, adds affiliation, and strips currency from the output.

For the full reference and the two-layer model, see Mapping.Rule docs.

Value[] Fallback Chains

At any value position, an array of values is a fallback chain: the first entry that resolves to a defined value wins.

{
"item_id": [
{ "key": "data.sku" },
{ "key": "data.id" },
{ "value": "unknown" }
]
}

Use this to try multiple source fields before falling back to a constant.

Only include PII if consent granted:

user: {
login: {
name: 'login',
data: {
map: {
method: 'data.method',
// Only include email if marketing consent
email: {
key: 'user.email',
consent: { marketing: true },
},
// Only include user ID if functional consent
userId: {
key: 'user.id',
consent: { functional: true },
},
},
},
},
}

Wildcard Patterns

Catch-all for unmatched events:

// Any product action
product: {
'*': {
name: { fn: (e) => `product_${e.action}` },
data: 'data',
},
}

// Any click on any entity
'*': {
click: {
name: 'element_click',
data: {
map: {
element_type: 'entity',
element_id: 'data.id',
},
},
},
}

Source-Side Mapping

Transform HTTP input to walkerOS event:

// In source config
{
mapping: {
// Map incoming field names to walkerOS structure
name: { fn: (input) => `${input.entity} ${input.action}` },
data: 'payload',
user: {
map: {
id: 'userId',
session: 'sessionId',
},
},
},
}

Debugging Tips

  1. Event not mapping? Check entity/action match exactly (case-sensitive)
  2. Data missing? Verify source path exists: 'data.nested.field'
  3. Function errors? Add null checks: e.data?.price ?? 0
  4. Array empty? Confirm nested array exists and has items

Reference:

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