Skip to main content
Ask your AI

Mapping.Value

Mapping.Value is what you put into any mapping field that expects a value: data, every entry under map, entries in set[], keys under policy, and anywhere a destination rule field accepts any. It is polymorphic: a value can be a simple string path, an object with one of several transforming keys, or an array of those, which is a fallback chain: the first entry that resolves wins. The shape is defined in packages/core/src/types/mapping.ts as Value = ValueType | Array<ValueType>, where ValueType is either a string (path) or a ValueConfig object.

Options​

FormShapeWhat / When
PathstringReads a dot-path from the event. Use for copying raw fields straight into the output.
Constant{ value }Emits a fixed value. Use when the destination needs a literal like a currency, ID, or label.
Map{ map: { key: Value, … } }Builds an object from multiple paths. Use when the destination expects a structured payload.
Loop{ loop: [source, Value] }Iterates an array source and transforms each item. Use for nested product, cart, or item lists.
Set{ set: [Value, Value, …] }Builds an array from several values, in order. Use when the destination expects a list.
Fn{ fn: (value, context) => … }Runs a custom function on the event. Use only when no declarative form fits.
Condition{ condition, value }Gates the value on a predicate. Use for branching logic inside a single rule.
Consent{ consent: {…}, value }Gates the value on consent states. Use to make individual fields privacy-aware.

A ValueConfig uses one producer plus optional filters. key, fn, map, loop and set each produce the value, so set exactly one. If you set several, exactly one runs, in this order, and the rest never run: loop, map, set, key, fn. value is the fallback when the producer returns nothing, including a loop over something that is not a list. condition, consent and validate filter the result and combine freely.

To read a field and then transform it, use fn alone. It receives the whole source object, so fn: (source) => source.user.email.split('@')[1] does both steps in one place. For an event field you can also rewrite it with a policy entry and read it with key. Anything bigger belongs in a transformer.

The examples below run live: edit one and its result updates. Each calls getMappingValue with a running collector in its context ({ collector }, from startFlow), as a step's mapping does.

Path​

Extract a value by dot-path from the event.

Configuration
Loading...
Result
Loading...

Paths also index into arrays:

Configuration
Loading...
Result
Loading...

Constant​

Return a fixed value, independent of the event.

Configuration
Loading...
Result
Loading...

Map​

Build an object by mapping keys to their own Mapping.Value.

Configuration
Loading...
Result
Loading...

Loop​

Iterate an array source and transform each element. loop: [source, value]: source selects the array (a path, or 'this' for the event itself), value transforms each item.

Each item is mapped under the event's consent. A loop item's consent key neither unlocks nor holds back a value; the event's consent decides. A condition or fn inside the item mapping sees that same consent in context.consent.

Configuration
Loading...
Result
Loading...

Set​

Resolve every value and return them as an array, in order. A value that resolves to nothing keeps its position as an empty entry.

{ set: ['data.id', 'data.name'] } // ['P1', 'Shirt']

For a fallback chain, where the first value that resolves wins, use a plain array instead: ['data.email', 'user.email', { value: 'anonymous' }].

Fn​

Run a custom function. The handler receives (value, context) and may return a promise. All three callbacks (fn, condition, validate) share the same shape.

Context object​

FieldTypeRequiredDescription
eventWalkerOS.DeepPartialEventyesThe root event being mapped
mappingMapping.Value | Mapping.RuleyesThe surrounding mapping config (or rule)
collectorCollector.InstanceyesActive collector, use for push and queue
loggerLogger.InstanceyesUse for info/warn/error/debug
consentWalkerOS.Consent (optional)noResolved consent at this evaluation point

One-arg callbacks like (value) => value.toUpperCase() continue to work, TypeScript ignores the unused context argument.

Configuration
Loading...
Result
Loading...

Condition​

Only produce output when condition(event) returns truthy.

{
condition: (event) => event.data?.value > 50,
value: 'high_value',
}

Only produce output when the required consent states are granted on the event.

Configuration
Loading...
Result
Loading...

Nothing: marketing consent is false on the event, so the value is dropped. Set consent.marketing to true in the input to see john@example.com.

Validate​

validate is a filter, not a form. Combine it with any value-producing key. The function runs on the produced value; if it returns falsy the result is dropped (undefined).

Configuration
Loading...
Result
Loading...

Policy​

A policy is a record of Mapping.Values applied to the event before the rule runs. The key is the path the result writes into; the value is any form above.

Config-level policy applies to every event handled by the source or destination:

{
  config: {
    policy: {
      'user.email': { fn: (e) => e.user?.email?.toLowerCase() },
      'data.timestamp': { fn: () => Date.now() },
    },
  },
}

Event-level policy applies only inside the matched rule:

{
  config: {
    mapping: {
      product: {
        view: {
          name: 'view_item',
          policy: {
            'data.id': { fn: (e) => `PRODUCT_${e.data?.id}` },
          },
        },
      },
    },
  },
}

Processing order: config policy → event matching → event policy → data transformation.

See also​

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