Privacy, consent and your data
What the SDK collects, cookies, consent, excluding pages, uninstalling and deleting data.
What does the analytics SDK collect, and where does it send it?#
The package is @heycatch/sdk, MIT licensed, and it sends to exactly one host, in.heycatch.ai. One path for events and one static script. It makes no requests to any third-party analytics host from your site.
Captured automatically: pageviews, page leaves, clicks, rage clicks, the fact that a form was submitted, and route changes in single-page apps, the full URL including path segments, the page title of every pageview, and IP, device and browser. Capturing starts as soon as init runs, unless you hold it for consent, see "How do I hold analytics until a visitor consents?".
Clicks include the text of the element that was clicked, for example the label on a button. That is deliberate. Those labels are what the dashboard uses to describe what a visitor actually did, so it can tell you someone pressed "Start free trial" and then rage-clicked a broken control, rather than reporting that they clicked an element. You can switch that off yourself, see "Does the SDK record the text on the buttons my visitors click?".
Not captured: the contents of form inputs, so nothing anyone types into a field. There is no session replay and no screen recording, neither is in the SDK at all. Ad-click identifiers are stripped out of the URLs it captures.
Everything else is explicit: events you write yourself, and identity if you call setIdentity, which carries only the properties you pass.
Two things to keep out of it on your side: names or emails in a URL or a page title, and a visitor's name or email shown as the text of something they click.
Does the SDK record the text on the buttons my visitors click?#
Yes, and it is worth knowing exactly what that means before you answer for it in your own privacy policy.
When a visitor clicks something, the SDK records the label on the element they clicked, for example "Start free trial" or "Pricing". It is a deliberate choice rather than a default we left on: those labels are what makes your dashboard readable, because the per-user and per-session summaries describe what someone actually pressed instead of reporting an anonymous click. By default nothing strips the labels.
What it does not record is the contents of form inputs, so nothing your visitors type into a field. There is no session replay and no screen recording either.
If your situation requires clicked labels not to be captured, you can switch that off yourself in analytics.init, from SDK version 0.8.0.
- maskAllText: true removes the text of clicked elements.
- autocapture: false turns off the automatic capture of clicks and form submissions altogether. Pageviews, page leaves and rage clicks are still recorded.
Both have a cost. Without the text, the recap can no longer name the places where visitors struggle, and with autocapture off the dashboard sees pageviews and only the events you send yourself. The SDK says so once in the console.
Does the analytics SDK write cookies or local storage?#
Yes, one entry in each, and both hold the same thing: a device id, your own user id if you call setIdentity, a session id with a 30 minute timeout, the referrer and the first URL seen, plus SDK and framework metadata. The cookie expiry is one year.
With a consent banner you can hold all of it back: pass optOutCapturingByDefault: true in analytics.init, and nothing is written to the browser's storage, and nothing is sent, until you call analytics.optInCapturing(). The steps are in "How do I hold analytics until a visitor consents?".
Is capturing off until I call optInCapturing()?#
No. Capturing is on as soon as analytics.init runs, so a site without a consent banner needs nothing more.
It starts off only if you pass optOutCapturingByDefault: true to analytics.init. Then nothing is sent, and nothing is written to the browser's storage, until you call analytics.optInCapturing().
If you read the SDK bundle you will see opt_out_persistence_by_default set on every init. That is a different setting: it only keeps browser storage off for a visitor who has opted out, and it opts nobody out.
How do I hold analytics until a visitor consents?#
Pass optOutCapturingByDefault: true in analytics.init. Until the visitor agrees, nothing is sent and nothing is written to the browser's storage.
- When the visitor accepts, call analytics.optInCapturing().
- If they later withdraw, call analytics.optOutCapturing().
Call both only after analytics.init has run. Before it they do nothing and log a [HeyCatch] warning in the console.
Can I exclude my logged-in or sensitive pages from analytics tracking?#
Not by page address. Once init runs, automatic capture applies across the app, and there is no route allowlist or blocklist to set. One thing does work inside a page: add the class ph-no-capture to an element, for example the container of your logged-in area, and clicks and form submissions on it and everything inside it are not captured. Pageviews of those pages are still recorded.
What you can do is hold all capturing until a visitor consents, or switch off the text of clicked elements or the automatic capture of clicks: see "How do I hold analytics until a visitor consents?" and "Does the SDK record the text on the buttons my visitors click?".
If excluding your authenticated area is a hard requirement, tell us and we will treat it as a blocker rather than sell you a workaround.
Is my analytics project key a secret? Should I keep it out of client code?#
No, it is publishable by design. It starts with hck_pk_ and is inlined in your client bundle, where anyone viewing your site can read it. Treat it like a public analytics id rather than an API secret. There is no environment variable to set for it.
Is the analytics data processed by an AI model?#
Yes. The event stream is summarised by a large language model to produce the per-user and per-session narratives you see in the dashboard. We route it through OpenRouter to leading commercial models and do not disclose the specific models. OpenRouter is named on our published sub-processor list. The data is never used to train models, and providers may keep prompts for a limited period for abuse prevention. If that is not acceptable in your environment, raise it before you install rather than after.
How do I uninstall the SDK, and what happens to the data it collected?#
To uninstall: remove the package and the init call, plus the redirect rule if you added one for short links.
On the data: end-user analytics collected by the SDK are collected only while your subscription is active. After the subscription ends they are kept for 2 months so you can reactivate, then deleted or irreversibly anonymised, unless you reactivate or ask for earlier deletion. Deletion on request goes to support@heycatch.ai. The DPA and the sub-processor list are published on our site.
One of my own users asked me to delete their data. How do I do that?#
Email support@heycatch.ai with that person's user id or email address and we delete their data by hand. There is no API endpoint for it and no control in the dashboard, so a request to us is the only route.
That matters if you ship on the App Store or Google Play, where an in-app account-deletion path is a store requirement: your app can delete its own record of the person, but the analytics we hold for them is a request to us rather than something your app can call.