Integrated mode
In Integrated mode, walkerOS lives inside your application code. You configure it with TypeScript, and it deploys as part of your app bundle.
Quickstart
1. Install the collector
npm install @walkeros/collector2. Send your first event
import { startFlow } from '@walkeros/collector';
const { elb } = await startFlow({
destinations: {
console: {
code: {
type: 'console',
config: {},
push: (event) => console.log('Event:', event.name),
},
},
},
});
await elb({ name: 'page view', data: { title: 'Home' } });
// -> logs: Event: page viewThat's it. You just sent your first event and saw it in the console.
Adding destinations
Install the browser source and the destination packages, then add them to your config:
npm install @walkeros/web-source-browser @walkeros/web-destination-api @walkeros/web-destination-gtagimport { startFlow } from '@walkeros/collector';
import { sourceBrowser } from '@walkeros/web-source-browser';
import { destinationAPI } from '@walkeros/web-destination-api';
import { destinationGtag } from '@walkeros/web-destination-gtag';
const { elb } = await startFlow({
sources: {
browser: {
code: sourceBrowser,
config: {
settings: { pageview: true },
},
},
},
destinations: {
// Send to your API
api: {
code: destinationAPI,
config: {
settings: { url: 'https://your-api.com/events' },
},
},
// Send to Google Analytics 4
ga4: {
code: destinationGtag,
config: {
settings: {
ga4: { measurementId: 'G-XXXXXXXXXX' },
},
},
},
},
});Adding consent
Add consent requirements to control which destinations receive events:
const { elb } = await startFlow({
sources: {
browser: {
code: sourceBrowser,
config: { settings: { pageview: true } },
},
},
destinations: {
api: {
code: destinationAPI,
config: {
settings: { url: 'https://your-api.com/events' },
consent: { functional: true }, // Requires functional consent
},
},
ga4: {
code: destinationGtag,
config: {
settings: { ga4: { measurementId: 'G-XXXXXXXXXX' } },
consent: { analytics: true }, // Requires analytics consent
},
},
},
});
// When user accepts consent
elb('walker consent', { functional: true, analytics: true });Until a destination's required consent is granted, its events wait in an in-memory queue and are delivered once walker consent grants it. The queue holds up to 1000 events per destination by default; when it is full, the oldest events are dropped. Change the limit with config.queueMax on the destination, see buffer bounds.
Key concepts
The code: Property
In Integrated mode, you pass actual code references:
sources: {
browser: {
code: sourceBrowser, // Direct import, not a string
},
},
This differs from Bundled mode where you use package: with a string reference.
The elb function
startFlow() returns elb. Pass it a partial event: name is required, and
the collector adds the rest, such as id, timestamp and source.
const { elb } = await startFlow({ ... });
const result = await elb({
name: 'product add',
data: { id: 'abc', name: 'Widget', price: 29.99 },
});
if (!result.ok) console.error(result.error);
result.done lists the destinations that received the event, result.queued
those waiting for consent, and result.failed those whose push failed. The
event model lists the fields
a partial event takes and what the collector adds.
Type safety
Each step is typed by the package you pass as code. Its settings, the
settings of its mapping rules and its env keys autocomplete, and a setting
the package does not have is a type error:
import { startFlow } from '@walkeros/collector';
import { sourceBrowser } from '@walkeros/web-source-browser';
import { destinationGtag } from '@walkeros/web-destination-gtag';
const { elb } = await startFlow({
sources: {
browser: {
code: sourceBrowser,
config: { settings: { pageview: true, prefix: 'data-elb' } },
},
},
destinations: {
gtag: {
code: destinationGtag,
config: {
// `measurementID` instead of `measurementId` would be a type error
settings: { ga4: { measurementId: 'G-XXXXXXXXXX' } },
mapping: {
order: { complete: { name: 'purchase', settings: { ga4: {} } } },
},
},
},
},
});
Write the config inline in the startFlow call. A config kept in a separate
variable still compiles and is checked, but not for unknown keys. To declare a
config on its own, annotate it as Collector.InitConfig; its settings then stay
unchecked. An explicit type argument such as startFlow<WalkerOS.Elb>(...)
turns the checking off for the whole call.
Framework examples
- React
- Next.js
// hooks/useWalker.ts
import { useEffect, useState } from 'react';
import { startFlow } from '@walkeros/collector';
import { sourceBrowser } from '@walkeros/web-source-browser';
import type { WalkerOS } from '@walkeros/core';
export function useWalker() {
const [elb, setElb] = useState<WalkerOS.Elb | null>(null);
useEffect(() => {
startFlow({
sources: {
browser: { code: sourceBrowser, config: { settings: { pageview: true } } },
},
}).then(({ elb }) => setElb(() => elb));
}, []);
return elb;
}
// app/providers.tsx
'use client';
import { useEffect } from 'react';
import { startFlow } from '@walkeros/collector';
import { sourceBrowser } from '@walkeros/web-source-browser';
export function WalkerProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
startFlow({
sources: {
browser: { code: sourceBrowser, config: { settings: { pageview: true } } },
},
});
}, []);
return <>{children}</>;
}
See your event
The basic setup above logs every event it receives. Run it (Node, or your app's dev server) and push an event:
await elb({ name: 'page view', data: { title: 'Home' } });
// -> logs: Event: page viewIntegrated mode verifies where it runs: in your console. For an offline CLI test loop with mocked destinations, use bundled mode.
Observe a running flow
The console loop above is local. To watch a running flow's events live, add
the public connect pair to startFlow once:
const { elb } = await startFlow({
// Both values are public and safe to commit
observe: { url: 'https://observer.example.com', binding: 'pb_x' },
// ...your sources and destinations
});Nothing is sent yet: the per-session credential arrives out-of-band as a
?elbObserve= URL parameter, so committed code never contains a secret. On
the server, read the connect config from the environment instead:
import { observeFromEnv } from '@walkeros/core';
const { elb } = await startFlow({
observe: observeFromEnv(process.env),
// ...your sources and destinations
});See Observe for the full setup, the environment variables, and the credential lifecycle.
Next steps
- Event Model: How events are structured
- Mapping: Transform events for destinations
- Browser Source: DOM-based automatic tracking
- Destinations: Available destination packages
See also
- Bundled mode: Configure with JSON, build with CLI
- Collector reference: Full
startFlow()API documentation