JavaScript reference
pagehum.js needs no setup beyond its tag. These are the knobs it has, and what it sends on its own.
Attributes
| Attribute | On | Does |
|---|---|---|
data-site | The script tag | Your site key. Required. |
data-requests="off" | The script tag | Stops watching your own fetch and XHR calls for failures. The snippet then leaves fetch and XMLHttpRequest untouched. |
data-pagehum-success | Any button, link, or form | Counts a success when it is clicked or submitted. Each click or submit counts, so put it on the final step. |
<button type="submit" data-pagehum-success>Start free trial</button>
pagehum.track()
For moments only your code knows about. Write calls as window.pagehum?.track(…) so nothing breaks if the script hasn’t loaded; the call is then skipped.
| Call | Counts |
|---|---|
track("success") | A success, e.g. after your server confirms a signup or payment. |
track("engage") | An engaged visit, if the default (15 seconds or half the page) misses real interest. Once per session. |
track("broken", "/path") | A broken hit on a path, when your app renders its own not-found view without a 404 status. |
track("error") | A client error on the current page. |
track("pageview") | A pageview, for navigation the snippet can't see. Route changes through history are already counted. |
const response = await fetch("/api/signup", { method: "POST", body });
if (response.ok) window.pagehum?.track("success");What it sends on its own
| When | Sends |
|---|---|
| Page load and each route change | A pageview with the cleaned path, source, and device class |
| First load in a tab | A session |
| First visit of a day | A visitor, with the days since the previous visit day |
| After the page loads | Load time, TTFB, LCP, and CLS, with the page and device class |
| After the page loads (with the timings) | The KB the page transferred, and its 5 slowest outside origins: origin only, how many requests, how long they took while the page loaded, and their KB when the browser shows it |
| The page's Content Security Policy blocks something | The directive and what it blocked, as an origin or a keyword like inline or eval; never the full URL, the source file, or the line (up to 5 per page load) |
| When the page is hidden or left | Its slowest interaction (INP), if there was a tap, click, or key press |
| A call to your own host gets a 5xx or no response | The method, path, status, and the page that made it (up to 5 per page load) |
| Three quick clicks in one spot | A rage click on the page (up to 3 per page load) |
| 15 seconds or half the page | An engaged visit, once per session |
| An uncaught error or rejected promise | A client error with the page and a short message (up to 5 per page load) |
| A 404 page or a failed same-site asset | A broken hit with its path and the same-site page that led there (up to 8 per page load) |
| Every minute while open | A heartbeat |
Everything goes to https://pagehum.com/api/ingest in small batches. Requests from localhost count; the demo key counts only on pagehum.com.
Two things are added at ingest, not by the snippet: the browser family and major version on client errors, from the request’s User-Agent, and the visitor’s country on pageviews, as the two letters the hosting edge reports. The IP address is never read.