Skip to main content

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.

// Correct
'page view';
'product add';
'order complete';
'button click';

// Wrong
'page_view'; // underscore
'pageview'; // no separator
'purchase'; // no entity
'add_to_cart'; // wrong format

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).

PropertyTypePurposeExample
namestring"entity action" format"product view"
dataobjectEntity-specific properties{ id: "P123", price: 99 }
contextobjectState/environment info (optional){ stage: ["checkout", 1] }
globalsobjectGlobal properties{ language: "en" }
userobjectUser identification{ id: "user123" }
nestedarrayRelated entities (optional)[{ entity: "product", data: {...} }]
consentobjectConsent states{ marketing: true }
idstringW3C span_id, 16 lowercase hex chars, generated by collector"0123456789abcdef"
timestampnumberAuto-generated Unix ms1647261462000
entitystringParsed from name"product"
actionstringParsed from name"view"
source.typestringSource kind (browser, dataLayer, cookiefirst, ...)"browser"
source.platformstringRuntime platform (web, server)"web"
source.schemastringSource-emitted schema/version (optional)"datalayer-v2"
source.tracestringRun-scoped W3C trace_id, shared by every event of a run"0123...cdef" (32 hex)
source.countnumberPer-run emission sequence (1, 2, 3, ...)1
source.releaseobjectPer-flow config release map, accumulates across crossings{ web: "3", server: "5" }

data Property

Entity-specific properties. Schema-free but consistent within entity type.

// product entity
data: { id: "P123", name: "Laptop", price: 999, currency: "USD" }

// page entity
data: { title: "Home", path: "/", referrer: "https://..." }

context Property

Hierarchical state information. Format: { name: [value, order] }. Optional.

context: {
stage: ["checkout", 1], // checkout stage, first step
test: ["variant-A", 0], // A/B test variant
group: ["premium", 2] // user segment
}

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.

// Order with line items
nested: [
{ entity: 'product', data: { id: 'P1', quantity: 2 } },
{ entity: 'product', data: { id: 'P2', quantity: 1 } },
];

user Property

User identification across sessions.

user: {
id: "user123", // Your user ID
device: "device456", // Device fingerprint
session: "sess789" // Session ID
}

source Property

Where the event came from. The collector enriches the event with source data based on which source emitted it.

source: {
type: 'browser', // source kind (browser, dataLayer, cookiefirst, ...)
platform: 'web', // runtime: 'web' or 'server'
version: '4.0.0', // external source-emitter version (collector no longer sets this)
schema: 'datalayer-v2', // optional schema/version emitted by the source
trace: '0123...cdef', // run-scoped W3C trace_id, groups all events of a run
count: 1, // per-run emission sequence (1, 2, 3, ...)
release: { web: '3' }, // per-flow config release map, accumulates web to server
url: 'https://...', // page URL (web only, set by web-context transformer)
referrer: '...', // page referrer (web only)
tool: 'cli', // tool that produced the event (optional)
command: 'simulate', // command name (optional)
}

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:

v3v4
event.id = "<ts>-<rnd>-<seq>"event.id = W3C span_id (16 lowercase hex chars)
event.versionremoved - see source.version and source.schema
event.groupremoved - use source.trace (run-scoped trace_id) for correlation
event.countremoved - use source.count (per-run emission sequence)
event.source.idevent.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';

// Basic event
await elb('page view', { title: 'Home', path: '/' });

// With all properties
await elb(
'product add',
{ id: 'P123', price: 99 }, // data
{ stage: ['cart', 1] }, // context (optional)
{ currency: 'USD' }, // globals (optional)
);

Source Files:

Documentation:

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