Skip to main content
Ask your AI

Step examples

Add examples to any step in your flow config to document what it expects and produces:

"examples": {
"purchase": {
"in": { "name": "order complete", "data": { "id": "ORD-123", "total": 149.97 } },
"mapping": { "name": "purchase", "data": { "map": { "transaction_id": "data.id", "value": "data.total" } } },
"out": ["event", "purchase", { "transaction_id": "ORD-123", "value": 149.97 }]
}
}

Examples are test fixtures, documentation, and simulation data in one place. They live in your flow config, get stripped at build time, and have zero runtime impact.

What are step examples

Every source, transformer, and destination in a walkerOS flow is a step. Each step receives input and produces output. Step examples are named { in, out } pairs that capture concrete data for each step: what goes in, what comes out.

They serve multiple purposes simultaneously:

  • Documentation: developers see real data shapes, not just type signatures
  • Testing: your tests use examples as fixtures, and walkeros validate checks that connected steps have compatible examples
  • Simulation: debug your pipeline before deployment
  • LLM context: AI tools use examples to suggest correct mappings

The { in, out } format

Each example has a human-readable name and two fields:

{
  "examples": {
    "page view": {
      "in": {
        "name": "page view",
        "data": { "title": "Home", "path": "/" }
      },
      "out": ["event", "page_view", { "page_title": "Home" }]
    },
    "purchase": {
      "in": {
        "name": "order complete",
        "data": { "id": "ORD-123", "total": 149.97, "currency": "EUR" }
      },
      "mapping": {
        "name": "purchase",
        "data": {
          "map": {
            "transaction_id": "data.id",
            "value": "data.total",
            "currency": "data.currency"
          }
        }
      },
      "out": ["event", "purchase", {
        "transaction_id": "ORD-123",
        "value": 149.97,
        "currency": "EUR"
      }]
    }
  }
}
FieldTypeDescription
inanyThe data the step receives
mappingobjectThe mapping rule applied to this event (destinations only)
outanyThe data the step produces
out: falsefalseThe step rejects or filters this event
commandstringRoute in through a walker command instead of pushing it as an event (config, consent, user, run)

For destinations, the optional mapping field captures the mapping rule that transforms the walkerOS event into the vendor-specific output. This ties the example to a specific mapping configuration, so tests and simulations can register it dynamically as { [entity]: { [action]: example.mapping } }.

Command examples

Some destinations need to react to walker commands (consent updates, user identification, run state) rather than events. Set the command field on a step example so the test runner invokes elb('walker <command>', in) instead of pushing in as a regular event:

{
  "command": "consent",
  "in": { "marketing": true, "functional": true },
  "out": ["consent", "update", { "ad_storage": "granted", "analytics_storage": "granted" }]
}

Supported commands: `config`, `consent`, `user`, `run`. When command is set, mapping is ignored, because commands don't flow through event mapping. See the walkeros-using-step-examples skill for the full test-runner pattern.

You can add as many named examples as you need. Tests refer to each example by its name, and the MCP flow_examples tool lists them by name for each step.

Three type zones

A walkerOS flow has three distinct type zones. The shape of in and out depends on where the step sits:

ARBITRARY walkerOS.Event ARBITRARY
┌─────────┐ ┌──────────────────────┐ ┌──────────────┐
│ Source │ → │ Collector → Transform │ → │ Destination │
│ ingest │ │ → ... → Transform │ │ output │
└─────────┘ └──────────────────────┘ └──────────────┘
package- known structure, package-
specific varying properties specific
  • Source in: raw HTTP request body, DOM event, dataLayer push (package-specific)
  • Source out through destination in: walkerOS.Event (known structure, varying properties)
  • Destination out: gtag() args, fbq() args, HTTP POST body (vendor-specific)

Transformers that filter events use out: false to indicate rejection.

Adding examples to a flow

Here is a complete flow config with examples on a source, transformer, and destination:

{
  "version": 4,
  "flows": {
    "default": {
      "config": { "platform": "server" },
      "sources": {
        "http": {
          "package": "@walkeros/server-source-express",
          "config": { "settings": { "port": 8080 } },
          "examples": {
            "page view": {
              "in": {
                "method": "POST",
                "body": { "name": "page view", "data": { "title": "Home" } }
              },
              "out": { "name": "page view", "data": { "title": "Home" } }
            }
          }
        }
      },
      "transformers": {
        "fingerprint": {
          "package": "@walkeros/server-transformer-fingerprint",
          "examples": {
            "enriched event": {
              "in": { "name": "page view", "data": { "title": "Home" } },
              "out": { "name": "page view", "data": { "title": "Home" } }
            }
          }
        }
      },
      "destinations": {
        "ga4": {
          "package": "@walkeros/web-destination-gtag",
          "config": {
            "settings": { "measurementId": "G-DEMO123456" }
          },
          "examples": {
            "page view": {
              "in": { "name": "page view", "data": { "title": "Home" } },
              "mapping": {
                "name": "page_view",
                "data": { "map": { "page_title": "data.title" } }
              },
              "out": ["event", "page_view", { "page_title": "Home" }]
            }
          }
        }
      },
      "collector": {}
    }
  }
}

Examples are stripped by the bundler at build time. They never appear in your production bundle.

Using examples with the CLI

Simulate a step with an example's input

Push an event through one step with its external calls mocked. --event takes the input itself, so pass an example's in value:

# Push the "page view" example's in value through the ga4 destination
walkeros push flow.json --simulate destination.ga4 --event '{"name":"page view","data":{"title":"Home"}}'

The CLI does not read examples here and does not compare anything against out. It reports whether the push succeeded and how long it took, and exits with code 1 only when the push fails with an error. A mapping that produces the wrong output still exits 0. To assert on out, run the examples in your own tests (see Using examples in tests).

Validate examples

walkeros validate checks examples statically. It does not run any step:

walkeros validate flow.json

For steps connected through next (source to transformer, transformer to transformer) or a destination's before chain, it checks that at least one out of the upstream step is structurally compatible with an in of the downstream step. Both values must have the same type. Two objects are compatible when they share at least half of the keys of the object with fewer keys; any two arrays are compatible regardless of their content. This is a shape check, not an equality check.

  • No compatible pair is an error.
  • A connection is only checked when both steps declare examples. If either step has no examples key, nothing is checked and no warning is produced.
  • When both steps declare examples but one side has no usable value, the connection produces a warning. An upstream out counts when it is a non-empty array, string, or object (such as a walkerOS event); out: false and empty values are skipped. A downstream in counts unless its example sets command.
  • Steps without next or before are not checked.
  • When the config defines a contract, each destination and transformer example in that carries entity and action is validated against it. Violations are warnings, or errors with --strict.

Using examples in tests

Extract examples from your flow config and use them as test fixtures:

import { readFileSync } from 'fs';
import { push } from '@walkeros/web-destination-gtag';

const flow = JSON.parse(readFileSync('flow.json', 'utf-8'));
const ga4Examples = flow.flows.default.destinations.ga4.examples;

const cases = Object.entries(ga4Examples).map(
  ([name, ex]) => [name, ex.in, ex.out]
);

it.each(cases)('ga4 destination: %s', (name, input, expected) => {
  const result = push(input);
  expect(result).toEqual(expected);
});

This pattern means your flow config is the single source of truth for both documentation and tests.

Package-level vs flow-level examples

Examples exist at two levels:

LevelWherePurpose
PackagewalkerOS.json in the npm package (via dev.ts)Generic examples showing what the package handles
FlowInline on step references in flow.jsonSpecific examples for your actual data and mappings

Package examples are generic and ship with the npm package. They show the package's capabilities with sample data. The CLI and MCP tools discover them from CDN.

Flow examples are specific to your setup. They use your real event names, your actual data properties, and your configured mappings. They override or complement package examples.

How packages ship examples

Packages export examples through the dev.ts convention:

// src/dev.ts
export * as schemas from './schemas';
export * as examples from './examples';

These are included in the package's walkerOS.json metadata and discoverable via CDN, following the same { in, out } format used in flow configs.

Next steps

  • CLI: Bundle and simulate flows with examples
  • Flow: Learn the full flow configuration format
  • Mapping: Transform events between steps
  • Event model: Understand the walkerOS event structure
💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)