Skip to content

walkerOS v3.3.0

Choose a tag to compare

@github-actions github-actions released this 13 Apr 20:59
· 293 commits to main since this release
ebf684d

Changes

Add Amplitude web destination (@walkeros/web-destination-amplitude) —
analytics, identity with full operation vocabulary, revenue (single and
multi-product via loop), groups, consent opt-out, and three optional plugins
(Session Replay, Feature Experiments, Guides & Surveys) via the official
@amplitude/* npm packages.

  • Default event forwarding: every walkerOS event becomes
    amplitude.track(name, event_properties)
  • Custom event properties: settings.include flattens walkerOS event sections
    with prefix (data_*, globals_*, etc.)
  • Identity: destination-level + per-event settings.identify, resolving to
    user/device/session plus the full Identify operation vocabulary (set,
    setOnce, add, append, prepend, preInsert, postInsert, remove,
    unset, clearAll). Runtime state diffing skips redundant setter calls.
  • Revenue: settings.revenue supports both single-object and loop-based
    multi-product orders. Currency defaults to "EUR".
  • Groups: settings.group and settings.groupIdentify for B2B flows
  • Reset: settings.reset: true calls amplitude.reset() on logout
  • Consent: on('consent') handler derives the consent keys from
    config.consent and toggles amplitude.setOptOut() (strict: all keys must be
    granted for opt-in)
  • Plugins (all npm-bundled, opt-in via settings): Session Replay, Feature
    Experiments (via initializeWithAmplitudeAnalytics), Engagement (Guides &
    Surveys)
  • Async init: awaits amplitude.init(...).promise so the destination is truly
    ready before returning
  • SDK resolution follows the env?.amplitude ?? amplitude pattern (mirrors
    @walkeros/web-destination-clarity and @walkeros/server-destination-gcp
    BigQuery)

BREAKING CHANGE: The packages block has moved from flow.<name>.packages
to flow.<name>.bundle.packages. Flow files using the old shape fail fast with
a migration error pointing to the new location.
Also adds flow.<name>.bundle.overrides — a Record<string, string> for
pinning transitive dependency versions, matching npm's overrides semantics.
Use this to resolve version conflicts when a transitive dependency's declared
range conflicts with another required version in the same tree (the original
motivating case: @amplitude/engagement-browser pins
@amplitude/analytics-types@^1.0.0 while @amplitude/analytics-browser
transitively requires analytics-types@2.11.1 exact — previously an
unresolvable bundler conflict).
Migration: move the existing packages block one level deeper into a new
bundle wrapper.

  {
    "version": 3,
    "flows": {
      "default": {
        "web": {},
-       "packages": {
-         "@walkeros/collector": {}
-       },
+       "bundle": {
+         "packages": {
+           "@walkeros/collector": {}
+         }
+       },
        "sources": { },
        "destinations": { }
      }
    }
  }

Overrides example:

{
  "flows": {
    "default": {
      "web": {},
      "bundle": {
        "packages": {
          "@walkeros/web-destination-amplitude": {}
        },
        "overrides": {
          "@amplitude/analytics-types": "2.11.1"
        }
      }
    }
  }
}

Overrides only substitute transitive dependencies during resolution — direct
package specs declared in bundle.packages always win. Overrides targeting a
direct local-path package emit a warning and are ignored. Peer constraint
mismatches against the chosen override emit a warning but do not error (the
override is an explicit user directive).

Add Microsoft Clarity web destination (@walkeros/web-destination-clarity) —
session replay, heatmaps, custom tags, identity, session priority, and consent
translation via the official @microsoft/clarity SDK.

  • Default event forwarding: every walkerOS event becomes Clarity.event(name)
  • Custom tags: flatten sections with settings.include or define explicit maps
    with mapping.settings.set (supports string and string[] values natively)
  • Identity: mapping values resolve to positional Clarity.identify(...) args.
    Destination-level settings.identify fires on every push, matching Clarity's
    "identify on every page load" recommendation
  • Session priority: mapping.settings.upgrade fires Clarity.upgrade(reason)
  • Consent: explicit settings.consent table translates walkerOS consent keys to
    Clarity ConsentV2 categories (analytics_Storage, ad_Storage). All
    consent state is forwarded via Clarity.consentV2(...) — the legacy
    Clarity.consent(...) API is intentionally not used.
  • Honours mapping.skip to run side effects without the default event call
  • Push execution order: identify → tags → upgrade → event, matching Clarity's
    own guidance
  • SDK resolution follows the env?.clarity ?? Clarity pattern (mirrors
    @walkeros/server-destination-gcp BigQuery wiring), so production uses the
    real imported SDK while tests inject a mock via env.clarity

Expand getMarketingParameters to recognise 25+ ad platform click IDs
(Pinterest, Reddit, Quora, Yandex, Outbrain, Taboola, Mailchimp, Klaviyo,
HubSpot, Adobe, Impact, CJ, Branch, plus Google's wbraid/gbraid). Add a new
platform field that resolves the click ID to a canonical platform identifier
(e.g. gclidgoogle, fbclidmeta). Multi-click-ID URLs are resolved
deterministically via a priority order.
Custom click-ID registries can be passed as the third argument to
getMarketingParameters, or via the new clickIds field in the session source
settings — so flow.json users can extend or override defaults without touching
code.

Fix bare filename resolution in bundle command — walkeros bundle flow.json now resolves relative to cwd instead of CLI examples directory. Add TTY hint when writing to stdout

BREAKING: settings.include and mapping.settings.*.include have been
removed. Use config.include (destination-level) and mapping.include
(per-event rule-level) instead. The include logic is now handled by the walkerOS
core/collector — the destination receives pre-flattened properties in
context.data automatically.
Migration:
Before:

"config": {
  "settings": { "ga4": { "include": ["data"] } }
}

After:

"config": {
  "include": ["data"]
}

For per-event overrides:
Before:

"mapping": { "order": { "complete": { "settings": { "ga4": { "include": ["data", "globals"] } } } } }

After:

"mapping": { "order": { "complete": { "include": ["data", "globals"] } } }

Add include as a first-class field on Destination.Config (destination-level)
and Mapping.Rule (per-event override). The collector resolves include in
processEventMapping before calling push(), flattening specified event
sections into prefixed key-value pairs (e.g. data_price: 420) and merging them
as the bottom layer of context.data.
Rule-level include replaces config-level (not additive). Merge priority:
include (bottom) → config.data → rule.data (top, wins on conflict). The
context section correctly extracts [0] from OrderedProperties tuples.
New export: flattenIncludeSections(event, sections) from @walkeros/core.

Add LinkedIn Insight Tag web destination (@walkeros/web-destination-linkedin)
— opt-in conversion forwarding via window.lintrk('track', ...).

  • Opt-in conversion model: Events without mapping.settings.conversion are
    silently ignored. Each conversion references a pre-created Conversion Rule ID
    from LinkedIn Campaign Manager.
  • Per-event conversion mapping with short keys: id, value, currency,
    eventId — translated at call time to LinkedIn's conversion_id /
    conversion_value / currency / event_id.
  • Currency fallback via walkerOS { key, value } syntax — defaults to
    "EUR" when data.currency is absent.
  • Deduplication ready — maps walkerOS event.id to LinkedIn's event_id
    field, ready for future cross-channel deduplication with a server (Conversions
    API) destination.
  • Consent-gated: marketing (not analytics). The collector's
    config.consent gate is the sole mechanism — the Insight Tag has no vendor
    opt-out API. config.loadScript: true supports deferred script injection
    after consent grant.
  • No npm SDK — the destination injects the official Insight Tag from
    https://snap.licdn.com/li.lms-analytics/insight.min.js at runtime.
  • No identity tracking — LinkedIn identity is cookie-based and managed
    entirely by the Insight Tag. li_fat_id capture is the session source's
    responsibility (future Conversions API destination will consume it).
  • Covered features: 8 step-example fixtures including unmapped-event
    ignoring, simple conversion ID, full e-commerce conversion (value + currency +
    eventId), page view key-page-view, LEAD conversion, mapping.skip, falsy id
    guard, and partial-fields omission.

Add skip?: boolean to Mapping.Rule as a universal sibling of ignore.
Destinations can now honor a rule-level skip to process settings.* side
effects (identify, revenue, group, etc.) while omitting their default forwarding
call (track(), capture(), event()). Replaces destination-specific
settings.skipTrack / settings.skipEvent toggles.
processEventMapping() now returns an explicit skip: boolean field alongside
ignore. The collector does not short-circuit on skip — it still calls
destination.push() so the destination can run its side effects. The
destination implementation reads context.rule?.skip and gates its default
forwarding call on !skip.
ignore: true still wins when both flags are set on the same rule.

Add Mixpanel web destination (@walkeros/web-destination-mixpanel) — events,
identity, the full 8-operation people vocabulary, group association, group
profiles, reset, and consent opt-in/opt-out via the official mixpanel-browser
npm package.

  • Default event forwarding: every walkerOS event becomes
    mixpanel.track(name, properties)
  • Custom event properties: settings.include flattens walkerOS event sections
    with prefix (data_*, globals_*, etc.)
  • Identity: destination-level + per-event settings.identify, resolving to
    { distinctId }mixpanel.identify(distinctId). Runtime state diffing
    skips redundant identify calls.
  • People: settings.people supports the full Mixpanel operation set (set,
    set_once, increment, append, union, remove, unset, delete_user)
  • Groups: settings.group for user-group association (mixpanel.set_group) and
    settings.groupProfile for group profile properties
    (mixpanel.get_group(key, id).set/set_once/union/remove/unset/delete)
  • Reset: settings.reset: true calls mixpanel.reset() on logout
  • Consent: on('consent') handler derives the consent keys from
    config.consent and toggles opt_in_tracking/opt_out_tracking
  • All mixpanel-browser init options flow through via snake_case passthrough
    (api_host, batch_requests, record_sessions_percent,
    cross_subdomain_cookie, etc.). walkerOS-specific defaults:
    autocapture: false and track_pageview: false
  • SDK resolution follows the env?.mixpanel ?? mixpanel pattern (mirrors
    @walkeros/web-destination-clarity and @walkeros/server-destination-gcp
    BigQuery)

Add Pinterest Tag web destination (@walkeros/web-destination-pinterest) —
conversion tracking with the full Pinterest standard event taxonomy, enhanced
matching via em/external_id, auto event_id deduplication, inline
line_items, and consent-aware suppression. Loads core.js from Pinterest's
CDN.

  • Standard event taxonomy: explicit mapping.name rename to Pinterest's
    lowercase concatenated names (pagevisit, addtocart, checkout,
    viewcontent, lead, signup, search, custom, ...).
  • Inline line_items for multi-product: single
    pintrk('track', 'checkout', { line_items: [...] }) call (NOT N separate
    calls). Built via the standard walkerOS loop mapping syntax.
  • Enhanced matching: strict allow-list of em (email) and external_id.
    The Pinterest JS tag auto-hashes em with SHA-256 — the destination passes
    raw values through and never hashes. Per-push diff suppresses redundant
    pintrk('set', ...) calls.
  • Auto event_id for dedup: every pintrk('track', ...) call attaches the
    walkerOS event id, ready for cross-channel deduplication with a future
    server (Conversions API) destination.
  • Currency fallback via walkerOS { key, value } syntax — defaults to
    "EUR".
  • Consent-aware suppression: Pinterest has no vendor opt_in/opt_out API.
    on('consent') flips a runtime state flag, so subsequent track calls are
    suppressed silently after revocation.
  • No npm SDK — the destination injects the official Pinterest Tag from
    https://s.pinimg.com/ct/core.js at runtime.
  • Covered features: 11 step-example fixtures including default forward,
    wildcard ignore, page view rename, site search, single-product viewcontent,
    addtocart with inline line_items, multi-product checkout via loop, lead with
    identify, identify-only mapping.skip, and consent grant/revoke runtime
    suppression.

Add PostHog web destination (@walkeros/web-destination-posthog) — product
analytics, identity with $set/$set_once person properties, groups, logout
via reset, consent opt-in/opt-out, plus passthrough for all built-in PostHog
features (session replay, feature flags, surveys, heatmaps, error tracking) via
the official posthog-js npm package.

  • Default event forwarding: every walkerOS event becomes
    posthog.capture(name, properties)
  • Custom event properties: settings.include flattens walkerOS event sections
    with prefix (data_*, globals_*, etc.)
  • Identity: destination-level + per-event settings.identify, resolving to
    { distinctId?, $set?, $set_once? }. With distinctId: posthog.identify().
    Without distinctId: posthog.setPersonProperties() (property-only updates).
    Runtime state diffing skips redundant identify() calls when distinctId
    hasn't changed.
  • Groups: settings.group for B2B workflows — destination-level or per-event,
    tracked in runtime state
  • Reset: settings.reset: true calls posthog.reset() on logout
  • Consent: on('consent') handler derives the consent key from config.consent
    and toggles posthog.opt_in_capturing()/opt_out_capturing()
  • Built-in features (config passthrough, no destination code): session
    recording, feature flags, surveys, heatmaps, exceptions, cookieless mode,
    bootstrap
  • walkerOS defaults override PostHog defaults: autocapture: false,
    capture_pageview: false, capture_pageleave: false — walkerOS sources
    handle event capture
  • SDK resolution follows the env?.posthog ?? posthog pattern (mirrors
    @walkeros/web-destination-clarity and @walkeros/server-destination-gcp
    BigQuery)

Add preview mode preflight to web bundles

  • WrapSkeletonOptions accepts optional previewOrigin and previewScope
    fields
  • generateWrapEntry injects a preflight snippet before startFlow when both
    are set: checks ?elbPreview param / cookie, loads preview bundle from
    {previewOrigin}/preview/{previewScope}/walker.{token}.js, skips production
    flow. Zero overhead when preview options are absent.
  • Input validation rejects path-traversal in previewScope and special
    characters in previewOrigin.

Add Segment CDP web destination (@walkeros/web-destination-segment) — forwards
walkerOS events to Segment via the official @segment/analytics-next
(Analytics.js 2.0) package. Implements the full Segment Spec surface with
automatic walkerOS→Segment consent context forwarding and deferred-load consent
handling.

  • Default event forwarding: every walkerOS event becomes
    analytics.track(name, properties)
  • Custom event properties: settings.include flattens walkerOS event sections
    with prefix (data_*, globals_*, etc.) or use mapping.data for full
    Segment-Spec-shaped properties
  • Identity: destination-level + per-event settings.identify resolving to
    { userId, traits, anonymousId }. Runtime state diffing skips redundant
    identify() calls.
  • Groups: settings.group and per-event mapping.settings.group with reserved
    Segment group trait names
  • Page views: first-class mapping.settings.page
    analytics.page(category, name, properties) (explicit configuration, no
    auto-detection)
  • Reset: settings.reset: true calls analytics.reset() on logout
  • Consent context forwarding: walkerOS consent state is automatically stamped as
    context.consent.categoryPreferences on every track, identify, group, and
    page call when settings.consent is configured, with optional key remapping
    (e.g. walkerOS marketing → Segment Advertising)
  • Deferred-load consent pattern: when config.consent is declared,
    AnalyticsBrowser.load() is held until on('consent') fires with all
    required keys granted
  • Ecommerce: walkerOS mapping.name + mapping.data produce Segment Spec event
    names (e.g. Order Completed) with a products array property — a single
    track() call per order, not a loop
  • SDK resolution follows the env?.analytics ?? realSegment pattern (mirrors
    @walkeros/web-destination-clarity)
  • Plugins, source middleware, and destination middleware are explicitly out of
    scope for v1 (JavaScript functions cannot be serialized in JSON flow configs —
    register them programmatically on the returned AnalyticsBrowser instance if
    needed)
  • alias() and screen() are intentionally deferred (legacy / mobile-only)

Add Slack server destination with dual-mode support (Incoming Webhooks + Web API), channel routing, DM support, threading, ephemeral messages, and Block Kit formatting.

Bundle /dev exports into stage 1 skeleton for environment-agnostic simulation

  • /dev exports from packages are included in the skipWrapper bundle as
    __devExports
  • Stage 2 production bundles tree-shake dev exports (no size impact)
  • prepareFlow() accepts Flow.Config object or pre-built bundlePath
  • Simulate functions read env/createTrigger from bundle instead of filesystem

Add command field to Flow.StepExample for routing non-event inputs through
walker commands (consent, user, run, config). Replaces the gtag-only
_consent: true magic marker pattern. Test runners can now explicitly opt into
elb('walker <command>', in) instead of pushing in as a regular event.
Breaking for anyone copying gtag's step-example test runner: the
_consent: true magic marker on mapping is gone. Migrate to
command: 'consent' on Flow.StepExample.

Add TikTok Pixel web destination (@walkeros/web-destination-tiktok) —
conversion tracking, Advanced Matching, and consent-aware cookie handling via
the official TikTok Pixel snippet. No npm SDK dependency; loads from TikTok's
CDN.

  • Default event forwarding: every walkerOS event becomes a
    ttq.track(name, params, { event_id }) call. event_id is always
    walkerOS event.id for deduplication with a future server-side Events API
    destination.
  • Event renaming via standard walkerOS mapping.name. A StandardEventNames
    TypeScript union exports all 14 TikTok standard events (ViewContent,
    AddToCart, CompletePayment, …) for IDE autocomplete; arbitrary strings still
    work as custom events.
  • Advanced Matching: destination-level + per-event settings.identify resolving
    to { email, phone_number, external_id }. Runtime state diffing skips
    redundant ttq.identify() calls on unchanged values. TikTok's SDK auto-hashes
    all values with SHA256 before sending.
  • Custom event properties: settings.include flattens walkerOS event sections
    with prefix (data_*, globals_*, etc.) — useful for custom events where
    TikTok won't optimize anyway.
  • Ecommerce via standard mapping.data: users build contents, value,
    currency, order_id through walkerOS's built-in map and loop. No
    destination-specific ecommerce logic.
  • Consent: config.consent gate (typically { marketing: true } since TikTok
    is an ad platform). on('consent') handler toggles ttq.enableCookie() /
    ttq.disableCookie().
  • TikTok's SDK auto-fires ttq.page() on init; no destination knob to suppress
    it (decision 2026-04-09 — the knob was unreliable, letting the auto page view
    fire is expected behavior).
  • Script-tag only: no npm SDK exists for TikTok Pixel. The destination uses the
    standard snippet + addScript() pattern from
    @walkeros/web-destination-meta, loading from
    analytics.tiktok.com/i18n/pixel/events.js.

Published Packages