Optimizely
Optimizely Feature Experimentation
runs A/B tests and feature rollouts. This destination forwards walkerOS events
to Optimizely as conversion events via the official
@optimizely/optimizely-sdk
v6 modular API, calling userContext.trackEvent(eventKey, eventTags) with
optional revenue/value tags and user attributes.
Optimizely is a web destination in the walkerOS flow:
Installation
npm install @walkeros/web-destination-optimizely- Integrated
- Bundled
import { startFlow } from '@walkeros/collector';
import { destinationOptimizely } from '@walkeros/web-destination-optimizely';
await startFlow({
destinations: {
optimizely: {
code: destinationOptimizely,
config: {
settings: {
sdkKey: 'YOUR_SDK_KEY',
userId: 'user.id',
},
},
},
},
});Add to your flow.json destinations:
"destinations": {
"optimizely": {
"package": "@walkeros/web-destination-optimizely",
"config": {
"settings": {
"sdkKey": "YOUR_SDK_KEY",
"userId": "user.id"
}
}
}
}Configuration
This destination uses the standard destination config wrapper (consent, data, env, id, ...). For the shared fields see destination configuration. Package-specific fields live under config.settings and are listed below.
Settings
| Property | Type | Description | More |
|---|---|---|---|
sdkKey | string | Your Optimizely Feature Experimentation SDK key. Find it in your Optimizely project under Settings > Environments. | |
userId | any | walkerOS mapping value to resolve userId for experiment bucketing. Example: "user.id" or { key: "user.id", value: "user.device" } for fallback. | |
attributes | any | User attributes for audience targeting. Resolves to Record<string, unknown>. Applied to every event via createUserContext(). | |
updateInterval | integer | Polling interval for datafile updates in milliseconds. Default: 60000. | |
autoUpdate | boolean | Auto-update datafile via polling. Default: true. | |
batchSize | integer | Batch event processor: number of events per batch. Default: 10. | |
flushInterval | integer | Batch event processor: flush interval in milliseconds. Default: 1000. | |
skipOdp | boolean | Skip Optimizely Data Platform (ODP) manager initialization. Default: true. Set to false only if you use ODP. |
Mapping
Per-event rules under config.mapping. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.
| Property | Type | Description | More |
|---|---|---|---|
eventKey | string | Override event key sent to Optimizely. If omitted, the walkerOS event name is used. Must match an event created in your Optimizely project. | |
revenue | any | Revenue mapping. Resolves to an integer in cents (e.g. 7281 = $72.81). Passed as eventTags.revenue to trackEvent(). | |
value | any | Numeric value mapping. Resolves to a float. Passed as eventTags.value to trackEvent(). | |
eventTags | any | Additional event tags. Resolves to Record<string, unknown>. Spread into the eventTags object passed to trackEvent(). | |
attributes | any | Per-event user attributes override. Resolves to Record<string, unknown>. Applied via setAttribute() before this event's trackEvent() call. |
Examples
Attributes only
A profile update sets Optimizely user attributes without firing a trackEvent for user enrichment.
{
"name": "profile update",
"data": {
"plan": "premium",
"country": "DE"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "f2dfda6d30702457",
"trigger": "test",
"entity": "profile",
"action": "update",
"timestamp": 1700000105,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"silent": true,
"settings": {
"attributes": {
"map": {
"plan": "data.plan",
"country": "data.country"
}
}
}
}optimizely.setAttribute("plan", "premium");
optimizely.setAttribute("country", "DE")Consent revoked
A walker consent command with analytics denied closes the Optimizely client and flushes queued events.
{
"analytics": false
}optimizely.close()Default event
A walker event becomes an Optimizely trackEvent call with the event name and empty eventTags.
{
"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": "ffc10fb4306c4ebb",
"trigger": "load",
"entity": "page",
"action": "view",
"timestamp": 1700000100,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}optimizely.trackEvent("page view", {})Mapped event key
A mapping renames the walker event to an Optimizely event key defined in the project.
{
"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": "9e1b7477590ab85c",
"trigger": "load",
"entity": "product",
"action": "view",
"timestamp": 1700000101,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"name": "product_viewed"
}optimizely.trackEvent("product_viewed", {})Purchase revenue
An order fires an Optimizely purchase event with revenue in cents, value, and additional event tags.
{
"name": "order complete",
"data": {
"revenue_cents": 55500,
"total": 555,
"currency": "EUR",
"item_count": 3
},
"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": "725795e1c7fcc709",
"trigger": "load",
"entity": "order",
"action": "complete",
"timestamp": 1700000102,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"name": "purchase",
"settings": {
"revenue": "data.revenue_cents",
"value": "data.total",
"eventTags": {
"map": {
"currency": "data.currency",
"item_count": "data.item_count"
}
}
}
}optimizely.trackEvent("purchase", {
"revenue": 55500,
"value": 555,
"currency": "EUR",
"item_count": 3
})Signup with attributes
A user signup sets per-event Optimizely attributes via setAttribute before firing the trackEvent.
{
"name": "user signup",
"data": {
"method": "google",
"source": "referral"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "b695ef8cacf881ab",
"trigger": "test",
"entity": "user",
"action": "signup",
"timestamp": 1700000103,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"name": "signup",
"settings": {
"attributes": {
"map": {
"signup_method": "data.method",
"referral_source": "data.source"
}
}
}
}optimizely.setAttribute("signup_method", "google");
optimizely.setAttribute("referral_source", "referral");
optimizely.trackEvent("signup", {})Revenue
Optimizely expects revenue as an integer in cents (e.g. 7281 =
$72.81). The destination passes the resolved value through without
conversion. The caller must provide cents.
Consent
Two layers protect event delivery:
config.consent: walkerOS gates delivery. Events are queued until required consent keys resolve totrue.on('consent'): the destination closes the Optimizely client (flushing queued events and stopping datafile polling) when any required key flips tofalse. On re-grant, the next push re-initializes the client.
destinations: {
optimizely: {
code: destinationOptimizely,
config: {
consent: { analytics: true },
settings: {
sdkKey: 'YOUR_SDK_KEY',
userId: 'user.id',
},
},
},
}Feature flags / decide()
This destination intentionally does not expose decide(). Experiment
decisions belong in application code where UI branching happens. This
package covers the outbound conversion-tracking use case.