Heatmaps show where visitors click on each page, which of those clicks were rage clicks or dead clicks, and how far down the page each view got. They are drawn over your real, live page, so what you see is the page as it is today. Heatmap clicks and scroll depth are never billed.
Turn heatmaps on
Heatmaps are off for a new site. Open Heatmaps for the site and choose Enable heatmaps, or switch them on under Settings → Installation. A member or owner of the workspace can do it; a viewer cannot. The tracker reads the setting when it starts, so nothing changes in your code and no redeploy is needed.
Clicks are recorded from then on; earlier visits have none. Scroll depth comes from the engagement signal, which is on by default, so a page usually has scroll data before its first click.
What is recorded
| Signal | What counts |
|---|---|
| Click | A real pointer click on an element. Clicks fired by scripts or made with the keyboard are left out, and so are clicks on invisit’s own widgets. |
| Rage click | The third or later click within 30 pixels of the others inside one second: someone hammering a spot that did not respond. |
| Dead click | A click on a link, a button or anything with a pointer cursor that gets no visible reaction within one second: no change to the page, no input, no scroll, no change of #hash. |
| Scroll depth | The deepest point the bottom of the window reached in a page view, as a share of the page’s height, in 5% steps. |
A link or submit button that the browser follows itself is never a dead click, even when the next page takes more than a second. One whose click your code cancels and then does nothing is.
Each click is stored as the element it landed on and a cell in a 32 by 32 grid over that element, not as a position on the screen. The heat stays on the right element when the layout shifts or the window is a different width.
The element is named by a short path of tags, such as main>section:nth-of-type(2)>button:nth-of-type(1), never by its classes, its text or what anyone typed. Clicks on form fields record that the field was clicked, nothing more. The same consent rules as the rest of the tracker apply: with consent required, or with Global Privacy Control or Do Not Track honoured, no clicks are sent either.
Reading a heatmap
Pick a page from the list, busiest first, and Desktop or Mobile. Tablets count as desktop, since they get the desktop layout. The date range is the dashboard’s, like every other report.
Above the page you get the range’s clicks, rage clicks, dead clicks, average scroll depth and the share of views that reached the end, each against the previous period. Rage and dead clicks going up show in red. Hover any element for its own clicks, its share of the page’s clicks, and its rage and dead clicks. Show scroll depth adds bands that show how many views got how far down.
Two notes can appear:
- Clicks on elements no longer on this page. The element they were recorded on is gone or has moved, often after a redesign. They still count in the totals.
- Showing the busiest spots. A page with a lot of clicks draws its 5,000 busiest cells.
Showing your page in the dashboard
The dashboard loads your page in a frame and draws the heatmap over it. That needs two things:
- The invisit script or package on the page.
- Permission for the dashboard to frame it. If your site sends a
frame-ancestorspolicy, add the dashboard to it; if it sendsX-Frame-Options, replace that with this policy, which browsers apply instead:
Content-Security-Policy: frame-ancestors 'self' https://app.invisit.devWithout either, Open in a new tab shows the same heatmap on your page in its own tab, with a small toolbar. Size the window to the layout you are looking at: under 768 pixels wide is mobile.
The dashboard hands your page a short-lived token to read the heatmap with. It is taken out of the address at once, so it never shows up in your own analytics or history, and it expires after 30 minutes; open the heatmap from the dashboard again to get a new one. While the heatmap is open, that tab records nothing, so looking at heatmaps does not add to your traffic.
Keep clicks on the right element
Paths stop at the nearest element with a stable id. Ids that look generated, such as React’s :r1: or ones with three or more digits in a row, are skipped because they change between deploys. For an element that moves around, a card in a list or a button whose position changes with A/B copy, give it a name of its own:
<button data-invisit-id="pricing-cta">Start free</button>Its clicks then stay with it wherever it sits on the page. Clicks recorded before you add the attribute stay under the old path.
From the API
Two read-only reports, with an API key that can read analytics (REST API):
| Report | Address | Returns |
|---|---|---|
| Pages | GET /v1/sites/{site_id}/analytics/heatmaps?from=&to=&device= |
The 100 busiest pages, with clicks, rage clicks, dead clicks and scroll depth for each. |
| One page | GET /v1/sites/{site_id}/analytics/heatmaps/page?from=&to=&device=&hostname=&path= |
Its totals, clicks by device, its 20 busiest elements with their rage and dead clicks, and its scroll depth in 5% bands. |
device is desktop or mobile and defaults to desktop. hostname is the page’s host without www.. The MCP server reaches both through its API tools.