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

# Snowplow

<!-- -->

[Web](#)[ ](https://github.com/elbwalker/walkerOS/tree/main/packages/web/destinations/snowplow)

<!-- -->

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

<!-- -->

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

[Snowplow](https://snowplow.io/) is a behavioral data platform for collecting and routing event data. The destination sends events via the browser tracker, supporting both the npm `@snowplow/browser-tracker` and the JavaScript tracker (`sp.js`). walkerOS handles tracker initialization, plugin loading, activity tracking (page pings), and self-describing ecommerce events with context entities.

<!-- -->

Where this fits

Snowplow is a **web destination** in the walkerOS flow:

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

```
npm install @walkeros/web-destination-snowplow
```

The destination supports two tracking approaches:

* **JavaScript tag (sp.js)**: loads the Snowplow tracker script from CDN
* **npm packages**: uses `@snowplow/browser-tracker` for smaller bundles and tree-shaking

- JavaScript Tag (sp.js)
- NPM Packages (browser-tracker)

Loads the Snowplow tracker script automatically. Simple setup, works everywhere.

* Integrated
* Bundled

```
import { startFlow } from '@walkeros/collector';
import { destinationSnowplow } from '@walkeros/web-destination-snowplow';

const { elb } = await startFlow({
  destinations: {
    snowplow: {
      code: destinationSnowplow,
      config: {
        settings: {
          collectorUrl: 'https://collector.example.com',
          appId: 'my-app',
        },
        loadScript: true,
      },
    },
  },
});
```

```
{
  "destinations": {
    "snowplow": {
      "package": "@walkeros/web-destination-snowplow",
      "config": {
        "settings": {
          "collectorUrl": "https://collector.example.com",
          "appId": "my-app"
        },
        "loadScript": true
      }
    }
  }
}
```

Uses imported functions directly. Smaller bundles, tree-shaking, type-safe.

**Available packages and functions:**

| Package                                          | Functions                                                                                                                                                                            | Purpose                  |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------ |
| `@snowplow/browser-tracker`                      | `newTracker`, `trackSelfDescribingEvent`                                                                                                                                             | Core tracking (required) |
| `@snowplow/browser-tracker`                      | `trackPageView`, `trackStructEvent`, `setUserId`, `enableActivityTracking`, `addPlugin`, `addGlobalContexts`, `clearUserData`, `enableAnonymousTracking`, `disableAnonymousTracking` | Optional features        |
| `@snowplow/browser-plugin-snowplow-ecommerce`    | `SnowplowEcommercePlugin`, `setPageType`                                                                                                                                             | Ecommerce tracking       |
| `@snowplow/browser-plugin-link-click-tracking`   | `LinkClickTrackingPlugin`                                                                                                                                                            | Auto link tracking       |
| `@snowplow/browser-plugin-button-click-tracking` | `ButtonClickTrackingPlugin`                                                                                                                                                          | Auto button tracking     |
| `@snowplow/browser-plugin-enhanced-consent`      | `trackConsentAllow`, `trackConsentDeny`, `trackConsentSelected`                                                                                                                      | Consent tracking         |

* Integrated
* Bundled

```
import { startFlow } from '@walkeros/collector';
import { destinationSnowplow } from '@walkeros/web-destination-snowplow';
import {
  newTracker,
  trackSelfDescribingEvent,
  trackPageView,
  enableActivityTracking,
  addPlugin,
  addGlobalContexts,
} from '@snowplow/browser-tracker';
import { SnowplowEcommercePlugin, setPageType } from '@snowplow/browser-plugin-snowplow-ecommerce';
import { LinkClickTrackingPlugin } from '@snowplow/browser-plugin-link-click-tracking';

const { elb } = await startFlow({
  destinations: {
    snowplow: {
      code: destinationSnowplow,
      config: {
        settings: {
          tracker: {
            newTracker,
            trackSelfDescribingEvent,
            trackPageView,
            enableActivityTracking,
            addPlugin,
            addGlobalContexts,
            setPageType,
          },
          collectorUrl: 'https://collector.example.com',
          appId: 'my-app',
          plugins: [
            { code: SnowplowEcommercePlugin },
            { code: LinkClickTrackingPlugin, config: { trackContent: true } },
          ],
        },
      },
    },
  },
});
```

```
{
  "bundle": {
    "packages": {
      "@snowplow/browser-tracker": {
        "imports": [
          "newTracker",
          "trackSelfDescribingEvent",
          "trackPageView",
          "enableActivityTracking",
          "addPlugin",
          "addGlobalContexts"
        ]
      },
      "@snowplow/browser-plugin-snowplow-ecommerce": {
        "imports": ["SnowplowEcommercePlugin", "setPageType"]
      },
      "@snowplow/browser-plugin-link-click-tracking": {
        "imports": ["LinkClickTrackingPlugin"]
      }
    }
  },
  "destinations": {
    "snowplow": {
      "package": "@walkeros/web-destination-snowplow",
      "config": {
        "settings": {
          "tracker": {
            "newTracker": "$code:newTracker",
            "trackSelfDescribingEvent": "$code:trackSelfDescribingEvent",
            "trackPageView": "$code:trackPageView",
            "enableActivityTracking": "$code:enableActivityTracking",
            "addPlugin": "$code:addPlugin",
            "addGlobalContexts": "$code:addGlobalContexts",
            "setPageType": "$code:setPageType"
          },
          "collectorUrl": "https://collector.example.com",
          "appId": "my-app",
          "plugins": [
            { "code": "$code:SnowplowEcommercePlugin" },
            { "code": "$code:LinkClickTrackingPlugin", "config": { "trackContent": 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)

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

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

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

| Property              | Type                          | Description                                             | More |
| --------------------- | ----------------------------- | ------------------------------------------------------- | ---- |
| `collectorUrl`        | `string`                      | Snowplow collector endpoint URL                         |      |
| `appId`               | `string`                      | Application identifier                                  |      |
| `trackerName`         | `string`                      | Tracker instance name                                   |      |
| `platform`            | `string`                      | Platform identifier                                     |      |
| `pageViewTracking`    | `boolean`                     | Enable automatic page view tracking                     |      |
| `snowplow`            | `snowplow`                    | Snowplow-specific ecommerce configuration               |      |
| `actionSchema`        | `string`                      | Ecommerce action schema URI                             |      |
| `productSchema`       | `string`                      | Product entity schema URI                               |      |
| `cartSchema`          | `string`                      | Cart entity schema URI                                  |      |
| `transactionSchema`   | `string`                      | Transaction entity schema URI                           |      |
| `refundSchema`        | `string`                      | Refund entity schema URI                                |      |
| `checkoutStepSchema`  | `string`                      | Checkout step entity schema URI                         |      |
| `promotionSchema`     | `string`                      | Promotion entity schema URI                             |      |
| `userSchema`          | `string`                      | User entity schema URI                                  |      |
| `customSchemas`       | `Record<string, string>`      | Custom entity schemas                                   |      |
| `currency`            | `string`                      | Default currency code (ISO 4217)                        |      |
| `discoverRootDomain`  | `boolean`                     | Discover root domain for cookies                        |      |
| `cookieSameSite`      | `'Strict' \| 'Lax' \| 'None'` | Cookie SameSite attribute                               |      |
| `appVersion`          | `string`                      | Application version                                     |      |
| `contexts`            | `contexts`                    | Built-in context entities                               |      |
| `webPage`             | `boolean`                     | Web page context                                        |      |
| `session`             | `boolean`                     | Client session context - enables client\_session schema |      |
| `performanceTiming`   | `boolean`                     | Performance timing context                              |      |
| `geolocation`         | `boolean`                     | Geolocation context                                     |      |
| `anonymousTracking`   | `boolean \| object`           | Enable anonymous tracking (no user identifiers)         |      |
| `plugins`             | `Array<any>`                  | Snowplow plugins                                        |      |
| `activityTracking`    | `activityTracking`            | Page ping configuration                                 |      |
| `minimumVisitLength*` | `number`                      | Seconds before first ping                               |      |
| `heartbeatDelay*`     | `number`                      | Seconds between pings                                   |      |
| `globalContexts`      | `Array<any>`                  | Global context entities                                 |      |

\* Required fields

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

Per-event rules under `config.mapping`. For the standard rule fields (consent, condition, data, batch, name, policy) see [mapping](https://www.walkeros.io/docs/mapping.md).

| Property       | Type            | Description                                    | More |
| -------------- | --------------- | ---------------------------------------------- | ---- |
| `context`      | `Array<object>` | Context entities to attach to this event       |      |
| `snowplow`     | `snowplow`      | Snowplow-specific settings override            |      |
| `actionSchema` | `string`        | Override action schema for this specific event |      |

## Examples

### Add to cart

A product add fires a Snowplow ecommerce add\_to\_cart action with product, cart, page, and user contexts.

Event

```
{
  "name": "product add",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420
  },
  "context": {
    "shopping": [
      "intent",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [],
  "consent": {
    "functional": true
  },
  "id": "ad70d1774ec7ec0f",
  "trigger": "click",
  "entity": "product",
  "action": "add",
  "timestamp": 1700000401,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "add_to_cart",
  "settings": {
    "context": [
      {
        "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/product/jsonschema/1-0-0",
        "data": {
          "id": "data.id",
          "name": "data.name",
          "category": "data.category",
          "price": "data.price",
          "currency": {
            "key": "data.currency",
            "value": "USD"
          },
          "quantity": {
            "key": "data.quantity",
            "value": 1
          }
        }
      },
      {
        "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/cart/jsonschema/1-0-0",
        "data": {
          "total_value": "globals.cart_value",
          "currency": {
            "key": "globals.cart_currency",
            "value": "USD"
          }
        }
      },
      {
        "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/page/jsonschema/1-0-0",
        "data": {
          "type": "globals.page_type",
          "language": "globals.language"
        }
      },
      {
        "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/user/jsonschema/1-0-0",
        "data": {
          "id": "user.id",
          "email": "user.email",
          "is_guest": {
            "fn": {
              "$code": "e=>{var o;return!!(null==(o=e.user)?void 0:o.id)||void 0}"
            }
          }
        }
      }
    ]
  }
}
```

Out

```
snowplow.trackSelfDescribingEvent({
  "event": {
    "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/snowplow_ecommerce_action/jsonschema/1-0-2",
    "data": {
      "type": "add_to_cart"
    }
  },
  "context": [
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/product/jsonschema/1-0-0",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "price": 420,
        "currency": "USD",
        "quantity": 1
      }
    },
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/cart/jsonschema/1-0-0",
      "data": {
        "currency": "USD"
      }
    },
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/page/jsonschema/1-0-0",
      "data": {}
    },
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/user/jsonschema/1-0-0",
      "data": {
        "id": "us3r",
        "is_guest": true
      }
    }
  ]
})
```

### Checkout step

A checkout view fires a Snowplow checkout\_step action with the current step and option.

Event

```
{
  "name": "checkout view",
  "data": {
    "step": "payment",
    "currency": "EUR",
    "value": 462
  },
  "context": {
    "shopping": [
      "checkout",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "checkout",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "checkout",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "17fb3134e751b927",
  "trigger": "load",
  "entity": "checkout",
  "action": "view",
  "timestamp": 1700000405,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "checkout_step",
  "settings": {
    "context": [
      {
        "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/checkout_step/jsonschema/1-0-0",
        "data": {
          "step": "data.step",
          "option": "data.option"
        }
      }
    ]
  }
}
```

Out

```
snowplow.trackSelfDescribingEvent({
  "event": {
    "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/snowplow_ecommerce_action/jsonschema/1-0-2",
    "data": {
      "type": "checkout_step"
    }
  },
  "context": [
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/checkout_step/jsonschema/1-0-0",
      "data": {
        "step": "payment"
      }
    }
  ]
})
```

### Transaction with products

A transaction event adds one Snowplow product context per nested product via a loop mapping.

Event

```
{
  "name": "order complete",
  "data": {
    "id": "0rd3r1d",
    "currency": "EUR",
    "shipping": 5.22,
    "taxes": 73.76,
    "total": 555
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "caae6960886297a2",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000407,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "transaction",
  "settings": {
    "context": [
      {
        "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/transaction/jsonschema/1-0-0",
        "data": {
          "transaction_id": "data.id",
          "revenue": "data.total",
          "currency": "data.currency"
        }
      },
      {
        "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/product/jsonschema/1-0-0",
        "data": {
          "loop": [
            "nested",
            {
              "map": {
                "id": "data.id",
                "name": "data.name",
                "price": "data.price"
              }
            }
          ]
        }
      }
    ]
  }
}
```

Out

```
snowplow.trackSelfDescribingEvent({
  "event": {
    "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/snowplow_ecommerce_action/jsonschema/1-0-2",
    "data": {
      "type": "transaction"
    }
  },
  "context": [
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/transaction/jsonschema/1-0-0",
      "data": {
        "transaction_id": "0rd3r1d",
        "revenue": 555,
        "currency": "EUR"
      }
    },
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/product/jsonschema/1-0-0",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "price": 420
      }
    },
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/product/jsonschema/1-0-0",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "price": 42
      }
    },
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/product/jsonschema/1-0-0",
      "data": {
        "name": "Surprise"
      }
    }
  ]
})
```

### Initialization

Destination bootstrap creates a Snowplow tracker pointed at the configured collector URL.

Event

```
{
  "loadScript": true,
  "settings": {
    "collectorUrl": "https://collector.example.com",
    "appId": "my-app",
    "pageViewEvent": "page view"
  }
}
```

Out

```
snowplow.newTracker("sp", "https://collector.example.com", {
  "appId": "my-app",
  "platform": "web"
})
```

### Page view

A page view calls Snowplow trackPageView directly instead of a self-describing event.

Event

```
{
  "name": "page view",
  "data": {
    "domain": "www.example.com",
    "title": "walkerOS documentation",
    "referrer": "https://www.walkeros.io/",
    "search": "?foo=bar",
    "hash": "#hash",
    "id": "/docs/"
  },
  "context": {
    "dev": [
      "test",
      1
    ]
  },
  "globals": {
    "pagegroup": "docs"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "4f45b901a5ce653f",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000404,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Out

```
snowplow.trackPageView()
```

### Product view

A product view fires a Snowplow ecommerce action with a product context schema and pricing fields.

Event

```
{
  "name": "product view",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420
  },
  "context": {
    "shopping": [
      "detail",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [],
  "consent": {
    "functional": true
  },
  "id": "1bb0873868168b7c",
  "trigger": "load",
  "entity": "product",
  "action": "view",
  "timestamp": 1700000400,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "product_view",
  "settings": {
    "context": [
      {
        "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/product/jsonschema/1-0-0",
        "data": {
          "id": "data.id",
          "name": "data.name",
          "category": "data.category",
          "price": "data.price",
          "currency": {
            "key": "data.currency",
            "value": "USD"
          },
          "brand": "data.brand",
          "variant": "data.variant"
        }
      }
    ]
  }
}
```

Out

```
snowplow.trackSelfDescribingEvent({
  "event": {
    "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/snowplow_ecommerce_action/jsonschema/1-0-2",
    "data": {
      "type": "product_view"
    }
  },
  "context": [
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/product/jsonschema/1-0-0",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "price": 420,
        "currency": "USD"
      }
    }
  ]
})
```

### Promo view

A promotion visible event fires a Snowplow promo\_view action with a promotion context.

Event

```
{
  "name": "promotion visible",
  "data": {
    "name": "Setting up tracking easily",
    "position": "hero"
  },
  "context": {
    "ab_test": [
      "engagement",
      0
    ]
  },
  "globals": {
    "pagegroup": "homepage"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "child",
      "data": {
        "is": "subordinated"
      }
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "51b4c6098640b160",
  "trigger": "visible",
  "entity": "promotion",
  "action": "visible",
  "timestamp": 1700000403,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "promo_view",
  "settings": {
    "context": [
      {
        "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/promotion/jsonschema/1-0-0",
        "data": {
          "id": "data.id",
          "name": "data.name",
          "creative_id": "data.creative_id",
          "type": "data.type",
          "position": "data.position",
          "slot": "data.slot"
        }
      }
    ]
  }
}
```

Out

```
snowplow.trackSelfDescribingEvent({
  "event": {
    "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/snowplow_ecommerce_action/jsonschema/1-0-2",
    "data": {
      "type": "promo_view"
    }
  },
  "context": [
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/promotion/jsonschema/1-0-0",
      "data": {
        "name": "Setting up tracking easily",
        "position": "hero"
      }
    }
  ]
})
```

### Struct event

A custom event is tracked via Snowplow trackStructEvent with category, action, label, property, and value.

Event

```
{
  "name": "product visible",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420,
    "position": 3,
    "promo": true
  },
  "context": {
    "shopping": [
      "discover",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [],
  "consent": {
    "functional": true
  },
  "id": "0f2222c0077385cf",
  "trigger": "load",
  "entity": "product",
  "action": "visible",
  "timestamp": 1700000406,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "settings": {
    "struct": {
      "category": {
        "value": "ecommerce"
      },
      "action": {
        "value": "impression"
      },
      "label": "data.name",
      "property": "data.color",
      "value": "data.price"
    }
  }
}
```

Out

```
snowplow.trackStructEvent({
  "category": "ecommerce",
  "action": "impression",
  "label": "Everyday Ruck Snack",
  "property": "black",
  "value": 420
})
```

### Transaction

A completed order fires a Snowplow ecommerce transaction action with transaction id, revenue, tax, and shipping.

Event

```
{
  "name": "order complete",
  "data": {
    "id": "0rd3r1d",
    "currency": "EUR",
    "shipping": 5.22,
    "taxes": 73.76,
    "total": 555
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "c051b729bee8d298",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000402,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```
{
  "name": "transaction",
  "settings": {
    "context": [
      {
        "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/transaction/jsonschema/1-0-0",
        "data": {
          "transaction_id": "data.id",
          "revenue": "data.total",
          "currency": {
            "key": "data.currency",
            "value": "USD"
          },
          "payment_method": {
            "value": "credit_card"
          },
          "tax": "data.taxes",
          "shipping": "data.shipping"
        }
      }
    ]
  }
}
```

Out

```
snowplow.trackSelfDescribingEvent({
  "event": {
    "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/snowplow_ecommerce_action/jsonschema/1-0-2",
    "data": {
      "type": "transaction"
    }
  },
  "context": [
    {
      "schema": "iglu:com.snowplowanalytics.snowplow.ecommerce/transaction/jsonschema/1-0-0",
      "data": {
        "transaction_id": "0rd3r1d",
        "revenue": 555,
        "currency": "EUR",
        "payment_method": "credit_card",
        "tax": 73.76,
        "shipping": 5.22
      }
    }
  ]
})
```

## User identity and privacy[​](#user-identity-and-privacy "Direct link to User identity and privacy")

### Cross-session user stitching[​](#cross-session-user-stitching "Direct link to Cross-session user stitching")

Use `userId` to link events across sessions when users log in. The ID is set once via Snowplow's `setUserId()` on the first event where the value resolves:

```
{
  collectorUrl: 'https://collector.example.com',
  userId: 'user.id',
}
```

The `userId` setting supports walkerOS mapping syntax:

* `'user.id'` from walkerOS user object (recommended)
* `'globals.user_id'` from globals

### Anonymous tracking[​](#anonymous-tracking "Direct link to Anonymous tracking")

Enable anonymous tracking for privacy-focused collection or before consent:

```
{
  collectorUrl: 'https://collector.example.com',
  anonymousTracking: {
    withServerAnonymisation: true,
    withSessionTracking: true,
  },
}
```

### Runtime privacy controls[​](#runtime-privacy-controls "Direct link to Runtime privacy controls")

Control tracking modes at runtime using exported utility functions:

```
import {
  clearUserData,
  enableAnonymousTracking,
  disableAnonymousTracking,
} from '@walkeros/web-destination-snowplow';

clearUserData();
enableAnonymousTracking({ withServerAnonymisation: true });
disableAnonymousTracking();
```

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

Track GDPR/CCPA consent events using Snowplow's [Enhanced Consent plugin](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/web-tracker/tracking-events/consent-gdpr/). The destination automatically reacts to walkerOS consent events and calls the appropriate Snowplow consent methods.

**Prerequisites:** load the Enhanced Consent plugin via the `plugins` setting or include it in your Snowplow script bundle.

```
{
  collectorUrl: 'https://collector.example.com',
  consent: {
    required: ['analytics', 'marketing'],
    basisForProcessing: 'consent',
    consentUrl: 'https://example.com/privacy',
    consentVersion: '2.0',
    domainsApplied: ['example.com'],
    gdprApplies: true,
  },
}
```

| Option               | Type       | Description                                                                                                     |
| -------------------- | ---------- | --------------------------------------------------------------------------------------------------------------- |
| `required`           | `string[]` | walkerOS consent groups to check                                                                                |
| `basisForProcessing` | `string`   | GDPR basis: `consent`, `contract`, `legal_obligation`, `vital_interests`, `public_task`, `legitimate_interests` |
| `consentUrl`         | `string`   | Privacy policy URL                                                                                              |
| `consentVersion`     | `string`   | Policy version                                                                                                  |
| `domainsApplied`     | `string[]` | Domains where consent applies                                                                                   |
| `gdprApplies`        | `boolean`  | Whether GDPR applies                                                                                            |

The destination maps walkerOS consent state to Snowplow methods:

| walkerOS consent state      | Snowplow method        |
| --------------------------- | ---------------------- |
| All required scopes granted | `trackConsentAllow`    |
| All required scopes denied  | `trackConsentDeny`     |
| Partial consent (mixed)     | `trackConsentSelected` |

## Media tracking[​](#media-tracking "Direct link to Media tracking")

Track video and audio playback events using Snowplow's [media tracking schemas](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/web-tracker/tracking-events/media/). The destination supports all media events and contexts.

### Basic usage[​](#basic-usage "Direct link to Basic usage")

```
await elb('video play', {
  id: 'video-123',
  title: 'Product Demo',
  currentTime: 0,
  duration: 120,
});

await elb('video progress', {
  id: 'video-123',
  percentProgress: 25,
});

await elb('video pause', {
  id: 'video-123',
  currentTime: 45,
});

await elb('video end', {
  id: 'video-123',
  duration: 120,
});
```

### Media mapping configuration[​](#media-mapping-configuration "Direct link to Media mapping configuration")

Configure media event mappings with the `MEDIA_SCHEMAS` constants:

```
import { MEDIA_SCHEMAS } from '@walkeros/web-destination-snowplow';

{
  video: {
    play: {
      settings: {
        snowplow: { actionSchema: MEDIA_SCHEMAS.PLAY },
        context: [{
          schema: MEDIA_SCHEMAS.MEDIA_PLAYER,
          data: {
            currentTime: 'data.currentTime',
            duration: 'data.duration',
            paused: { value: false },
            muted: 'data.muted',
            volume: 'data.volume',
          },
        }],
      },
    },
    progress: {
      settings: {
        snowplow: { actionSchema: MEDIA_SCHEMAS.PERCENT_PROGRESS },
      },
      data: { map: { percentProgress: 'data.percent' } },
    },
  },
}
```

### Ad tracking[​](#ad-tracking "Direct link to Ad tracking")

Track video advertisements with pre-roll, mid-roll, and post-roll events:

```
import { MEDIA_SCHEMAS } from '@walkeros/web-destination-snowplow';

{
  ad: {
    break_start: {
      settings: {
        snowplow: { actionSchema: MEDIA_SCHEMAS.AD_BREAK_START },
        context: [{
          schema: MEDIA_SCHEMAS.AD_BREAK,
          data: {
            breakId: 'data.breakId',
            breakType: 'data.breakType',
          },
        }],
      },
    },
    start: {
      settings: {
        snowplow: { actionSchema: MEDIA_SCHEMAS.AD_START },
        context: [{
          schema: MEDIA_SCHEMAS.AD,
          data: {
            adId: 'data.adId',
            name: 'data.name',
            duration: 'data.duration',
          },
        }],
      },
    },
  },
}
```

### Available media schemas[​](#available-media-schemas "Direct link to Available media schemas")

| Schema                                 | Description           | Use case              |
| -------------------------------------- | --------------------- | --------------------- |
| `PLAY`                                 | Playback started      | Video/audio play      |
| `PAUSE`                                | Playback paused       | User pauses content   |
| `END`                                  | Playback ended        | Video/audio completed |
| `SEEK_START` / `SEEK_END`              | User seeking          | Scrubbing timeline    |
| `BUFFER_START` / `BUFFER_END`          | Buffering state       | Loading content       |
| `QUALITY_CHANGE`                       | Video quality changed | Adaptive streaming    |
| `FULLSCREEN_CHANGE`                    | Fullscreen toggled    | User interaction      |
| `VOLUME_CHANGE`                        | Volume changed        | User adjustment       |
| `PERCENT_PROGRESS`                     | Progress milestone    | 25%, 50%, 75% markers |
| `ERROR`                                | Playback error        | Error tracking        |
| `AD_BREAK_START` / `AD_BREAK_END`      | Ad break              | Pre/mid/post-roll     |
| `AD_START` / `AD_COMPLETE` / `AD_SKIP` | Individual ad         | Ad impressions        |

## Schema constants[​](#schema-constants "Direct link to Schema constants")

The package exports pre-defined Snowplow schema URIs for use in custom mappings:

```
import {
  SCHEMAS, ACTIONS, WEB_SCHEMAS, CONSENT_SCHEMAS,
  MEDIA_SCHEMAS, MEDIA_ACTIONS
} from '@walkeros/web-destination-snowplow';

SCHEMAS.PRODUCT;
SCHEMAS.TRANSACTION;
ACTIONS.ADD_TO_CART;
ACTIONS.TRANSACTION;
WEB_SCHEMAS.LINK_CLICK;
WEB_SCHEMAS.SUBMIT_FORM;
WEB_SCHEMAS.SITE_SEARCH;
MEDIA_SCHEMAS.PLAY;
MEDIA_SCHEMAS.PAUSE;
MEDIA_SCHEMAS.AD_BREAK_START;
CONSENT_SCHEMAS.PREFERENCES;
CONSENT_SCHEMAS.GDPR;
```

## Advanced configuration[​](#advanced-configuration "Direct link to Advanced configuration")

### Tracker settings[​](#tracker-settings "Direct link to Tracker settings")

```
{
  collectorUrl: 'https://collector.example.com',
  appId: 'my-app',
  appVersion: '1.0.0',
  discoverRootDomain: true,
  cookieSameSite: 'Lax',
  contexts: {
    webPage: true,
    session: true,
    performanceTiming: true,
    geolocation: false,
  },
}
```

### Activity tracking (page pings)[​](#activity-tracking-page-pings "Direct link to Activity tracking (page pings)")

```
{
  collectorUrl: 'https://collector.example.com',
  activityTracking: {
    minimumVisitLength: 10,
    heartbeatDelay: 30,
  },
}
```

### Page view tracking[​](#page-view-tracking "Direct link to Page view tracking")

Snowplow's native `trackPageView()` can be triggered either on init or via a walkerOS event. Both options require explicit configuration. If neither `trackPageView` nor `pageViewEvent` is set, no automatic page view tracking occurs.

```
{
  collectorUrl: 'https://collector.example.com',
  trackPageView: true,
}
```

```
{
  collectorUrl: 'https://collector.example.com',
  pageViewEvent: 'page view',
}
```

### Plugins[​](#plugins "Direct link to Plugins")

Load Snowplow plugins for automatic tracking. Supports both URL-based plugins (sp.js) and npm BrowserPlugin instances:

```
{
  collectorUrl: 'https://collector.example.com',
  plugins: [
    {
      url: 'https://cdn.jsdelivr.net/npm/@snowplow/browser-plugin-link-click-tracking@latest/dist/index.umd.min.js',
      name: ['snowplowLinkClickTracking', 'LinkClickTrackingPlugin'],
      options: { trackContent: true },
    },
  ],
}
```

The enable method is derived automatically from the plugin name (`LinkClickTrackingPlugin` becomes `enableLinkClickTracking`). Override with `enableMethod` if needed.

### Global contexts[​](#global-contexts "Direct link to Global contexts")

Attach context entities to all events. Supports static objects and dynamic generator functions:

```
{
  collectorUrl: 'https://collector.example.com',
  globalContexts: [
    {
      schema: 'iglu:com.example/app_info/jsonschema/1-0-0',
      data: { version: '1.0.0', environment: 'production' },
    },
    () => ({
      schema: 'iglu:com.example/consent/jsonschema/1-0-0',
      data: {
        advertising: document.cookie.includes('ads_consent=1'),
      },
    }),
  ],
}
```

## Testing with Snowplow Micro[​](#testing-with-snowplow-micro "Direct link to Testing with Snowplow Micro")

Use [Snowplow Micro](https://docs.snowplow.io/docs/testing-debugging/snowplow-micro/basic-usage/) for local development:

```
docker run -p 9090:9090 snowplow/snowplow-micro
```

Configure the destination with `collectorUrl: 'http://localhost:9090'` and view events at `http://localhost:9090/micro/ui`.
