What we collect
The Traceten snippet collects the following signals on each pageview. Every field listed here is necessary for AI traffic detection, session management, or the per-session figures we report back to you. We do not collect anything else. A few of the fields we store are derived on our servers from the signals below, rather than read from the visitor. The table says so where that applies.Signals collected
We store most behavioral signals, such as scroll depth and mouse movement, only on the individual event record. Four things are also summarized per session: the number of pageviews, the total time your pages spent in the foreground of the visitor’s browser, the first page of the visit (the entry page), and its last page (the exit page). The entry and exit pages are page URLs we already store on the individual event records; summarizing them per session lets us show a visit as a journey with two ends rather than an undifferentiated list. Session records are keyed by visitor, so the sessions one visitor had on your site can be read together for as long as those records are retained (see Data retention). We rely on that to connect a conversion back to the AI referral that led to it, which is what this product exists to measure. A deletion request removes every session record for that visitor.
What we receive on the server
When the snippet sends an event toingest.traceten.com, the Cloudflare Worker receives:
- The payload above
- The visitor’s IP address (used only for hashing; see below)
What we do NOT collect
-
Email addresses, names, or phone numbers, in our analytics stores. They are never written to the analytics database, and never written to a log. Two paths do handle an address before that point, and both are described below rather than glossed over.
traceten.identify(). If you call it, the snippet reads the address you pass and sends it to our edge. The edge hashes it there, clears the plaintext before the request returns, and stores only the hash. The snippet does not read an address on any other code path, and never reads form fields to find one. The revenue paths. The Stripe, Shopify, Lemon Squeezy and Polar integrations take the customer email from the order, and the Payment API accepts an optionalemailfield. Paddle is the exception: no email reaches us at all. Paddle does not put the buyer’s address on a transaction, and Traceten does not ask for one: it creates the notification destination withinclude_sensitive_fieldsset to false and never requests the customer record, so a Paddle payment is matched by the visitor id you pass through checkout or not at all. On the other paths the address is placed on our internal processing queue and hashed when a separate process consumes it, usually within seconds. It is not hashed in the same operation that receives it, so for that short window the plaintext exists on the queue. It is never indexed, never retrievable through any customer-facing surface, and ages off the queue on its own. See Data subject rights for what that means for an erasure request. One moment is not a trickle. Connecting a store or a payment account imports your existing orders so your revenue history is not blank on day one, and that import puts every one of those orders on the same queue in a single burst: up to 90 days of them, 60 for Shopify. Each carries the buyer’s email, each is hashed by the same consumer within seconds, and each ages off on the same schedule. Nothing different happens to them. What changes is the number of people briefly represented on that queue at once, which is why it is stated here rather than left to be inferred from the sentence above. - Form field contents. The snippet does not read input values.
- Passwords or payment information. The snippet does not interact with sensitive form fields.
-
URL parameter values that carry personal identifiers. The value of any parameter whose name is a known personal-data parameter (
email,token,access_token,id_token,code,state, and others) or containstoken,secretorkeyis replaced with the literalREDACTED. This covers parameters in the query string and in the fragment after#(where sign-in callbacks often put tokens), in the page URL, the referrer and the clicked link. The snippet does it before the URL leaves the browser, and our ingestion edge applies the same rule to every event it receives, including events from server SDKs and direct API calls. To be precise about what that does and does not do: the parameter name itself remains in the URL, every other parameter is kept as it was, and a hash route such as#/pricingis left unchanged. We do not remove the query string from the page URL, becauseutm_source,utm_campaignandrefare read from it, as described in the table above. - Raw visitor IP addresses. A visitor’s IP address is hashed with HMAC-SHA-256 under a per-site key at the edge (Cloudflare Worker) before any storage. The raw value is never written to ClickHouse, logs, or disk. See the AI crawler exception below, which is not visitor data.
- Location finer than the city. We derive the country and city from the IP address at the edge. We never derive from a visitor, or store, the region, postcode, street address, or GPS coordinates, and we never ask the browser for its location. Dashboard maps do not change this: when a map needs a point to draw, we look the city name up in a public list of city centre coordinates as the page is rendered. That point belongs to the city, not to the visitor: everyone in a city gets the identical point, it is never written to your data, and no request about a visitor is sent to any location service. See Third-party data and licences.
- Network operator (ASN). Not recorded, for visitors or for AI crawlers.
- Cross-site tracking data. The session and visitor cookies are first-party, scoped to your domain. They cannot be read by Traceten on any other site. Nothing we store links a visitor on your site to the same person on another site. (One value used purely to block abuse is shared across sites for one hour, and is never written to any record. See How IP hashing works.)
AI crawler IP addresses
This section is about AI crawlers fetching your pages, not about people visiting your site. If you have not installed AI crawler tracking, none of it applies to you. An AI crawler’s connection terminates at your server, not at ours, so its IP address is observable only there and your server reports it to us. We use it to check the crawler’s claimed identity against evidence the vendor publishes: first against the IP ranges the vendor publishes, and, if that does not match and the claimed vendor supports it, by a reverse DNS lookup. That lookup sends the address to Cloudflare’s public DNS resolver to see whether it resolves back to the vendor’s own hostname. The address is sent before we know whether it belongs to a crawler at all, on failed attempts as well as successful ones, unless a recent identical lookup is still cached. That cache holds the address itself, in memory on the machine that made the lookup, for up to one hour; it is never written to disk and never logged. We retain that raw IP address in exactly two cases:- It fell inside an IP range the vendor publishes for that specific crawler.
- Its reverse DNS forward-confirmed to the vendor’s own domain.
How IP hashing works
This describes the visitor path. AI crawler IP addresses follow different rules, including two cases where we keep the raw address. See AI crawler IP addresses. When a visitor event arrives at our Cloudflare Worker:- We extract the IP address from the connection.
- We derive a key unique to your site:
HMAC-SHA-256(key = server_secret, message = site_id). - We compute the hash:
HMAC-SHA-256(key = your_site_key, message = IP). - We store only the hash.
- The raw IP is discarded before the event is written anywhere.
A second derivation, used only to block abuse
Rate limiting has to recognise one client sending traffic to many sites at once, which a per-site hash cannot do. For that we compute a separate value:HMAC-SHA-256(key = shield_secret, message = IP + current hour).
This value is the same for one IP across every site, for one hour. It exists to stop floods and denial-of-service traffic, and we handle it accordingly:
- It is never written to an event, a log, or any database. It exists in memory for the life of the request and in a rate-limit counter that deletes itself.
- It rotates every hour, so it cannot be used to follow anyone over time.
- It is never combined with a site identifier, a visitor ID, or anything else we store.
Cookies set
All cookies are first-party (scoped to your domain, not ours) and
Secure on HTTPS connections. SameSite varies by cookie: _traceten_sid and _traceten_vid use SameSite=Lax so a visitor’s identity survives their first hit from an AI-answer link; _traceten_optout uses SameSite=Strict. _traceten_consent carries whatever your CMP sets, since your CMP writes it, not Traceten. See Cookies for the full breakdown.
For more on cookies, see Cookies.
Opt-out and Do Not Track
The_traceten_optout cookie and the DNT: 1 header both put the snippet into opt-out mode. We treat them identically.
To set the opt-out cookie programmatically:
- The persistent
_traceten_vidvisitor cookie. A transient in-memory ID is used instead, so visits cannot be joined across sessions. - The higher-entropy device signals: WebGL support, canvas entropy, approximate JavaScript heap size, timezone offset, and paste detection.
- The
_traceten_cartShopify cart token. - Exit events, click tracking, and in-app navigation tracking.
- Goals fired from the
data-traceten-goalanddata-traceten-scrollHTML attributes: neither the click listener nor the scroll observer is installed at all. traceten.identify()and customtraceten.track()calls, which become no-ops.
_traceten_sid session cookie is also still written.
Screen size, language, and timezone are fingerprinting inputs in their own right. Opt-out mode reduces how identifiable a visitor is; it does not make them anonymous.
If you need collection to stop outright, use a consent tool and set the consent state to denied. That is enforced on our side: no event is stored. To remove data we already hold for a visitor, use the deletion API.
Data retention
These are retention limits: how long we keep a record before deleting it. They are not a statement that a record of that age exists. A limit that has recently been raised takes the full period to be reached, because raising it does not restore anything already deleted. Retention depends on the kind of record:- Raw event data is stored at full granularity for 730 days (two years), then permanently deleted.
- Session-level records, which are keyed by pseudonymous visitor and session identifiers, are kept for at least 730 days and at most 760 days. Deletion runs on monthly storage partitions, so the exact expiry date for a given session falls between those two bounds. Quote the 730 figure: it is the one we guarantee for any individual session.
- Custom events you send with
traceten.track(), with a goal attribute such asdata-traceten-goal, or from a server SDK, are kept for 365 days (each one also writes a visitor step record, retained for 730 days, described below). This is shorter than the raw event data above, so a session from more than a year ago can show pageviews on its timeline with no custom events around them. Each one holds the event name you chose, any properties you attached, and the pseudonymous visitor and session identifiers. Every property value is scanned on arrival for email address, phone number, payment card and national ID patterns, and any match is replaced with a redaction marker. That scan is the same one on every route data can arrive by.
email, phone, name, password, token, ssn, credit_card or card_number is dropped before storage when it arrives from a website snippet or a server SDK. It is not dropped on /v1/ingest/conversions, the authenticated ingestion API you can call with a server API key: there the value is scanned and redacted as everywhere else, but a property named email is stored under that name. Beyond that fixed list of eight, keys are not inspected for meaning on any route, so a key you invent is stored as you sent it, except that a key longer than 40 characters is dropped by the browser snippet before sending.
Events arriving at the ingestion endpoints are capped at 20 properties with string values truncated to 256 characters; the account API rejects an over-limit payload outright instead of truncating it. Events sent from a browser are clamped further before they are sent at all, to 10 properties with values truncated to 200 characters. What those properties contain is decided by you, in your own code or in a data-traceten-goal-* attribute on your page, so treat anything you put in them as data you are choosing to retain for a year.
- Visitor step records are kept for 730 days. Every pageview and every goal completion also writes one narrow row here, holding the pseudonymous visitor identifier, the session identifier, a timestamp, the URL path (query string and fragment removed) and, for a goal, its name. No property values are stored in it. It is what funnel questions are answered from, and it is retained for the same period as the raw event data above, so a funnel is not limited to a shorter window than the pageviews it counts. A deletion request removes it along with everything else.
- Aggregated dashboard metrics (daily rollups such as pageview counts, revenue by AI source, top pages, and visits by country, device type and referring site) contain no visitor or session identifier column; distinct-visit counts are stored as approximate aggregate sketches derived from hashed session identifiers. One rollup, the daily visitor count, derives its sketch from the hashed visitor identifier instead, and is retained for 730 days rather than for the life of your account for that reason. Most are retained for the life of your account. They are what powers year-over-year trend reporting. Top-page rollups include the page URL as it was received. For a pageview sent by the tracking snippet, the values of personal-data query parameters have already been replaced in the browser as described above. That replacement happens only in the browser. A pageview sent from one of our server SDKs, or posted directly to our server-side events endpoint, is stored with the URL exactly as you sent it, including its query string; nothing on that path rewrites it. If you send pageviews from your own server, remove personal data from the URL before you send it.
- Top pages by country is one of two aggregated rollups we do not keep for the life of your account (the daily visitor count above is the other). It records, per day, which page URLs were read from which country, and it is deleted after 730 days. It is kept for a shorter time than the rollups above precisely because pairing a page with a country is more revealing than either on its own.
-
Payment Link signals pair a provider’s transaction id with the visitor whose browser reported it, as described in the table above. Each one holds the site key, the provider, that transaction id, and the pseudonymous visitor and session identifiers. No email, no name, no amount. A signal is kept in two places:
- On our internal processing queue, for up to about 25 hours. This applies to every signal we accept, whether or not it ever pairs with a payment and whether or not your site uses that provider.
- In our database, for up to 60 minutes, and only when your site has connected that payment provider (for Dodo, when the site’s account holds a live server API key). A signal for any other provider is dropped when it is read off the queue and is never written to the database. A job running every two minutes deletes stored signals past the 60 minutes. The visitor and session identifiers are cleared as soon as the pairing is used or refused, which is normally within seconds. A pairing more than 30 minutes apart is refused. One case runs longer: if we have started moving an order onto the visitor and cannot finish, for example because our analytics store is unavailable, the stored signal is kept and retried until the move completes, so the order’s revenue is not lost. It keeps its visitor identifier while it waits, unless a deletion request removes it; the order is then completed without a visitor, as unattributed revenue.
- Individual AI crawler records are stored for 90 days, then permanently deleted. This applies only if you have installed AI crawler tracking. For how we handle a crawler’s IP address inside that window, see AI crawler IP addresses.
- AI crawler rollups (daily counts by crawler, by page, and by page and crawler) hold no IP address in any form, and no visitor or session identifier. We retain them for the life of your account, which is what keeps your crawl trends available after the 90-day records above expire.
- AI visibility answers are stored for 90 days, then permanently deleted. This applies only if AI visibility is running for your account. Each record holds the verbatim answer an engine returned (up to 100,000 characters) and its citation list (up to 100 citations, each with a title up to 512 characters and a URL up to 2,048), alongside the prompt identifier, the engine, the exact model identifier, the tool configuration, the locale and the timestamp. Citation URLs have their query string and fragment removed before storage.
- AI visibility mentions and citations are kept for 365 days. A mention holds a verbatim span of up to 500 characters around where your brand was matched, with its confidence score and how it was matched. A resolved citation holds the URL, its path and its domain. They outlive the answers above so that a year of trend data is not limited to the shorter window of the evidence behind it.
- AI visibility brand rollups (daily counts per prompt, engine and brand) hold counts only, and are retained for the life of your account.
- AI visibility citation rollups (daily counts per cited link) are retained for the life of your account and are not counts-only: each row keeps the cited URL, its path and its domain, because that is what a year-over-year citation trend is made of. Those links are third-party pages an engine chose to cite, not pages anyone on your site visited, but a URL can identify a person on its own. This is the only visibility record that has no expiry and holds more than counts.
Chart notes your team writes
Chart notes are not visitor data. They are text your own team types onto a site’s traffic chart, and we store them only because you write them. For each note we keep:- The text, with leading and trailing whitespace removed, up to 500 characters. A note containing control characters or text-direction overrides is refused.
- The day it is pinned to, and when it was created and when it was last changed.
- Who wrote it and who last changed it, as the identifiers our authentication provider gives us. Never a name or an email address. A note written with an API key is attributed to the team member who created that key.
- How it was written and last changed: in the dashboard, with an API key (and which key), or through an AI assistant connected to your account.
deleted-user on every note, on every account.
Do not put personal data in a note.
AI crawler records and AI visibility answers both stay at 90 days deliberately. The crawler screens read individual records only for the last few days, and every longer-range chart on them comes from the rollups, so a longer window there would store more without showing you more. The same reasoning applies to stored answers: the rates and trends come from the rollups, and the answers exist so you can read the evidence behind a recent number.
You can delete all stored data for an individual visitor, a site, or your whole account at any time, ahead of any of these schedules. See Data deletion.
One limit is worth stating precisely, because it is a property of the storage rather than of the API.
The aggregate sketches described above have no visitor or session identifier column to match on, so a per-visitor deletion cannot single them out, and the structure itself has no way to remove one input. Deleting the site or the account clears them completely. For the rollups we keep for the life of the account, that is the only thing that clears them. There is no retention limit to fall back on. For the two time-limited rollups, the daily visitor count and top pages by country, they also expire on their own after 730 days.
What a sketch is, stated accurately rather than reassuringly: an approximate distinct-count structure. It cannot be read back to produce a list of who was counted, and nothing in the product joins it to an individual. But below a certain size it retains a hash of each distinct identifier it counted, which means that if someone already holds a particular visitor identifier, they can test whether it is present. We do not do that, and no feature is built on it, but the capability is what makes us describe these as bounded rather than as anonymous.
