Create Your Own Source
A source captures events from an environment (browser, server, third-party API) and forwards them to the walkerOS collector.
The source interface
Sources are async functions that receive a context object and return a source instance:
The context contains:
The returned instance must implement:
Types bundle
Sources use a Types interface to bundle all TypeScript types:
The 4 type parameters:
- Settings: Source configuration options
- Mapping: Event mapping (usually
neverfor sources) - Push: External push signature (what
source.pushexposes) - Env: Internal dependencies (what source calls via
env.elb)
Context destructuring
The context parameter contains everything your source needs:
The collector provides env.push (formerly env.elb). You provide other dependencies (like window, document, custom APIs) when configuring the source.
Minimal example
Complete example: Event API source
Capturing events from a third-party API with event listeners:
Using your source
Testing your source
Test Utilities
Test Example
Conditional activation with require
Sources can declare dependencies on collector events. A source with require won't initialize until all specified events have fired:
How it works:
- Sources with
requireare stored incollector.pendinginstead of initializing - After each collector event (
consent,user,session,run, etc.), pending sources are checked - When all required events have fired, the source initializes
- Chains work naturally:
consentactivates session source, which firesuser, which activates dataLayer
Common patterns:
| Require | Use case |
|---|---|
['consent'] | Wait for CMP consent before tracking |
['user'] | Wait for identity resolution |
['session'] | Wait for session detection |
['consent', 'run'] | Wait for both consent and collector run |
Common patterns
Polling for API Readiness
When the external API isn't immediately available:
Source as adapter pattern
Sources bridge external systems and the collector:
External System ←→ Source (Adapter) ←→ Collector
Two interfaces:
-
External (
source.push): Platform-specific signature- Browser:
push(elem, data, options)→ ReturnsPromise<PushResult> - Server:
push(req, res)→ ReturnsPromise<void>(writes HTTP response) - Your choice: Match your environment's needs
- Browser:
-
Internal (
env.elb): Standard collector interface- Always
Elb.Fn- same across all sources - Sources translate external inputs → standard events →
env.elb(event)
- Always
Example signatures:
The Push type parameter defines what your source exposes externally. Internally, all sources use env.elb to forward to the collector.
Key concepts
- Context pattern: Sources receive a single context object with config, env, logger, id
- Validate custom dependencies: Only check optional env properties your source needs
- Types bundle: Use 4-parameter pattern for full type safety
- Adapter pattern: External push adapts to environment, internal env.push stays standard
- Cleanup: Implement
destroy()to remove listeners - Stateless: Let collector manage state
Package convention
Every walkerOS package includes machine-readable metadata for tooling and discovery.
walkerOS field in package.json
| Field | Required | Description |
|---|---|---|
walkerOS | Yes | Object with type and platform metadata |
Build-time generation
Use buildDev() from the shared tsup config to auto-generate walkerOS.json:
This file contains your package's JSON Schemas and examples, enabling MCP tools and the CLI to validate configurations without installing your package.
Publishing checklist
-
walkerOSfield in package.json - Keywords include
walkerosandwalkeros-source -
buildDev()in tsup.config.ts -
dist/walkerOS.jsongenerated on build -
npm run testpasses -
npm run lintpasses
Next steps
- Review Browser Source for DOM patterns
- Review DataLayer Source for interception patterns
- Learn about creating destinations