Heap
Heap (now part of Contentsquare) is a product
analytics platform with auto-capture and retroactive event definitions.
With loadScript: true, this destination loads the Heap script from Heap's
CDN. It forwards walkerOS events through heap.track(name, properties), plus
identity, user properties, persistent event properties, and runtime consent.
Heap is a web destination in the walkerOS flow:
Installation
npm install @walkeros/web-destination-heap- Integrated
- Bundled
import { startFlow } from '@walkeros/collector';
import { destinationHeap } from '@walkeros/web-destination-heap';
await startFlow({
destinations: {
heap: {
code: destinationHeap,
config: {
loadScript: true,
settings: {
appId: 'YOUR_HEAP_APP_ID',
},
},
},
},
});Add to your flow.json destinations:
"destinations": {
"heap": {
"package": "@walkeros/web-destination-heap",
"config": {
"loadScript": true,
"settings": {
"appId": "YOUR_HEAP_APP_ID"
}
}
}
}loadScript: true loads the classic Heap SDK
(https://cdn.heapanalytics.com/js/heap-<appId>.js). Events pushed while the
script loads wait for it and reach Heap once it is ready; if the script is
blocked or fails to load, those and later pushes fail with vendor-not-loaded
and show up as failed events. disableTextCapture (default true),
secureCookie and further SDK options in heapConfig go into the config the
classic SDK reads when it loads, so they apply only with loadScript: true.
Without loadScript the destination ignores them and nothing reports it: set
these options in your own Heap snippet. The classic SDK has no switch to stop
tracking, so a consent revocation stops the events walkerOS sends but not
Heap's own autocapture (see Consent).
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 |
|---|---|---|---|
appId | string | Heap App ID. Find it in your Heap project under Settings > App ID. | |
disableTextCapture | boolean | Disable Heap auto text capture. Default: true. Applied only with loadScript: true, in the config the classic Heap SDK reads when it loads; with your own Heap snippet, set it there. | |
secureCookie | boolean | SSL-only cookies. Applied only with loadScript: true, in the config the classic Heap SDK reads when it loads. | |
heapConfig | Record<string, any> | Additional options for the classic Heap SDK, merged over disableTextCapture and secureCookie. Applied only with loadScript: true. Example: { "trackingServer": "https://heap.example.com" }. | |
identify | any | Destination-level identity mapping. Resolves to a string for heap.identify(). Example: { "key": "user.id" }. | |
userProperties | any | Destination-level user properties mapping. Resolves to object for heap.addUserProperties(). Example: { "map": { "plan": "data.plan" } }. |
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 identity. Resolves to a string for heap.identify(). Example: { "key": "data.email" }. | |
reset | any | Reset Heap identity on this event. Set to true to call heap.resetIdentity(). | |
userProperties | any | Per-event user properties. Resolves to object for heap.addUserProperties(). | |
eventProperties | any | Per-event persistent event properties. Resolves to object for heap.addEventProperties() (persisted across page loads). | |
clearEventProperties | any | Clear all persistent event properties. Set to true to call heap.clearEventProperties(). |
Examples
Consent granted
With consent: { analytics: true } in the destination config, a walker consent grant for analytics calls heap.startTracking.
{
"analytics": true
}window.heap.startTracking()Consent revoked
With consent: { analytics: true } in the destination config, a revocation of analytics calls heap.stopTracking once Heap has loaded. The classic Heap SDK that loadScript loads has no such method, so there only the pushes stop.
{
"analytics": false
}window.heap.stopTracking()Default track
A walker event becomes a Heap track call with the event name and empty properties.
{
"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": "db22fb16c70f663d",
"trigger": "load",
"entity": "product",
"action": "view",
"timestamp": 1700000100,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}window.heap.track("product view", {})Destination identify
With settings.identify set to 'user.id', the destination calls heap.identify before the default track.
{
"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": "f0cc5f6fec3d8eeb",
"trigger": "load",
"entity": "page",
"action": "view",
"timestamp": 1700000102,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}window.heap.identify("us3r");
window.heap.track("page view", {})Renamed purchase
An order complete is renamed to purchase and mapped to Heap track properties such as order_id, total, and currency.
{
"name": "order complete",
"data": {
"id": "0rd3r1d",
"currency": "EUR",
"shipping": 5.22,
"taxes": 73.76,
"value": 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": "235d0d7bd7a213f2",
"trigger": "load",
"entity": "order",
"action": "complete",
"timestamp": 1700000101,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"name": "purchase",
"data": {
"map": {
"order_id": "data.id",
"total": "data.value",
"currency": {
"key": "data.currency",
"value": "EUR"
}
}
}
}window.heap.track("purchase", {
"order_id": "0rd3r1d",
"total": 555,
"currency": "EUR"
})User properties on event
An order fires Heap addUserProperties with last-order fields and then tracks the event.
{
"name": "order complete",
"data": {
"id": "0rd3r1d",
"value": 555,
"currency": "EUR"
},
"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": "235d0d7bd7a213f2",
"trigger": "load",
"entity": "order",
"action": "complete",
"timestamp": 1700000105,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"settings": {
"userProperties": {
"map": {
"last_order_value": "data.value",
"last_order_currency": "data.currency"
}
}
}
}window.heap.addUserProperties({
"last_order_value": 555,
"last_order_currency": "EUR"
});
window.heap.track("order complete", {})Global event properties
A page view sets persistent Heap event properties so all subsequent events include the page category.
{
"name": "page view",
"data": {
"category": "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": "f0cc5f6fec3d8eeb",
"trigger": "load",
"entity": "page",
"action": "view",
"timestamp": 1700000106,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"silent": true,
"settings": {
"eventProperties": {
"map": {
"page_category": "data.category"
}
}
}
}window.heap.addEventProperties({
"page_category": "docs"
})User login identify
A user login identifies the Heap user by email and adds user properties while skipping the track.
{
"name": "user login",
"data": {
"email": "user@example.com",
"plan": "premium",
"company": "Acme"
},
"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": "47f07df3d8014322",
"trigger": "test",
"entity": "user",
"action": "login",
"timestamp": 1700000103,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"silent": true,
"settings": {
"identify": "data.email",
"userProperties": {
"map": {
"plan": "data.plan",
"company": "data.company"
}
}
}
}window.heap.identify("user@example.com");
window.heap.addUserProperties({
"plan": "premium",
"company": "Acme"
})User logout reset
A user logout calls heap.resetIdentity to clear the identified user from the Heap client.
{
"name": "user logout",
"data": {
"string": "foo",
"number": 1,
"boolean": true,
"array": [
0,
"text",
false
]
},
"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": "9fb90fbd8836eb19",
"trigger": "test",
"entity": "user",
"action": "logout",
"timestamp": 1700000104,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"silent": true,
"settings": {
"reset": true
}
}window.heap.resetIdentity()Consent
With config.consent declared, the collector initializes the destination, and
with loadScript: true loads Heap's script, only once one of the required
consent keys is granted (see consent management). On
each consent command that names a required key, once Heap has loaded, the
destination calls heap.startTracking() while the required consent is granted
(one granted key is enough) and heap.stopTracking() otherwise.
The classic SDK that loadScript: true loads has neither method, so the
destination calls neither. A revocation then only stops the events walkerOS
sends: Heap's own autocapture keeps running because the classic SDK cannot be
switched off. To keep Heap from capturing
before consent, load Heap's script only after consent is granted, which is what
config.consent does with loadScript: true.
destinations: {
heap: {
code: destinationHeap,
config: {
loadScript: true,
consent: { analytics: true },
settings: { appId: 'YOUR_HEAP_APP_ID' },
},
},
}