> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

# 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`](https://github.com/elbwalker/walkerOS/blob/main/packages/core/src/types/mapping.ts).

## Configuration[​](#configuration "Direct link to 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](https://www.walkeros.io/docs/mapping/value.md).

## How destinations consume a rule[​](#how-destinations-consume-a-rule "Direct link to 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 differ from contract wildcards

Mapping wildcards are **first-match**: once `entity.action` (or its `entity.*` / `*.action` / `*.*` fallback) hits, no other rule is consulted. [Contract wildcards](https://www.walkeros.io/docs/getting-started/flow/contract.md#wildcard-inheritance) are **additive**: every matching level merges in. The two systems intentionally pick different defaults — mapping selects a single transformation target, contract accumulates requirements.

Configuration

Loading...

Result

Loading...

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-scheduling "Direct link to 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.

A rule-level `batch` splits this entity-action into its own buffer. When the destination also sets `config.batch`, the rule's values override destination-level per field (`rule ?? config ?? default`); fields the rule omits fall back to `config.batch`. Setting `config.batch` alone batches **all** of the destination's events into one shared buffer with no rule needed. 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[​](#conditional-rules "Direct link to Conditional rules")

Use an array with conditions to branch by event contents; the first matching rule wins.

Configuration

Loading...

Result

Loading...

## Ignore vs skip[​](#ignore-vs-skip "Direct link to 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's `push()` **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.

Configuration

Loading...

Result

Loading...

```
{

  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[​](#api-reference "Direct link to 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 "Direct link to 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 "Direct link to 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](https://www.walkeros.io/docs/mapping/value.md).

## Rule-level examples[​](#rule-level-examples "Direct link to Rule-level examples")

### Source mapping[​](#source-mapping "Direct link to Source mapping")

Normalize events before they reach the collector:

```
await startFlow({
  sources: {
    browser: {
      code: sourceBrowser,
      config: {
        mapping: {
          product: {
            click: {
              name: 'product view',
              policy: {
                'data.id': { fn: (e) => e.data?.id?.toUpperCase() },
              },
            },
          },
          test: { '*': { ignore: true } },
        },
        policy: {
          'user.email': { fn: (e) => e.user?.email?.toLowerCase() },
        },
      },
    },
  },
});
```

### Destination mapping[​](#destination-mapping "Direct link to Destination mapping")

Transform for a specific destination API:

```
await startFlow({
  destinations: {
    gtag: {
      code: destinationGtag,
      config: {
        mapping: {
          product: {
            view: {
              name: 'view_item',
              data: {
                map: {
                  item_id: 'data.id',
                  value: 'data.price',
                  currency: { value: 'USD' },
                },
              },
            },
          },
        },
      },
    },
  },
});
```

### Combined flow[​](#combined-flow "Direct link to 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[​](#patching-package-shipped-rules "Direct link to 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-config-layer "Direct link to 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-output-layer "Direct link to 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[​](#mode-switching "Direct link to 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[​](#example-patch-a-ga4-decoder-rule "Direct link to 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[​](#see-also "Direct link to See also")

* [Mapping.Value](https://www.walkeros.io/docs/mapping/value.md): the eight value forms used in every rule field
* [Consent guide](https://www.walkeros.io/docs/guides/consent.md): consent model and gating
* [Destinations reference](https://www.walkeros.io/docs/destinations.md): destination-specific `settings`
* [`mapping.ts` source](https://github.com/elbwalker/walkerOS/blob/main/packages/core/src/types/mapping.ts)
