Privacy & retention
What is collected, what is deliberately not, where it lives, and how long it stays. Written so you can hand it to a privacy officer without translating it first.
No cookies
The tracker sets no cookies of any kind. It keeps one item in localStorage containing a random visitor id, a visit count and a sampling decision. That storage is readable only by the site that set it, is not shared across domains, and is cleared when the visitor clears site data.
identify(). HLD is not giving you legal advice; ask your own adviser. What we can tell you is exactly what is stored, which is this page.Do Not Track
Honoured by default. A browser sending DNT is not tracked at all — no events, no session, and nothing written to their storage. Turn it off with data-dnt="false" only with a reason you can defend.
Never collected
| Name | Type | Required | Description |
|---|---|---|---|
| Form field values | never | No | Which field was focused is recorded. What was typed into it is not, and there is no setting that turns that on. |
| Keystrokes | never | No | Key events update an activity timestamp. The keys are not read. |
| Page text or screenshots | never | No | No session replay, no DOM snapshots, no video. |
| Copied or selected text | never | No | A copy is counted. A selection records its length only. |
| Cross-site identifiers | never | No | Nothing is shared between sites, and no third-party network is contacted. |
| Precise location | never | No | No browser geolocation prompt. Location is city-level, derived at the edge from the IP address. |
Personal data that is collected
| Name | Type | Required | Description |
|---|---|---|---|
| IP address | stored | No | Recorded on the session and on events, resolved at the Cloudflare edge from the connection rather than taken from the payload. Under GDPR this is personal data. |
| Approximate location | derived | No | Country, region, city, postal code and timezone, from the IP. |
| Network and organisation | derived | No | ASN, network operator, and reverse DNS. Identifies an organisation, not a person. |
| Device fingerprint | stored | No | A coarse device signature, so a cleared localStorage is still a recognisable device. Not shared with anyone and not portable between sites. |
| Name, email, company | only if you send it | No | Present only where your own site called identify(). Never inferred, never guessed from an address, and absent from every response for keys without the analytics:visitors scope. |
identify(), you are the one deciding that this data goes into an analytics record. Do it only with details the person gave you for a purpose that covers it, and reflect it in your privacy notice.Where it lives
- Ingest terminates at the Cloudflare edge and writes to HLD's Supabase project.
- Nothing browser-side ever talks to the database. Both ingest and reads go through server-side functions on a service role.
- Row-level security is enabled and closed on every table, so a leaked public key is not a list of anyone's visitors.
- No data is sold, shared between tenants, or sent to any advertising or third-party analytics network.
Retention
| Name | Type | Required | Description |
|---|---|---|---|
| Sessions and events | 400 days default | No | Set per site, between 7 and 1100 days. Anything older is deleted, not archived. |
| Heatmap and scroll aggregates | retained | No | Accumulated counts with no session or visitor attached — they survive the pruning of the events they came from, because there is nothing personal left in them. |
| App telemetry | pruned on schedule | No | Operational signal, not an audit log. |
Ask HLD to change a site's retention window, or to delete a specific visitor's records — the visitor id or an identified email is enough to find them.
Turning collectors off
Every collector can be disabled in the snippet, and disabling one stops collection rather than hiding a display. If your assessment says you should not be recording pointer movement or form interaction, set data-pointer="false" or data-forms="false" and neither is ever sent.
Sampling
data-sample reduces how many visitors are recorded at all. It is decided once per visitor rather than per page — sampling per page would cut sessions in half and make every funnel wrong — so an unsampled visitor is never recorded, not partially recorded.