> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

# 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[​](#quickstart "Direct link to Quickstart")

### 1. Install the collector[​](#1-install-the-collector "Direct link to 1. Install the collector")

```bash
npm install @walkeros/collector
```

### 2. Send your first event[​](#2-send-your-first-event "Direct link to 2. Send your first event")

```typescript
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 view
```

That's it. You just sent your first event and saw it in the console.

***

## Adding destinations[​](#adding-destinations "Direct link to Adding destinations")

Install the browser source and the destination packages, then add them to your config:

```bash
npm install @walkeros/web-source-browser @walkeros/web-destination-api @walkeros/web-destination-gtag
```

```typescript
import { 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[​](#adding-consent "Direct link to Adding consent")

Add consent requirements to control which destinations receive events:

```typescript
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](/preview/pr-749/docs/collector.md#buffer-bounds).

***

## Key concepts[​](#key-concepts "Direct link to Key concepts")

### The `code:` Property[​](#the-code-property "Direct link to 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[​](#the-elb-function "Direct link to 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](/preview/pr-749/docs/getting-started/event-model.md#push-an-event) lists the fields a partial event takes and what the collector adds.

### Type safety[​](#type-safety "Direct link to 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[​](#framework-examples "Direct link to 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[​](#see-your-event "Direct link to 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:

```typescript
await elb({ name: 'page view', data: { title: 'Home' } });
// -> logs: Event: page view
```

Integrated mode verifies where it runs: in your console. For an offline CLI test loop with mocked destinations, use [bundled mode](/preview/pr-749/docs/getting-started/modes/bundled.md#see-your-event).

***

## Observe a running flow[​](#observe-a-running-flow "Direct link to 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:

```typescript
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:

```typescript
import { observeFromEnv } from '@walkeros/core';

const { elb } = await startFlow({
  observe: observeFromEnv(process.env),
  // ...your sources and destinations
});
```

See [Observe](/preview/pr-749/docs/getting-started/observe.md) for the full setup, the environment variables, and the credential lifecycle.

***

## Next steps[​](#next-steps "Direct link to Next steps")

* [**Event Model**](/preview/pr-749/docs/getting-started/event-model.md): How events are structured
* [**Mapping**](/preview/pr-749/docs/mapping.md): Transform events for destinations
* [**Browser Source**](/preview/pr-749/docs/sources/web/browser.md): DOM-based automatic tracking
* [**Destinations**](/preview/pr-749/docs/destinations.md): Available destination packages

***

## See also[​](#see-also "Direct link to See also")

* [**Bundled mode**](/preview/pr-749/docs/getting-started/modes/bundled.md): Configure with JSON, build with CLI
* [**Collector reference**](/preview/pr-749/docs/collector.md): Full `startFlow()` API documentation
