Mapping.Rule
A Mapping.Rule is the object that sits at
config.mapping[entity][action] on a source or destination. It decides whether
an event applies, renames it, reshapes its data, gates it by consent, and can
emit side effects (batching, custom settings). The shape is defined in
packages/core/src/types/mapping.ts.
Configuration
| Property | Type | Description | More |
|---|---|---|---|
name | string | Custom event name override (e.g., "view_item" for "product view") | |
data | any | any | Data transformation rules for event | |
settings | any | Destination-specific settings for this event mapping | |
condition | string | Condition function as string: return true to process event | |
consent | WalkerOS.Consent | Required consent states to process this event | |
policy | Mapping.Policy | Event-level policy overrides (applied after config-level policy) | |
batch | number | object | Batch scheduling: bare number is the debounce wait window (legacy); object form supports wait/size/age. | |
include | Array<string> | Event sections (e.g. ["context", "globals"]) flattened into context.data | |
ignore | boolean | Skip the event entirely. No push, no side effects. Use for suppression. | |
silent | boolean | Run side effects (settings.identify, ...) but suppress the destination default push call. | |
extend | Mapping.RulePatch | Merge mode: a partial rule deep-merged onto the package-shipped default at this key (instead of replacing it). A null value clears an inherited field. | |
remove | Array<string> | Dotted paths stripped from the produced data payload after evaluation (applied last). |
Every value-shaped field (data, entries in policy, entries in settings
that take values) accepts any form documented in
Mapping.Value.
How destinations consume a rule
When an event reaches a destination, the collector looks up
mapping[event.entity][event.action]. An array means "try each in order, first
matching rule wins". A wildcard '*' on either entity or action acts as a
fallback.
Mapping wildcards are first-match: once entity.action (or its entity.* / *.action / *.* fallback) hits, no other rule is consulted. Contract wildcards are additive: every matching level merges in. The two systems intentionally pick different defaults — mapping selects a single transformation target, contract accumulates requirements.
Once a rule matches, the collector runs policy (event-level), resolves data,
checks consent and condition, then hands the result to the destination's
push (or buffers it when batch is set).
Batch scheduling
batch accepts a number (debounce wait window in ms, legacy form) or an
object { wait?, size?, age? } for finer control:
wait(ms): debounce window. The timer resets on every push.size: hard count cap. Flushes immediately at this many events.age(ms): hard age cap since the first entry of the current window.
Per-destination upper bounds (config.batch on the destination) apply
when the mapping rule omits a field; mapping-level values override
destination-level for matched events. Defaults when batching is enabled:
size: 1000, age: 30000. wait is a hint, not a hard delay: when
events keep arriving faster than wait, the size and age caps are
what force the flush.
Conditional rules
Use an array with conditions to branch by event contents; the first matching rule wins.
Ignore vs skip
Two flags control destination behaviour and they are not interchangeable:
ignore: true: the rule matched but nothing happens. No data transform, no destination call, no side effects. Use for suppression.skip: true: the rule matched and the destination'spush()is called.settings.identify,settings.revenue,settings.group, and other side effects still run. Only the destination's default forwarding call (e.g.track(),capture(),event()) is suppressed. Use for "identify without an event" style flows.
If both are set on the same rule, ignore wins.
{
user: {
login: {
skip: true,
settings: { identify: { map: { user: 'data.id' } } },
},
},
}
The example runs the destination's identify() side effect on user login
events but skips the default forwarding call.
API reference
The two functions below power mapping resolution. Destinations and sources call them through the collector, but they are exported for direct use in custom transformers or tests.
getMappingEvent
getMappingEvent(
event: WalkerOS.PartialEvent,
mapping?: Mapping.Rules,
): Promise<Mapping.Result>
Resolves the matching rule for an event based on event.name (the
"entity action" string). Returns { eventMapping, mappingKey } where
eventMapping is the matched Mapping.Rule and mappingKey is the lookup key
that matched (including wildcards).
getMappingValue
getMappingValue(
value: unknown,
mapping: Mapping.Data,
context?: Partial<Mapping.Context>,
): Promise<WalkerOS.Property | undefined>
Resolves a Mapping.Value against an input. Used internally for every data,
policy, and set resolution. The companion reference for each value form
lives in Mapping.Value.
Rule-level examples
Source mapping
Normalize events before they reach the collector:
Destination mapping
Transform for a specific destination API:
Combined flow
The same event can be transformed at both stations:
1. Browser sends: "product click"
2. Source mapping: "product click" → "product view"
3. Destination mapping: "product view" → "view_item"
4. GA4 receives: "view_item"
Patching package-shipped rules
Some packages (such as @walkeros/transformer-ga4) ship their own default
mapping rules. Normally, a user rule at the same key replaces the default in
full. Two keywords change that:
extend (config layer)
extend holds a partial rule that is deep-merged onto the package-shipped
default at the same key instead of replacing it. The merge happens once at
init, before any event is evaluated. A null value clears an inherited field.
Use extend when you want to add or override one field of a default rule while
inheriting the rest unchanged.
remove (output layer)
remove is a list of dotted paths stripped from the produced data payload
after evaluation, regardless of how each field was produced (map, fn,
include, etc.). Applied last, so it always wins.
Use remove when you must not emit a field (PII, a vendor-reserved parameter)
but do not want to rewrite the full rule.
Mode switching
A rule that has neither extend nor remove keeps today's replace
behavior. Presence of either keyword activates merge mode for that rule.
Example: patch a GA4 decoder rule
The transformer-ga4 purchase default ships id, currency, total, tax,
shipping, and coupon. The config below adds affiliation from a GA4 event
parameter and drops currency from the output, keeping all other default
fields:
{
"settings": {
"mapping": {
"purchase": {
"extend": {
"data": { "map": { "affiliation": "params.ep.affiliation" } }
},
"remove": ["currency"]
}
}
}
}
extend.data.map is deep-merged onto the default data.map, so affiliation
is added alongside the existing keys. remove: ["currency"] then strips that
field from the final payload.
See also
- Mapping.Value: the eight value forms used in every rule field
- Consent guide: consent model and gating
- Destinations reference: destination-specific
settings mapping.tssource