| name | walkeros-understanding-events |
| description | Use when creating walkerOS events, understanding event structure, or working with event properties. Covers entity-action naming, event properties, statelessness, and vendor-agnostic design. |
Understanding walkerOS Events
Overview
walkerOS events are self-describing, stateless, vendor-agnostic data structures.
They capture user interactions in a standardized format that can be transformed
for any destination.
Core principle: Events describe WHAT happened, not WHERE it goes. Stateless.
Self-describing. Industry-agnostic.
Entity-Action Naming (Critical)
STRICT REQUIREMENT: All events use "entity action" format with space
separation.
'page view';
'product add';
'order complete';
'button click';
'page_view';
'pageview';
'purchase';
'add_to_cart';
Parsing: const [entity, action] = event.split(' ')
- Entity: Noun (page, product, user, order, button)
- Action: Verb (view, add, complete, click, login)
Event Properties
See
packages/core/src/types/walkeros.ts
for canonical types (Event interface, plus event helpers in event.ts).
| Property | Type | Purpose | Example |
|---|
name | string | "entity action" format | "product view" |
data | object | Entity-specific properties | { id: "P123", price: 99 } |
context | object | State/environment info (optional) | { stage: ["checkout", 1] } |
globals | object | Global properties | { language: "en" } |
user | object | User identification | { id: "user123" } |
nested | array | Related entities (optional) | [{ entity: "product", data: {...} }] |
consent | object | Consent states | { marketing: true } |
id | string | W3C span_id, 16 lowercase hex chars, generated by collector | "0123456789abcdef" |
timestamp | number | Auto-generated Unix ms | 1647261462000 |
entity | string | Parsed from name | "product" |
action | string | Parsed from name | "view" |
source.type | string | Source kind (browser, dataLayer, cookiefirst, ...) | "browser" |
source.platform | string | Runtime platform (web, server) | "web" |
source.schema | string | Source-emitted schema/version (optional) | "datalayer-v2" |
source.trace | string | Run-scoped W3C trace_id, shared by every event of a run | "0123...cdef" (32 hex) |
source.count | number | Per-run emission sequence (1, 2, 3, ...) | 1 |
source.release | object | Per-flow config release map, accumulates across crossings | { web: "3", server: "5" } |
data Property
Entity-specific properties. Schema-free but consistent within entity type.
data: { id: "P123", name: "Laptop", price: 999, currency: "USD" }
data: { title: "Home", path: "/", referrer: "https://..." }
context Property
Hierarchical state information. Format: { name: [value, order] }. Optional.
context: {
stage: ["checkout", 1],
test: ["variant-A", 0],
group: ["premium", 2]
}
globals Property
Properties that apply to ALL events in the session.
globals: {
language: "en",
currency: "USD",
environment: "production"
}
nested Property
Related entities captured together. Optional.
nested: [
{ entity: 'product', data: { id: 'P1', quantity: 2 } },
{ entity: 'product', data: { id: 'P2', quantity: 1 } },
];
user Property
User identification across sessions.
user: {
id: "user123",
device: "device456",
session: "sess789"
}
source Property
Where the event came from. The collector enriches the event with source data
based on which source emitted it.
source: {
type: 'browser',
platform: 'web',
version: '4.0.0',
schema: 'datalayer-v2',
trace: '0123...cdef',
count: 1,
release: { web: '3' },
url: 'https://...',
referrer: '...',
tool: 'cli',
command: 'simulate',
}
CMP and other non-page sources do NOT set source.url/source.referrer -
that's the responsibility of a web-context transformer.
source.trace is the run grouping key: the collector mints a fresh run-scoped
trace_id on each run and stamps it (plus a per-run source.count) on every
event when absent. It is preserved unchanged when an event is forwarded from web
to server, so the whole pipeline shares one trace.
source.release records which config handled the event, keyed by flow name.
Each flow the event passes through adds its own entry (that flow's config
release), so an event captured on the web and processed on the server carries
both flow releases, and a warehouse row shows exactly which config version
touched it. This is distinct from source.version, the source package version
set only by external source emitters (the collector no longer stamps it).
Migration from v3
If you have existing v3 events or configs, here is the v4 mapping:
| v3 | v4 |
|---|
event.id = "<ts>-<rnd>-<seq>" | event.id = W3C span_id (16 lowercase hex chars) |
event.version | removed - see source.version and source.schema |
event.group | removed - use source.trace (run-scoped trace_id) for correlation |
event.count | removed - use source.count (per-run emission sequence) |
event.source.id | event.source.url (when it meant page URL) |
nested: [{ type, data }] | nested: [{ entity, data }] (Entity.entity replaces .type) |
Design Principles
Statelessness
Events are immutable snapshots. They don't reference previous events or maintain
state.
Self-Describing
Events contain all context needed to understand them. No external lookups
required.
Vendor-Agnostic
Events use generic concepts (product, order) not vendor-specific (GA4 item, FB
content).
Transformation to vendor formats happens in mapping, not in event creation.
Creating Events
import { elb } from '@walkeros/collector';
await elb('page view', { title: 'Home', path: '/' });
await elb(
'product add',
{ id: 'P123', price: 99 },
{ stage: ['cart', 1] },
{ currency: 'USD' },
);
Related Skills
Source Files:
Documentation: