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). That SDK does not replay
the calls the destination queues before it finishes loading, so events pushed
earlier (such as the first page view) do not reach Heap. It also ignores
disablePageviewAutocapture, disableSessionReplay, and ingestServer, and
has no startTracking() or stopTracking(), so any consent command after it
has loaded stops all further Heap events (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. | |
disablePageviewAutocapture | boolean | Disable Heap automatic pageview tracking. Default: true (walkerOS sources handle pageviews). Passed to heap.load(); the classic Heap SDK that loadScript loads ignores it. | |
disableSessionReplay | boolean | Disable Heap session replay. Passed to heap.load(); the classic Heap SDK that loadScript loads ignores it. | |
secureCookie | boolean | SSL-only cookies. | |
ingestServer | string | Custom server endpoint for proxying Heap data. Passed to heap.load(); the classic Heap SDK that loadScript loads ignores it. | |
heapConfig | Record<string, any> | Additional heap.load() options, merged over the options above. 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
}heap.startTracking()Consent revoked
With consent: { analytics: true } in the destination config, the destination calls heap.startTracking once analytics is granted and heap.stopTracking when it is revoked. The classic Heap SDK that loadScript loads has neither method.
{
"analytics": false
}heap.startTracking();
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": "e131862053adef0a",
"trigger": "load",
"entity": "product",
"action": "view",
"timestamp": 1700000100,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}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": "0474dc6b65de51c0",
"trigger": "load",
"entity": "page",
"action": "view",
"timestamp": 1700000102,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}heap.identify("us3r");
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,
"total": 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": "95b2d7e59e2ce094",
"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.total",
"currency": {
"key": "data.currency",
"value": "EUR"
}
}
}
}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",
"total": 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": "3f227884f15ee8f1",
"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.total",
"last_order_currency": "data.currency"
}
}
}
}heap.addUserProperties({
"last_order_value": 555,
"last_order_currency": "EUR"
});
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": "85ff0c61027934a7",
"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"
}
}
}
}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": "b8517a745dbbbd32",
"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"
}
}
}
}heap.identify("user@example.com");
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": "d6224500fb023f74",
"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
}
}heap.resetIdentity()Consent
With config.consent declared, the destination is not loaded before the
required consent keys are granted (see
consent management). On each consent command it calls
heap.startTracking() when all required keys are granted and
heap.stopTracking() otherwise.
The classic SDK that loadScript: true loads has neither method. The grant
that loads Heap works, but once the script has loaded, every later
walker consent command, even one that repeats the current state, makes the
destination's on('consent') handler fail. The collector logs
on callback failed and holds the destination's events in its queue, so Heap
receives nothing for the rest of the page view, while elb still returns
ok. A revocation also does not stop Heap's own capture. This setup keeps
sending events only when your consent source sends no further consent command
after the grant that loads Heap.
destinations: {
heap: {
code: destinationHeap,
config: {
loadScript: true,
consent: { analytics: true },
settings: { appId: 'YOUR_HEAP_APP_ID' },
},
},
}