Klaviyo
Server-side event delivery to Klaviyo via the official klaviyo-api SDK. Tracks events with EventsApi.createEvent() and manages profiles with ProfilesApi.createOrUpdateProfile(), including revenue tracking, ecommerce metric name mapping, and identify state diffing.
Klaviyo is a server destination in the walkerOS flow:
Receives events server-side from the collector, resolves a profile identifier (email, externalId, or phoneNumber), optionally upserts the profile, then forwards the event to Klaviyo for flows, segmentation, and campaigns.
Installation
npm install @walkeros/server-destination-klaviyo- Integrated
- Bundled
import { startFlow } from '@walkeros/collector';
import { destinationKlaviyo } from '@walkeros/server-destination-klaviyo';
await startFlow({
destinations: {
klaviyo: {
code: destinationKlaviyo,
config: {
settings: {
apiKey: 'YOUR_KLAVIYO_PRIVATE_API_KEY',
},
},
},
},
});Add to your flow.json destinations:
"destinations": {
"klaviyo": {
"package": "@walkeros/server-destination-klaviyo",
"config": {
"settings": {
"apiKey": "YOUR_KLAVIYO_PRIVATE_API_KEY"
}
}
}
}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 |
|---|---|---|---|
apiKey | string | Klaviyo private API key. Starts with pk_. Find it under Settings > API Keys in your Klaviyo account. | |
email | string | walkerOS mapping value path to resolve email from each event (like user.email). | |
phoneNumber | string | walkerOS mapping value path to resolve phone number in E.164 format from each event. | |
externalId | string | walkerOS mapping value path to resolve external ID from each event (like user.id). | |
identify | any | Destination-level identity mapping. Resolves to profile attributes { firstName?, lastName?, organization?, properties? }. Fires createOrUpdateProfile() on first push and re-fires when values change. | |
currency | string | Default ISO 4217 currency code for revenue events (like USD, EUR). Sets valueCurrency on Klaviyo events. |
Mapping
Per-event rules under config.mapping. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.
| Property | Type | Description | More |
|---|---|---|---|
identify | any | Per-event identify mapping. Resolves to profile attributes for createOrUpdateProfile(). Use with rule-level silent: true on login/signup events. | |
value | any | Revenue value mapping. Resolves to a numeric value for Klaviyo revenue tracking. Sets the value property and valueCurrency on the event. |
Examples
Default event
An event is sent to Klaviyo as a metric with an inline profile resolved from the user email and id.
{
"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",
"email": "user@example.com"
},
"nested": [],
"consent": {
"functional": true
},
"id": "8415f2979ba99adb",
"trigger": "load",
"entity": "product",
"action": "view",
"timestamp": 1700000100,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}eventsApi.createEvent({
"data": {
"type": "event",
"attributes": {
"profile": {
"data": {
"type": "profile",
"attributes": {
"email": "user@example.com",
"externalId": "us3r"
}
}
},
"metric": {
"data": {
"type": "metric",
"attributes": {
"name": "product view"
}
}
},
"properties": {},
"time": "1970-01-20T16:13:20.100Z"
}
}
})Destination identify
Destination-level identify upserts the Klaviyo profile with a first name before each event is sent.
{
"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",
"email": "user@example.com",
"firstName": "Jane"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "f5b89bfecc4f1e95",
"trigger": "load",
"entity": "page",
"action": "view",
"timestamp": 1700000104,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}profilesApi.createOrUpdateProfile({
"data": {
"type": "profile",
"attributes": {
"email": "user@example.com",
"externalId": "us3r",
"firstName": "Jane"
}
}
});
eventsApi.createEvent({
"data": {
"type": "event",
"attributes": {
"profile": {
"data": {
"type": "profile",
"attributes": {
"email": "user@example.com",
"externalId": "us3r"
}
}
},
"metric": {
"data": {
"type": "metric",
"attributes": {
"name": "page view"
}
}
},
"properties": {},
"time": "1970-01-20T16:13:20.104Z"
}
}
})Email only
A newsletter signup uses only the email address as the Klaviyo profile identifier, with no external id.
{
"name": "newsletter signup",
"data": {
"string": "foo",
"number": 1,
"boolean": true,
"array": [
0,
"text",
false
]
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"email": "subscriber@example.com"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "999a5f94c27a8cbc",
"trigger": "test",
"entity": "newsletter",
"action": "signup",
"timestamp": 1700000105,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}eventsApi.createEvent({
"data": {
"type": "event",
"attributes": {
"profile": {
"data": {
"type": "profile",
"attributes": {
"email": "subscriber@example.com"
}
}
},
"metric": {
"data": {
"type": "metric",
"attributes": {
"name": "newsletter signup"
}
}
},
"properties": {},
"time": "1970-01-20T16:13:20.105Z"
}
}
})Viewed product
A product view is mapped to the Klaviyo Viewed Product metric with properties such as product name and price.
{
"name": "product view",
"data": {
"name": "USB Cable",
"id": "PROD-1",
"price": 9.99
},
"context": {
"shopping": [
"detail",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"email": "user@example.com"
},
"nested": [],
"consent": {
"functional": true
},
"id": "4943578dcbbded9c",
"trigger": "load",
"entity": "product",
"action": "view",
"timestamp": 1700000101,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"name": "Viewed Product",
"data": {
"map": {
"ProductName": "data.name",
"ProductID": "data.id",
"Price": "data.price"
}
}
}eventsApi.createEvent({
"data": {
"type": "event",
"attributes": {
"profile": {
"data": {
"type": "profile",
"attributes": {
"email": "user@example.com",
"externalId": "us3r"
}
}
},
"metric": {
"data": {
"type": "metric",
"attributes": {
"name": "Viewed Product"
}
}
},
"properties": {
"ProductName": "USB Cable",
"ProductID": "PROD-1",
"Price": 9.99
},
"time": "1970-01-20T16:13:20.101Z"
}
}
})Placed order
An order complete is sent to Klaviyo as Placed Order with value and currency for revenue attribution.
{
"name": "order complete",
"data": {
"id": "ORD-123",
"total": 99.99,
"itemNames": [
"Widget A",
"Widget B"
]
},
"context": {
"shopping": [
"complete",
0
]
},
"globals": {
"pagegroup": "shop"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"email": "user@example.com"
},
"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": "a9b93fa6e4d522fd",
"trigger": "load",
"entity": "order",
"action": "complete",
"timestamp": 1700000102,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"name": "Placed Order",
"data": {
"map": {
"OrderId": "data.id",
"value": "data.total",
"ItemNames": "data.itemNames"
}
},
"settings": {
"value": "data.total"
}
}eventsApi.createEvent({
"data": {
"type": "event",
"attributes": {
"profile": {
"data": {
"type": "profile",
"attributes": {
"email": "user@example.com",
"externalId": "us3r"
}
}
},
"metric": {
"data": {
"type": "metric",
"attributes": {
"name": "Placed Order"
}
}
},
"properties": {
"OrderId": "ORD-123",
"value": 99.99,
"ItemNames": [
"Widget A",
"Widget B"
]
},
"time": "1970-01-20T16:13:20.102Z",
"valueCurrency": "EUR"
}
}
})User login identify
A user login upserts the Klaviyo profile with name, organization, and custom properties without firing an event.
{
"name": "user login",
"data": {
"firstName": "Jane",
"lastName": "Doe",
"company": "Acme Corp",
"plan": "premium"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"email": "user@acme.com"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "3c881975d9a66145",
"trigger": "test",
"entity": "user",
"action": "login",
"timestamp": 1700000103,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"silent": true,
"settings": {
"identify": {
"map": {
"firstName": "data.firstName",
"lastName": "data.lastName",
"organization": "data.company",
"properties": {
"map": {
"plan": "data.plan"
}
}
}
}
}
}profilesApi.createOrUpdateProfile({
"data": {
"type": "profile",
"attributes": {
"email": "user@acme.com",
"externalId": "us3r",
"firstName": "Jane",
"lastName": "Doe",
"organization": "Acme Corp",
"properties": {
"plan": "premium"
}
}
}
})Identity is resolved automatically from each event: email defaults to user.email and externalId defaults to user.id. Klaviyo requires at least one identifier (email, phoneNumber, or externalId) per event. Events without any identifier are skipped with a warning.
Revenue tracking
Map a mapping rule's settings.value to a numeric event property. When settings.currency is also set, the destination adds valueCurrency on the Klaviyo event for revenue reporting.
Ecommerce metric naming
Klaviyo's built-in flows and reports key off specific metric names. Use mapping.name to rename walkerOS events to Klaviyo's expected values:
| walkerOS Event | Klaviyo Metric | Unlocks |
|---|---|---|
product view | Viewed Product | Product analytics |
product add | Added to Cart | Cart abandonment flows |
order complete | Placed Order | Revenue reporting, CLV |