Skip to main content
Ask your AI

Heap

Web Source code Package Beta

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.

Where this fits

Heap is a web destination in the walkerOS flow:

Installation​

npm install @walkeros/web-destination-heap
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',
        },
      },
    },
  },
});
caution

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​

PropertyTypeDescriptionMore
appId*stringHeap App ID. Find it in your Heap project under Settings > App ID.
disableTextCapturebooleanDisable Heap auto text capture. Default: true.
disablePageviewAutocapturebooleanDisable Heap automatic pageview tracking. Default: true (walkerOS sources handle pageviews). Passed to heap.load(); the classic Heap SDK that loadScript loads ignores it.
disableSessionReplaybooleanDisable Heap session replay. Passed to heap.load(); the classic Heap SDK that loadScript loads ignores it.
secureCookiebooleanSSL-only cookies.
ingestServerstringCustom server endpoint for proxying Heap data. Passed to heap.load(); the classic Heap SDK that loadScript loads ignores it.
heapConfigRecord<string, any>Additional heap.load() options, merged over the options above. Example: { "trackingServer": "https://heap.example.com" }.
identifyanyDestination-level identity mapping. Resolves to a string for heap.identify(). Example: { "key": "user.id" }.
userPropertiesanyDestination-level user properties mapping. Resolves to object for heap.addUserProperties(). Example: { "map": { "plan": "data.plan" } }.
* Required fields

Mapping​

Per-event rules under config.mapping. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.

PropertyTypeDescriptionMore
identifyanyPer-event identity. Resolves to a string for heap.identify(). Example: { "key": "data.email" }.
resetanyReset Heap identity on this event. Set to true to call heap.resetIdentity().
userPropertiesanyPer-event user properties. Resolves to object for heap.addUserProperties().
eventPropertiesanyPer-event persistent event properties. Resolves to object for heap.addEventProperties() (persisted across page loads).
clearEventPropertiesanyClear 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.

Event
{
  "analytics": true
}
Out
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.

Event
{
  "analytics": false
}
Out
heap.startTracking();

heap.stopTracking()

Default track

A walker event becomes a Heap track call with the event name and empty properties.

Event
{
  "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"
  }
}
Out
heap.track("product view", {})

Destination identify

With settings.identify set to 'user.id', the destination calls heap.identify before the default track.

Event
{
  "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"
  }
}
Out
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.

Event
{
  "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"
  }
}
Mapping
{
  "name": "purchase",
  "data": {
    "map": {
      "order_id": "data.id",
      "total": "data.total",
      "currency": {
        "key": "data.currency",
        "value": "EUR"
      }
    }
  }
}
Out
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.

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"
  }
}
Mapping
{
  "settings": {
    "userProperties": {
      "map": {
        "last_order_value": "data.total",
        "last_order_currency": "data.currency"
      }
    }
  }
}
Out
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.

Event
{
  "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"
  }
}
Mapping
{
  "silent": true,
  "settings": {
    "eventProperties": {
      "map": {
        "page_category": "data.category"
      }
    }
  }
}
Out
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.

Event
{
  "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"
  }
}
Mapping
{
  "silent": true,
  "settings": {
    "identify": "data.email",
    "userProperties": {
      "map": {
        "plan": "data.plan",
        "company": "data.company"
      }
    }
  }
}
Out
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.

Event
{
  "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"
  }
}
Mapping
{
  "silent": true,
  "settings": {
    "reset": true
  }
}
Out
heap.resetIdentity()

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' },
    },
  },
}
💡 Need implementation support?
elbwalker offers hands-on support: setup review, measurement planning, destination mapping, and live troubleshooting. Book a 2-hour session (€399)