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

<!-- -->

[Source code](https://github.com/elbwalker/walkerOS/tree/main/packages/web/sources/session)[ ](https://www.npmjs.com/package/@walkeros/web-source-session)

<!-- -->

[Package](https://www.npmjs.com/package/@walkeros/web-source-session)

# Session source

Standalone session detection and management that can be composed with any walkerOS source.

## Installation[​](#installation "Direct link to Installation")

* Integrated
* Bundled

Install the packages:

```
npm install @walkeros/collector @walkeros/web-source-session
```

Configure in your code:

```
import { startFlow } from '@walkeros/collector';
import { sourceBrowser } from '@walkeros/web-source-browser';
import { sourceSession } from '@walkeros/web-source-session';

const { collector, elb } = await startFlow({
  sources: {
    browser: sourceBrowser,
    session: {
      code: sourceSession,
      config: {
        settings: {
          storage: true,
        },
      },
    },
  },
});
```

Add to your `flow.json` sources:

```
"sources": {
  "browser": {
    "package": "@walkeros/web-source-browser"
  },
  "session": {
    "package": "@walkeros/web-source-session",
    "config": {
      "settings": {
        "storage": true
      }
    }
  }
}
```

[See Bundled Mode setup →](https://www.walkeros.io/docs/getting-started/modes/bundled.md) | [CLI reference →](https://www.walkeros.io/docs/apps/cli.md)

## Detection methods[​](#detection-methods "Direct link to Detection methods")

The session source uses two complementary methods:

| Method      | Storage      | Use Case                        |
| ----------- | ------------ | ------------------------------- |
| **Window**  | None         | Privacy-first, per-page session |
| **Storage** | localStorage | Cross-page session tracking     |

### Window-based detection[​](#window-based-detection "Direct link to Window-based detection")

Without storage, session detection relies on browser signals:

**Navigation type:**

```
// Session starts when navigation type indicates new visit
const isNewSession =
  performance.navigation.type === 0 || // Navigate (new page load)
  document.referrer === '' ||          // No referrer (direct visit)
  !isSameHost(document.referrer);      // External referrer
```

**Marketing parameters:**

UTM and other marketing parameters trigger session start. The following are recognized by default:

```
// UTM parameters → mapped to short names
utm_source    → source
utm_medium    → medium
utm_campaign  → campaign
utm_term      → term
utm_content   → content

// Click IDs → stored as clickId + original key
gclid, dclid, fbclid, msclkid, ttclid, twclid, igshid, sclid
```

To capture additional URL parameters, pass a `parameters` map. Each entry maps a URL parameter name to the property name it should be stored as in the session data:

```
session: {
  code: sourceSession,
  config: {
    settings: { storage: true },
    parameters: {
      ref: 'referral',           // ?ref=newsletter → { referral: 'newsletter' }
      affiliate_id: 'affiliate', // ?affiliate_id=abc → { affiliate: 'abc' }
    },
  },
}
```

### Storage-based detection[​](#storage-based-detection "Direct link to Storage-based detection")

With `storage: true`, sessions persist across page loads:

```
session: {
  code: sourceSession,
  config: {
    settings: {
      storage: true,
      length: 30, // Session timeout in minutes
    },
  },
}
```

**Session lifecycle:**

```
┌─────────────────────────────────────────────────────────────┐

│                    Session Timeline                         │

├─────────────────────────────────────────────────────────────┤

│                                                             │

│  User visits    Page 2       Page 3       30min idle       │

│       │            │            │              │            │

│       ▼            ▼            ▼              ▼            │

│   [Session 1] ─────────────────────────────► [Expires]     │

│   id: abc123                                                │

│                                                             │

│                                          User returns       │

│                                               │             │

│                                               ▼             │

│                                         [Session 2]        │

│                                         id: def456         │

└─────────────────────────────────────────────────────────────┘
```

**Storage settings:**

| Setting          | Default        | Description                                                                            |
| ---------------- | -------------- | -------------------------------------------------------------------------------------- |
| `sessionKey`     | `elbSessionId` | Storage key for the session ID                                                         |
| `deviceKey`      | `elbDeviceId`  | Storage key for the device ID                                                          |
| `sessionStorage` | `local`        | Storage type for the session ID (`local`, `session`, `cookie`)                         |
| `deviceStorage`  | `local`        | Storage type for the device ID (`local`, `session`, `cookie`)                          |
| `domain`         |                | Cookie domain, e.g. `example.com` to share IDs across subdomains (cookie storage only) |

## Session start event[​](#session-start-event "Direct link to Session start event")

When a new session is detected, the source pushes a `session start` event and sets the user's session and device IDs on the collector:

```
{
  name: 'session start',
  data: {
    isStart: true,           // Always true when this event fires
    isNew: true,             // True only on the device's very first session
    id: 'abc123',            // Session ID
    device: 'xyz789',        // Device ID (storage mode only)
    storage: true,           // Whether storage is active
    count: 5,                // Total session count for this device
    runs: 1,                 // Page views in this session
    start: 1704067200,       // Session start timestamp
    referrer: 'google.com',  // Hostname only (not full URL)
    marketing: {
      source: 'google',
      medium: 'cpc',
      campaign: 'winter-sale',
      clickId: 'gclid',      // Which click ID platform (if present)
      gclid: 'AW-123...',    // The actual click ID value
    }
  }
}
```

**`isStart` vs `isNew`:**

| Field           | Meaning                                                          |
| --------------- | ---------------------------------------------------------------- |
| `isStart: true` | A new session began on this page load                            |
| `isNew: true`   | This is the device's very first session ever (storage mode only) |

A returning visitor starting their second session has `isStart: true` but `isNew: false`. `isNew` only appears in storage mode since window-only mode has no device memory.

**Click ID parameters** are stored twice: `clickId` identifies which platform originated the click (e.g. `'gclid'`), and a separate field stores the actual value (e.g. `gclid: 'AW-123...'`). This makes it easy to filter by platform without inspecting the value.

## Configuration[​](#configuration "Direct link to Configuration")

This <!-- -->source<!-- --> uses the standard <!-- -->source<!-- --> config wrapper (consent, data, env, id, ...). For the shared fields see [source<!-- --> configuration](https://www.walkeros.io/docs/sources.md#configuration). Package-specific fields live under `config.settings` and are listed below.

## Settings[​](#settings "Direct link to Settings")

| Property         | Type                               | Description                                                                                                                                                   | More |
| ---------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| `storage`        | `boolean`                          | Enable persistent storage for session/device IDs                                                                                                              |      |
| `consent`        | `string \| array`                  | Consent key(s) required to enable storage mode                                                                                                                |      |
| `length`         | `number`                           | Session timeout in minutes                                                                                                                                    |      |
| `pulse`          | `boolean`                          | Keep session alive on each event                                                                                                                              |      |
| `sessionKey`     | `string`                           | Storage key for session ID                                                                                                                                    |      |
| `sessionStorage` | `'local' \| 'session' \| 'cookie'` | Storage type for session                                                                                                                                      |      |
| `deviceKey`      | `string`                           | Storage key for device ID                                                                                                                                     |      |
| `deviceStorage`  | `'local' \| 'session' \| 'cookie'` | Storage type for device                                                                                                                                       |      |
| `deviceAge`      | `number`                           | Device ID age in days                                                                                                                                         |      |
| `domain`         | `string`                           | Cookie domain for session and device IDs, e.g. 'example.com' to share across subdomains (cookie storage only)                                                 |      |
| `cb`             | `function`                         | Custom session callback function or false to disable                                                                                                          |      |
| `clickIds`       | `Array<object>`                    | Custom click-ID registry. Entries with a \`param\` matching a default override the platform name in place; new params append to the end of the priority list. |      |

## Mapping[​](#mapping "Direct link to Mapping")

This package does not define custom rule-level settings. For the standard rule fields (consent, condition, data, batch, name, policy) see [mapping](https://www.walkeros.io/docs/mapping.md).

## Examples

### New marketing session

A visit with UTM parameters starts a new session and emits walker user, session, and session start calls.

Event

```
{
  "storage": true
}
```

Out

```
elb("user", {
  "session": "s3ss10n-id",
  "device": "d3v1c3-id"
});

elb("session", {
  "id": "s3ss10n-id",
  "start": 1700000000000,
  "isNew": true,
  "count": 1,
  "runs": 1,
  "marketing": true,
  "source": "google",
  "medium": "cpc",
  "campaign": "winter-sale",
  "referrer": "",
  "device": "d3v1c3-id",
  "isStart": true,
  "storage": true,
  "updated": 1700000000000
});

elb({
  "name": "session start",
  "data": {
    "id": "s3ss10n-id",
    "start": 1700000000000,
    "isNew": true,
    "count": 1,
    "runs": 1,
    "marketing": true,
    "source": "google",
    "medium": "cpc",
    "campaign": "winter-sale",
    "referrer": "",
    "device": "d3v1c3-id",
    "isStart": true,
    "storage": true,
    "updated": 1700000000000
  }
})
```

### Returning visitor

A returning visit with a google referrer reuses the stored device id and increments the session count.

Event

```
{
  "storage": true
}
```

Out

```
elb("user", {
  "session": "n3w-s3ss10n",
  "device": "d3v1c3-id"
});

elb("session", {
  "id": "n3w-s3ss10n",
  "start": 1700001000000,
  "isNew": false,
  "count": 3,
  "runs": 1,
  "referrer": "google.com",
  "device": "d3v1c3-id",
  "isStart": true,
  "storage": true,
  "updated": 1700001000000
});

elb({
  "name": "session start",
  "data": {
    "id": "n3w-s3ss10n",
    "start": 1700001000000,
    "isNew": false,
    "count": 3,
    "runs": 1,
    "referrer": "google.com",
    "device": "d3v1c3-id",
    "isStart": true,
    "storage": true,
    "updated": 1700001000000
  }
})
```

## Consent integration[​](#consent-integration "Direct link to Consent integration")

Session detection adapts to consent state:

| Consent State   | Behavior                           |
| --------------- | ---------------------------------- |
| No consent      | Window-only detection (no storage) |
| Consent granted | Storage-based with device ID       |
| Consent revoked | Falls back to window-only          |

```
// Configure consent requirement
session: {
  code: sourceSession,
  config: {
    settings: {
      consent: 'analytics', // Wait for this consent key
      storage: true,
    },
  },
}

// Grant consent to enable storage
elb('walker consent', { analytics: true });
```

## Pulse mode[​](#pulse-mode "Direct link to Pulse mode")

With `pulse: true`, the source updates the session's last-seen timestamp on each page load without counting it as a new page view and without triggering a new `session start` event. Use this for heartbeat-style presence tracking where you want to extend session lifetime without inflating `runs`:

```
session: {
  code: sourceSession,
  config: {
    settings: {
      storage: true,
      pulse: true,  // Extends session, does not increment runs
    },
  },
}
```

## Custom session callback[​](#custom-session-callback "Direct link to Custom session callback")

The `cb` setting lets you hook into session detection. It receives the detected session data, the collector instance, and the default callback:

```
session: {
  code: sourceSession,
  config: {
    settings: {
      cb: (session, collector, defaultCb) => {
        // Run custom logic first
        console.log('New session:', session.id);

        // Then run the default behavior (sets user IDs + pushes event)
        defaultCb(session, collector);
      },
    },
  },
}
```

Set `cb: false` to completely disable the default behavior. No `user` commands and no `session start` event will be emitted. This is useful when you want full control over what happens after detection.

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

* [Browser Source](https://www.walkeros.io/docs/sources/web/browser.md) - DOM-based event tracking
* [DataLayer Source](https://www.walkeros.io/docs/sources/web/dataLayer.md) - GTM/GA4 integration
* [Consent Guide](https://www.walkeros.io/docs/guides/consent.md) - Consent management patterns
