Executing JavaScript using Snapshots


Snapshots are typically used by non-devs to capture additional metadata as an event property that’s not automatically captured by Heap. They can also be used by developers to trigger custom JavaScript on your website without capturing any event properties.

We can leverage Snapshots to trigger client-side APIs whenever an event is triggered. This doc covers use cases where Snapshots are used to trigger JavaScript without returning an event property.

For a general overview of how Snapshots work and use cases for non-devs, see the Snapshots guide in our Help Center. To set up a JavaScript Snapshot from the event definition page, click the Add Snapshot button and select to value of javascript in the drop-down.


Since we’re not capturing any metadata with these use cases, the events with these Snapshots will not return any event properties for the Snapshot.

Use Cases

Find the Index Position of a Selected Element in a List

You may want to know the position of an element in a list or grid that users are selecting. Use this snapshot template to capture the index position of the element that has been selected.


The Javascript below will not work as-is since some of the selectors must be customized to correctly match your site. Do not copy/paste this as-is. This is for conceptual example purposes only.

Name: Tile Position
Javascript Snapshot:

(function() {
    var selector = 'li.h-full' // Replace this CSS! Selector must target all of the elements in the list
    var selected_element = event.target.closest(selector)
    var all_elements = document.querySelectorAll(selector)
    return Array.prototype.indexOf.call(all_elements, selected_element);

Call APIs

Since Snapshots can trigger JavaScript on your page, Snapshots can be used to call third party APIs, including Heap’s API. As an example, the snippet below adds your users’ most current timezone as a property.

Name: Add timezone as user property

JavaScript Snapshot:

(function() { var tz = Intl.DateTimeFormat().resolvedOptions().timeZone; heap.addUserProperties({ "Timezone": tz }); })();

The Snapshot above is used to trigger Heap’s client-side user property API, and it doesn’t return any data for the Snapshot property. The “Add timezone as user property” name is used simply to let us know what the Snapshot does for this example.

Once captured, you can use this data in your analysis to understand how well your geographically targeted ads are performing.

Check if Users Have Enabled Browser Push Notifications

On modern browsers, you can check how many of your users have enabled your browser push notifications. You can do something similar for checking location permissions if your app depends on it. (This is only supported in select modern browsers.)

Name: Add push notification status as user property

JavaScript Snapshot:

navigator.permissions.query({ name: 'notifications' }).then(function(result) { heap.addUserProperties({"Notifications Permission": result.state }); })

Add Timezone as a Heap User Property

To further enrich your Heap user data, you can capture users’ timezones. The Snapshot below adds the user’s current timezone as a Heap user property by triggering Heap’s client-side [heap.addUserProperties()](https://developers.heap.io/reference#adduserproperties) API. You can have this attached to any event that triggers at least once for users, like a pageview.

JavaScript Snapshot:

(function() {
    var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
        "Timezone": tz

Capture User State (Tealium)


This example is for customers using our Tealium integration.

This example captures the logged-in user state from a site using Tealium. Other common examples include page_type, site_section, or visitor_type. Use this type of data for high-level content analysis, or to understand how user state affects key behaviors.

Name: Logged In

JavaScript Snapshot


Analyze Image Types

eCommerce companies often AB test their images. But how can you tell which type of photography converts best: a lifestyle action shot vs a standard product shot? This example captures the name of the image file when clicked. Assuming you have some semantic data in the title that denotes the shot type, you can use this data within a Defined Property to analyze the effectiveness of different image types.

Name: Image

JavaScript Snapshot:



This example requires jQuery to execute correctly.

Capture Page Load Time


We do not recommend using the Page Load Time Snapshot on a single page app. Each pageview of a single page app ends up returning the same load time, which creates duplicate results.

It may be important for you to know how long it takes for your page to finish loading and how that affects user behavior. We are unable to capture page load time as an event property on a default pageview event because Heap captures a pageview event before the page finishes loading.

The Snapshot below calculates how long it takes for your page to completely load, and it captures a custom Page Load event with a Load Time event property by triggering Heap’s client-side heap.track() API. You can attach this to a View Any Page pageview event to trigger this JavaScript whenever a user views a page on your website.

Snapshots can be used to run custom Javascript without actually having to return a value, and as such, this example is used to track a completely new event. Note that it does not actually record a Snapshot property.


The performance.timing object can be unreliable. For this reason, we recommend excluding all negative values returned by the browser. For more details, see Mozilla’s documentation on this object.

Due to DOM event timing, this can’t be added as an event property, though you can write code similar to the Call APIs use case and fire a track call with the property.

Name: Page load

JavaScript Snapshot:

(function() { var interval = setInterval(sendTrack, 200); function sendTrack() { if (performance.timing.domComplete != 0){ var loadTime = (performance.timing.domComplete - performance.timing.navigationStart) / 1000; heap.track('Page Load', { 'Load Time': loadTime }); clearInterval(interval); } } })();

See how page load time affects your key funnels by starting your analysis with this event and grouping by load time!


Navigation timing events do not update after changes to the History API. The above method will not work on Single Page Applications.

Check if Users Have Enabled Browser Push Notifications

On modern browsers, you can check how many of your users have enabled your browser push notifications. You can do something similar for checking location permissions if your app depends on it (not compatible with all browsers).

The Snapshot below adds whether the user has enabled push notifications or not as a Heap user property by triggering Heap’s client-side [heap.addUserProperties()](https://developers.heap.io/reference#adduserproperties) API.

    name: 'notifications'
}).then(function(result) {
        "Notifications Permission": result.state

Scroll Tracking

Capturing how far users scroll on your website is important to see if users are viewing all of the content on a page. The Snapshot below measures the full length of a page, and it captures a custom Scroll Depth event by triggering Heap’s client-side heap.track() API every time a user scrolls a 25% of the full length (25%, 50%, 75%, 100%).


Scroll depth is calculated on the scroll location within the body element. If the content on your website is contained within a container element, then this Snapshot will not function as expected.

(function() {
    var quarters = 0;
    var scrollHeight, quarterHeight, scrollDistance, divisible, scrollPercent;
    document.addEventListener("scroll", function() {
        scrollHeight = document.documentElement.scrollHeight - window.innerHeight;
        quarterHeight = scrollHeight / 4;
        scrollDistance = window.pageYOffset || (document.documentElement || document.body.parentNode || document.body).scrollTop;
        divisible = Math.trunc(scrollDistance / quarterHeight);
        if (quarters < divisible && divisible !== Infinity) {
            scrollPercent = divisible * 25;
            heap.track('Scroll Depth', {
                percent: scrollPercent

Capturing Data from the Data Layer

You can capture any additional pieces of data within your data layer object by calling for the piece of data within the JavaScript snippet.

As an example, let’s say your data layer object (called data) is set up so that {id:"123", name:"foo"}. You would capture the objects within this data layer per the examples below.

Capture ID

Capture Name

Disabling JavaScript Snapshots (Admins only)

Admins can disable JavaScript Snapshots by navigating to Account > Manage > Privacy & Security and clicking the JavaScript Snapshots toggle.