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

# Collector commands

The collector provides a core event processing engine that manages destinations, consent, user data, and custom properties. Commands are executed through the `elb` function, which the collector also exposes as `collector.elb`.

Unknown walker commands log a warning and return `{ ok: false }`. Commands like `walker init` are browser-specific and handled by the browser source before they reach the collector.

note

For browser-specific commands like DOM initialization and elbLayer communication, see [Browser Source Commands](https://www.walkeros.io/docs/sources/web/browser/commands.md).

## destination[​](#destination "Direct link to destination")

Add destinations to the collector. The recommended approach is to configure destinations during initialization with `startFlow()`:

```
import { startFlow } from '@walkeros/collector';
import { destinationGtag } from '@walkeros/web-destination-gtag';

const { collector, elb } = await startFlow({
  destinations: {
    gtag: {
      code: destinationGtag,
      config: {
        settings: { /* custom config */ },
      },
    },
  },
});
```

tip

For dynamic scenarios requiring runtime destination addition, use `elb('walker destination')` command or `collector.addDestination()`. See destination-specific documentation for configuration options.

## consent[​](#consent "Direct link to consent")

Manage consent states for the collector. Names can be defined arbitrarily, but common groups are functional, analytics, and marketing. Values are booleans, and once a value is set to `true` it's treated as consent being granted.

```
elb('walker consent', { marketing: true, analytics: true });
```

Setting a consent state to `false` will immediately stop a destination from processing any events. Previously pushed events during the run are shared with existing destinations once consent is granted.

info

Learn more about [consent management](https://www.walkeros.io/docs/guides/consent.md) in detail.

## on[​](#on "Direct link to on")

Add event listeners to the collector. They get called when specific events occur like `run` or `consent` changes.

```
elb('walker on', { type, rules });
```

`rules` depends on `type` and can also be an array for multiple listeners at once. Every callback receives `(data, context)` where `context` exposes `collector` and `logger`.

### Callback signatures[​](#callback-signatures "Direct link to Callback signatures")

| Action  | Callback signature                                       |
| ------- | -------------------------------------------------------- |
| consent | `{ [key]: (consent, context) => void \| Promise<void> }` |
| ready   | `(_, context) => void \| Promise<void>`                  |
| run     | `(_, context) => void \| Promise<void>`                  |
| session | `(session, context) => void \| Promise<void>`            |
| user    | `(user, context) => void \| Promise<void>`               |
| (other) | `(data, context) => void \| Promise<void>`               |

The `context` object has the same shape for every action:

| Field       | Type                 | Description                              |
| ----------- | -------------------- | ---------------------------------------- |
| `collector` | `Collector.Instance` | Active collector, use for `push`/`queue` |
| `logger`    | `Logger.Instance`    | Use for `info`/`warn`/`error`/`debug`    |

### run[​](#run "Direct link to run")

With each `run`, the on-event will be called. Use `context.collector` to access the running instance.

```
elb('walker on', {
type: 'run',
rules: function (_, context) {
console.log('run with', { instance: context.collector });
},
});
```

Every time the `run` command is called, the function will be executed:

```
// Setup collector with browser source
const { collector } = await startFlow({ run: true });
// Output: run with { instance: { ... } }
elb('walker run');
// Output: run with { instance: { ... } }
```

### consent[​](#consent-1 "Direct link to consent")

Every time the `consent` changes, the rules-matching function(s) will be called with `consent` as the first argument and `context` (carrying `collector` and `logger`) as the second.

```
function onConsent(consent, context) {
console.log('consent with', { consent, instance: context.collector });
if (consent.marketing) context.collector.push('walker user', readFromStorage());
}

elb('walker on', {
type: 'consent',
rules: { marketing: onConsent },
});
```

The `onConsent` function will only be called when the `marketing` consent changes:

```
elb('walker consent', { functional: true }); // Won't trigger the onConsent function
elb('walker consent', { marketing: true }); // Will trigger the onConsent function
```

## user[​](#user "Direct link to user")

Set user identification data for the collector. There are three levels: user (company's internal ID), device (longer-term identifier), and session (temporary identification).

```
elb('walker user', { id: 'us3r', device: 'c00k13', session: 's3ss10n' });
```

User IDs are added to each event.

```
{
"event": "entity action",
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
}
// other properties omitted
}
```

warning

Use fully anonymized & arbitrary IDs by default and check your options with persistent user IDs with your data protection officer.

tip

Learn more about identification and [user stitching](https://www.walkeros.io/docs/guides/user-stitching.md)

You can also set user identity declaratively from the DOM with the `data-elbuser` attribute. See the browser source's [HTML attributes](https://www.walkeros.io/docs/sources/web/browser/tagging/html-attributes.md#user).

## custom[​](#custom "Direct link to custom")

Set custom properties that are added to each event processed by the collector.

```
elb('walker custom', { key: 'value' });
```

## globals[​](#globals "Direct link to globals")

Set global properties that are added to each event processed by the collector.

```
elb('walker globals', { key: 'value' });
```

These values are the base for every event the collector processes, including events from server sources and any source with no DOM to read. A browser source adds what it finds in `data-elbglobals` on top, and those values win per key. Defaults that should survive a `walker run` belong in the collector's `globalsStatic` config instead: it seeds the base at startup, and a run that supplies its own globals resets the base to it. An event carries the globals known when it was created, so a global set after an event is captured does not reach one already waiting, whether it waits for consent, for a destination's `require` gate, or for a destination to be added at all.

A transformer that runs before the collector, in a source's `next` chain, sees the event before enrichment and therefore before the base globals are merged.

## State delivery[​](#state-delivery "Direct link to State delivery")

State commands (`consent`, `user`, `globals`, `custom`) set values on the collector. The collector records every state change immediately, even when it arrives before `run`. Side-effecting delivery to subscribers (the `on` callbacks above, and source `on` handlers) happens at or after `run`: when the collector starts, it delivers the current state once to every subscriber that has not yet seen it.

This gives three practical guarantees:

* **Exactly-once.** Each subscriber is invoked once per state change. The collector tracks what each subscriber has already received, so re-running or re-registering never double-fires a reaction.
* **Order-independent.** A consent-gated reaction fires correctly whether the state was set before or after `run`, and regardless of the order in which sources initialize. You don't have to set state and start the collector in a particular sequence.
* **`require` is a timing hint, not a correctness dependency.** A source's `require` only delays when its first `on` delivery lands. A dependent source reacts to state correctly whether or not it declares `require`.

This means sources don't need their own deduplication for state deliveries: the collector enforces exactly-once.

### Pre-run events[​](#pre-run-events "Direct link to Pre-run events")

The same record-immediately, deliver-at-run rule applies to events. An event pushed while the collector has not run yet is held in a bounded FIFO buffer instead of being discarded, and replayed once the collector starts:

```
const { collector, elb } = await startFlow({ run: false, destinations: { ... } });

await elb('walker consent', { essential: true });
await elb({ name: 'page view' }); // held, not delivered yet

await elb('walker run'); // 'page view' is delivered now
```

* **Replayed in push order.** Held events reach destinations in the order they were pushed, after the run-barrier state delivery, so each one carries the consent, user, globals and custom state that is current at `run`.
* **The pipeline runs once, at replay.** Mapping, transformer chains and enrichment are applied when the event is replayed, not when it is held.
* **Exactly-once.** A second `run` does not re-deliver events an earlier run already replayed.
* **Bounded.** The buffer holds at most `queueMax` events (default `1000`, shared with the destination replay buffer) and drops the oldest entries on overflow. Each hold and drop is logged at `debug` level.

Commands are unaffected: they continue to apply immediately, as described above.

## hook[​](#hook "Direct link to hook")

Hooks customize the default behavior of the collector. Available hooks include `Push`, `DestinationInit`, `DestinationPush`, `StoreGet`, `StoreSet`, and `StoreDelete`. Hooks allow for validation, manipulation, or cancellation of default behavior.

Add hooks to the collector to customize or enhance default processing.

```
elb('walker hook', { name: '<moment>', fn: hookFn });
```

### Moments[​](#moments "Direct link to Moments")

The overall function execution order is as follows:

1. prePush
2. preDestinationInit
3. postDestinationInit
4. preDestinationPush or preDestinationPushBatch
5. postDestinationPush or postDestinationPushBatch
6. postPush

Others are:

* preSessionStart
* postSessionStart
* preStoreGet / postStoreGet
* preStoreSet / postStoreSet
* preStoreDelete / postStoreDelete

### Function signatures[​](#function-signatures "Direct link to Function signatures")

In general, `params` will be prefixed as a parameter, containing `fn` which is the original function and `result` for the post-hooks. Use the following function signatures:

```
// Push
function prePush(params, event, data, options, context, nested) {
return params.fn(event, data, options, context, nested);
}
function postPush(params, event, data, trigger, context, nested) {
console.log('default return result', params.result);
return;
}

// DestinationInit
function preDestinationInit(params, config) {
return params.fn(config);
}
function postDestinationInit(params, config) {
console.log('default return result', params.result);
return params.result;
}

// DestinationPush
function preDestinationPush(params, event, config, mapping, runState) {
console.log('default return result', params.result);
return params.fn(event, config, mapping, runState);
}
function postDestinationPush(params) {
// Custom code with a void return
return;
}

// DestinationPushBatch
function preDestinationPushBatch(params, event, config, mapping, runState) {
console.log('default return result', params.result);
return params.fn(event, config, mapping, runState);
}
function postDestinationPushBatch(params) {
// Custom code with a void return
return;
}

// StoreGet
function preStoreGet(params, key) {
return params.fn(key);
}
function postStoreGet(params, key) {
return params.result;
}

// StoreSet
function preStoreSet(params, key, value, ttl) {
return params.fn(key, value, ttl);
}
function postStoreSet(params, key, value, ttl) {
return params.result;
}

// StoreDelete
function preStoreDelete(params, key) {
return params.fn(key);
}
function postStoreDelete(params, key) {
return params.result;
}
```

### Adding a hook[​](#adding-a-hook "Direct link to Adding a hook")

Add hooks during collector initialization or via the `hook` command:

```
// Add hooks during initialization
const { collector } = await startFlow({
hooks: {
prePush: (params, ...args) => {
window.elbTimer = Date.now();
return params.fn(...args);
},
},
});

// Add hooks via command
elb('walker hook', {
name: 'postPush',
fn: function (params, ...args) {
console.log('walker exec time', Date.now() - window.elbTimer);
},
});

elb('entity action');

// Output:
// walker exec time 1
```
