walkerOS v3.3.0
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.includeflattens 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.revenuesupports both single-object andloop-based
multi-product orders. Currency defaults to"EUR". - Groups:
settings.groupandsettings.groupIdentifyfor B2B flows - Reset:
settings.reset: truecallsamplitude.reset()on logout - Consent:
on('consent')handler derives the consent keys from
config.consentand togglesamplitude.setOptOut()(strict: all keys must be
granted for opt-in) - Plugins (all npm-bundled, opt-in via settings): Session Replay, Feature
Experiments (viainitializeWithAmplitudeAnalytics), Engagement (Guides &
Surveys) - Async init: awaits
amplitude.init(...).promiseso the destination is truly
ready before returning - SDK resolution follows the
env?.amplitude ?? amplitudepattern (mirrors
@walkeros/web-destination-clarityand@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.includeor define explicit maps
withmapping.settings.set(supportsstringandstring[]values natively) - Identity: mapping values resolve to positional
Clarity.identify(...)args.
Destination-levelsettings.identifyfires on every push, matching Clarity's
"identify on every page load" recommendation - Session priority:
mapping.settings.upgradefiresClarity.upgrade(reason) - Consent: explicit
settings.consenttable translates walkerOS consent keys to
ClarityConsentV2categories (analytics_Storage,ad_Storage). All
consent state is forwarded viaClarity.consentV2(...)— the legacy
Clarity.consent(...)API is intentionally not used. - Honours
mapping.skipto 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 ?? Claritypattern (mirrors
@walkeros/server-destination-gcpBigQuery wiring), so production uses the
real imported SDK while tests inject a mock viaenv.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. gclid → google, fbclid → meta). 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.conversionare
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'sconversion_id/
conversion_value/currency/event_id. - Currency fallback via walkerOS
{ key, value }syntax — defaults to
"EUR"whendata.currencyis absent. - Deduplication ready — maps walkerOS
event.idto LinkedIn'sevent_id
field, ready for future cross-channel deduplication with a server (Conversions
API) destination. - Consent-gated:
marketing(notanalytics). The collector's
config.consentgate is the sole mechanism — the Insight Tag has no vendor
opt-out API.config.loadScript: truesupports 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.jsat runtime. - No identity tracking — LinkedIn identity is cookie-based and managed
entirely by the Insight Tag.li_fat_idcapture 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.includeflattens 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.peoplesupports the full Mixpanel operation set (set,
set_once,increment,append,union,remove,unset,delete_user) - Groups:
settings.groupfor user-group association (mixpanel.set_group) and
settings.groupProfilefor group profile properties
(mixpanel.get_group(key, id).set/set_once/union/remove/unset/delete) - Reset:
settings.reset: truecallsmixpanel.reset()on logout - Consent:
on('consent')handler derives the consent keys from
config.consentand togglesopt_in_tracking/opt_out_tracking - All
mixpanel-browserinit options flow through via snake_case passthrough
(api_host,batch_requests,record_sessions_percent,
cross_subdomain_cookie, etc.). walkerOS-specific defaults:
autocapture: falseandtrack_pageview: false - SDK resolution follows the
env?.mixpanel ?? mixpanelpattern (mirrors
@walkeros/web-destination-clarityand@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.namerename to Pinterest's
lowercase concatenated names (pagevisit,addtocart,checkout,
viewcontent,lead,signup,search,custom, ...). - Inline
line_itemsfor multi-product: single
pintrk('track', 'checkout', { line_items: [...] })call (NOT N separate
calls). Built via the standard walkerOSloopmapping syntax. - Enhanced matching: strict allow-list of
em(email) andexternal_id.
The Pinterest JS tag auto-hashesemwith SHA-256 — the destination passes
raw values through and never hashes. Per-push diff suppresses redundant
pintrk('set', ...)calls. - Auto
event_idfor dedup: everypintrk('track', ...)call attaches the
walkerOS eventid, 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_outAPI.
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.jsat 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-onlymapping.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.includeflattens walkerOS event sections
with prefix (data_*,globals_*, etc.) - Identity: destination-level + per-event
settings.identify, resolving to
{ distinctId?, $set?, $set_once? }. WithdistinctId:posthog.identify().
WithoutdistinctId:posthog.setPersonProperties()(property-only updates).
Runtime state diffing skips redundantidentify()calls whendistinctId
hasn't changed. - Groups:
settings.groupfor B2B workflows — destination-level or per-event,
tracked in runtime state - Reset:
settings.reset: truecallsposthog.reset()on logout - Consent:
on('consent')handler derives the consent key fromconfig.consent
and togglesposthog.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 ?? posthogpattern (mirrors
@walkeros/web-destination-clarityand@walkeros/server-destination-gcp
BigQuery)
Add preview mode preflight to web bundles
WrapSkeletonOptionsaccepts optionalpreviewOriginandpreviewScope
fieldsgenerateWrapEntryinjects a preflight snippet beforestartFlowwhen both
are set: checks?elbPreviewparam / 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
previewScopeand special
characters inpreviewOrigin.
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.includeflattens walkerOS event sections
with prefix (data_*,globals_*, etc.) or usemapping.datafor full
Segment-Spec-shaped properties - Identity: destination-level + per-event
settings.identifyresolving to
{ userId, traits, anonymousId }. Runtime state diffing skips redundant
identify()calls. - Groups:
settings.groupand per-eventmapping.settings.groupwith 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: truecallsanalytics.reset()on logout - Consent context forwarding: walkerOS consent state is automatically stamped as
context.consent.categoryPreferenceson every track, identify, group, and
page call whensettings.consentis configured, with optional key remapping
(e.g. walkerOSmarketing→ SegmentAdvertising) - Deferred-load consent pattern: when
config.consentis declared,
AnalyticsBrowser.load()is held untilon('consent')fires with all
required keys granted - Ecommerce: walkerOS
mapping.name+mapping.dataproduce Segment Spec event
names (e.g.Order Completed) with aproductsarray property — a single
track()call per order, not a loop - SDK resolution follows the
env?.analytics ?? realSegmentpattern (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 returnedAnalyticsBrowserinstance if
needed) alias()andscreen()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
/devexports from packages are included in the skipWrapper bundle as
__devExports- Stage 2 production bundles tree-shake dev exports (no size impact)
prepareFlow()acceptsFlow.Configobject or pre-builtbundlePath- 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_idis always
walkerOS event.idfor deduplication with a future server-side Events API
destination. - Event renaming via standard walkerOS
mapping.name. AStandardEventNames
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.identifyresolving
to{ email, phone_number, external_id }. Runtime state diffing skips
redundantttq.identify()calls on unchanged values. TikTok's SDK auto-hashes
all values with SHA256 before sending. - Custom event properties:
settings.includeflattens walkerOS event sections
with prefix (data_*,globals_*, etc.) — useful for custom events where
TikTok won't optimize anyway. - Ecommerce via standard
mapping.data: users buildcontents,value,
currency,order_idthrough walkerOS's built-inmapandloop. No
destination-specific ecommerce logic. - Consent:
config.consentgate (typically{ marketing: true }since TikTok
is an ad platform).on('consent')handler togglesttq.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
- @walkeros/cli
- @walkeros/collector
- @walkeros/core
- @walkeros/server-destination-slack
- @walkeros/web-destination-amplitude
- @walkeros/web-destination-clarity
- @walkeros/web-destination-gtag
- @walkeros/web-destination-linkedin
- @walkeros/web-destination-mixpanel
- @walkeros/web-destination-pinterest
- @walkeros/web-destination-posthog
- @walkeros/web-destination-segment
- @walkeros/web-destination-tiktok
- @walkeros/web-source-session