Skip to main content

GDPR

Is Traceten GDPR-compliant?

Traceten is designed with GDPR compliance as a baseline requirement, not an add-on. Key properties:
  • No PII collected by default. The snippet does not collect names, email addresses, or any data that directly identifies an individual. Session and visitor IDs are random UUIDs with no link to personal data.
  • Visitor IP addresses are hashed immediately at the edge. A visitor’s raw IP is never written to ClickHouse, logs, or disk. The hash is an HMAC-SHA-256 under a key derived per site, so the same IP address on two different customers’ sites produces two unrelated hashes, and the hashes we store cannot be correlated across sites. One value used solely to block abuse is deliberately shared across sites for one hour and is never written to any record. See How IP hashing works and Lawful basis for abuse prevention.
  • One exception, and it is not visitor data. When an AI crawler fetches your pages, your server reports the crawler’s IP address to us and we check it against evidence the vendor publishes; where that check needs a reverse DNS lookup, the address is sent to Cloudflare’s public DNS resolver, before we know whether it belongs to a crawler. We retain that raw address for 90 days in exactly two cases: it fell inside an IP range the vendor publishes for that specific crawler, or its reverse DNS forward-confirmed to the vendor’s own domain. In every other case, including where the only evidence is that the address sits somewhere in the vendor’s wider network, we store an HMAC-SHA-256 hash under a per-site key and discard the address. We do not derive or store the network operator or country from a crawler IP. Individual crawl records are deleted after 90 days; the aggregate counts that remain contain no IP data. This applies only if you have installed AI crawler tracking. See AI crawler IP addresses.
  • First-party cookies only. No cross-site tracking. The session (_traceten_sid), visitor (_traceten_vid), and _traceten_cart (Shopify stores only) cookies use SameSite=Lax rather than Strict: sid/vid so identity survives a visitor’s first hit from an AI-answer link, cart to survive Shopify’s checkout subdomain redirect. Lax still restricts these cookies to top-level navigations; they are never sent on cross-site subresource requests. See Cookies.
  • Data deletion on request. Deletion API available on all plans. See Data deletion.
  • Data residency. You select a region when creating a site, and we record it. Region-based storage routing is not yet in place: all event data currently lands in one region regardless of what you select. See Data residency and sub-processors for where that is.
  • Data Processing Agreement (DPA). Available on request for accounts that require it.

Shopify cart token

For Shopify stores with the revenue attribution integration enabled, Traceten stores a Shopify checkout token (cart_token) alongside session events. This value is a pseudonymous identifier under GDPR Recital 26: it does not directly identify a natural person, but it resolves to one when joined with the Shopify order (which contains name, email, and shipping address held by you as the data controller). The cart token is:
  • Never written for opted-out visitors (_traceten_optout=1 or DNT: 1)
  • Stored only for the duration of the checkout session (24-hour cookie); the stored value expires with session-level data on the schedule described in Data retention
  • Subject to GDPR Article 17 erasure requests alongside all other session data for that visitor

Identity linking

If you call traceten.identify(), or if you use the Shopify revenue integration, Traceten links a visitor’s activity from before they identified themselves to their activity after. This exists for one reason. Someone discovers you through ChatGPT and browses anonymously. Days later they come back, log in, and buy. Those are two different visitor IDs. Without a link between them, the AI referral that produced the sale looks like it produced nothing, and you would have no way to know the channel worked. What is actually stored. A row containing:
  • the earlier anonymous visitor ID (a random UUID we generated)
  • a one-way hash of the email address or account ID you supplied
  • which route produced the link, and when
What is not stored. The email address itself never reaches this table. Only its hash does. This table stores no names, no profiles, and no behavioral segments. It holds the link itself and nothing else. What the link is used for. Reading one person’s own activity on your site as a single journey rather than two disconnected halves. That means joining their sessions to their conversions, and, in the session view, counting their pageviews and activity across the link so a revenue figure that spans both halves is not shown beside a visit count that spans one. It is never used to build a profile, to enrich one, or to connect a visitor across different sites. How the two routes work: Stripe has no separate server-side route. A Stripe Checkout Session already carries the visitor reference, and Stripe merchants link identity through identify() on their own site, so there is nothing for an order webhook to add. Shopify gets its own route because Shopify’s checkout runs on checkout.shopify.com, which does not load your theme, so the snippet cannot run there and identify() cannot be called at the moment of purchase. Most Shopify sales are guest checkouts that never log in, so the order webhook is the only point at which identity is observed. Boundaries we hold:
  • Per-site only. Hashes are computed with a key unique to each site, so the same person on two different customers’ sites produces two unrelated hashes. Nothing we store about a visitor can be correlated across sites, and that is enforced by construction rather than by policy: the site identifier is part of the key derivation, so a cross-site hash cannot be produced from what we keep. Two exceptions, neither of which is visitor data: one value used solely to block abuse is deliberately shared across sites for one hour and is never stored, and a verified AI crawler’s IP address is stored raw, so it is the same value on every site that crawler visits. See Lawful basis for abuse prevention and AI crawler IP addresses.
  • Anonymous-to-identified only. One identified person is never linked to another. A shared device does not merge two customers’ histories.
  • Erasure and export include these links. Deleting a visitor by email removes their linked anonymous records too, and an access request covers the whole journey and returns the link records themselves, including when and by what route each link was made. See Data deletion.
A note on shared devices. If two people use the same browser profile and only one of them logs in, the earlier anonymous activity may be attributed to the person who logged in. We accept this narrow inaccuracy because the alternative (no linking at all) would mean AI-referred revenue could never be measured. It affects unidentified activity only.
Hashed identifiers are pseudonymous, not anonymous. Under GDPR they are still personal data, and we treat them accordingly: they are covered by erasure and export from day one.

Lawful basis

Traceten is designed to operate under the legitimate interests basis for analytics (GDPR Article 6(1)(f)) when configured correctly:
  • No advertising, ad targeting, or sale of audiences
  • No automated decision-making about a visitor, and no scoring of individual people. Our classifier labels where TRAFFIC came from, not who a person is
  • No cross-site tracking
  • We do keep a per-visitor history within a single site: the session records described in Data collected are keyed by a pseudonymous visitor identifier, so one visitor’s sessions on one site can be read together. That is what lets us attribute a conversion back to the AI referral that produced it, and it is deleted with the visitor on request
  • Genuine legitimate interest: understanding which channels drive traffic to your own website
However, lawful basis assessment depends on your specific use case and jurisdiction. If you are in doubt, consult a legal advisor. If you require consent as the lawful basis (common in Germany and some other EU markets), use the dynamic snippet loading pattern described in Cookies.

Lawful basis for abuse prevention

To block floods and denial-of-service traffic, we compute a second value from the IP address at the edge: HMAC-SHA-256(key = shield_secret, message = IP + current hour). Unlike the per-site hash above, this value is the same for one IP across every site. That is the point: a flood aimed at many sites at once is invisible to a per-site hash, because each site sees a different value for the same attacker. The lawful basis is legitimate interests (Article 6(1)(f)). Recital 49 names preventing denial-of-service attacks as a legitimate interest in its own right, so this is the most clearly founded basis of any IP-derived processing we do. What bounds it. The value rotates every hour, so it cannot follow anyone across a day. It is never written to an event, a log, or a database, and it is never combined with a site identifier, a visitor ID, or anything else we keep. It exists in memory for the life of the request and in a rate-limit counter that deletes itself once traffic returns to normal. Stated plainly: this value is capable of linking one person’s requests across two of our customers’ sites within the same hour. We do not do that, and nothing we store would let us do it afterwards, because the value is never written down. What prevents cross-site linkage in our stored data is the per-site derivation, which is unchanged. Access and erasure. No record we keep contains this value, so it does not appear in an access request and there is nothing to erase in a deletion request.

Lawful basis for city-level geolocation

Traceten stores the visitor’s country and city, derived from their IP address at the edge. Nothing finer: no region, no postcode, no street address, no coordinates, and we never ask the browser for its location. The lawful basis is legitimate interests (Article 6(1)(f)), the same basis as the rest of the analytics data, and city is not gated behind consent separately from anything else. Why we collect it. Country alone does not answer “where is my AI traffic coming from” for a business deciding where to ship, which timezone to staff, or which market to advertise in. City also feeds detection: a location that does not match the claimed browser environment is one signal that a visit is automated rather than human. What city actually adds, stated plainly. City is derived from the IP address, and a keyed hash of that same IP address is already stored on the same row. The hash already groups every visit from one IP address together. Adding the city does not create that ability. What it adds is legibility: “Ipswich” is a fact a person reading the row can join against outside knowledge, where the hash is an opaque string. That is a real difference and we do not minimise it, but it is a different one from “we can now track you across the web”, which remains false. The combination risk. A single row carries the hashed IP, the user agent, the timestamp, the browser environment, the country, and now the city. Together that is a much stronger disclosure than city on its own, and someone who already knows a specific person lives in a specific small town could, in principle, point at a row. Three things bound it:
  • We do not collect the network operator (ASN). City plus employer or institution network in a small town is the combination that would genuinely narrow things to a handful of people, and it does not exist in our data.
  • Precision stops at the city. There is no postcode or coordinate field to combine with. Maps in the dashboard are drawn by looking each city name up in a public list of city centre coordinates while the page renders, so every visitor in a city lands on the same point and no coordinate is derived from any individual visitor. On the live visitor globe that point is then moved to a public park or square nearby, which our servers ask Mapbox for by sending that city centre coordinate and nothing about any visitor: no visitor identifier, no city name, no counts, and nothing identifying the site. The request does identify us, because it goes out under Traceten’s own Mapbox account and a Traceten user agent, so Mapbox knows Traceten is asking and cannot tell which customer it is asking for. Mapbox’s reply, a public place name and its coordinate, is drawn on the map and travels with it into our response cache, and our servers keep the most recent 5,000 cities’ landmarks in memory while the server runs. No coordinate is written to your stored analytics data; a drawn map is held in our response cache for up to 60 seconds (the live globe and the visitor map) or 5 minutes (the country map) and then discarded. Two endpoints suppress a city name, and naming both is more honest than describing a category. /v1/breakdowns/cities and /v1/geo/points both leave a city out when fewer than five sessions came from it in the window; that threshold counts sessions, not people, so five sessions can be one visitor returning five times, and it is a floor on how few sessions can put a city’s name in a response rather than a guarantee that a named city contains five separate visitors. (/v1/geo/points has no product surface reading it and cannot be called with an API key, so in practice you will meet the other one.) Everywhere else that returns a city returns it with no threshold at all. That includes the live visitor globe (/v1/geo/live), which applies no visitor threshold: every city with at least one visitor active in the window being viewed is named; the session list and an individual session’s detail, in the dashboard and over the API alike; the visitor list and an individual visitor’s detail (/v1/visitors and /v1/visitors/{handle}), and the lists of visitors behind one funnel step or one goal (/v1/funnels/{id}/steps/{position}/visitors and /v1/goals/{name}/visitors), all four of which return the city of a visitor’s first visit, and the first of which is what the dashboard’s Visitors table shows; the city and region breakdowns on the Overview; and the data returned by an access request. The region breakdown lists only the busiest cities, so a very small one may fall outside it; the session list is not limited that way.
  • The data expires. Raw events are deleted after 730 days; session-level records after 730 to 760 days. See Data retention.
Erasure. City lives on the same rows as every other signal, so an erasure request removes it with the row. There is no separate step and no field left behind. This works whether you erase by visitor or by session. Storage. City takes the same path as the country code and is stored in the same place, which today means one region for every site regardless of the region you selected. See Data residency. Opt-out. The _traceten_optout cookie and DNT: 1 do not stop a visitor being geolocated. They stop the persistent visitor cookie, the higher-entropy device signals (WebGL, canvas entropy, heap size, timezone offset, paste detection), the cart token, and all exit, click, and in-app navigation tracking, but the initial pageview is still sent, and we derive country and city from it like any other pageview. If you need collection to stop outright, gate the snippet behind your consent tool: a denied consent state is enforced on our side and no event is stored at all. To remove data already collected for a visitor, use the deletion API. The written assessment behind this is an internal record and is available to customers on request. As with everything on this page, it is our assessment of the typical configuration, not legal advice for yours.

Lawful basis for AI crawler tracking

This basis is stated separately and is not inherited from the analytics path above. The processing, the data and the balancing test are all different, and the optional feature described here runs only if you install it. What is processed. Records of requests made to your site by automated crawler software: the requested URL, the response status, the raw user-agent string, and the address the request came from. The URL is transmitted in full, including any query string; the query string and any fragment are removed on receipt at our edge, before the record is stored or placed on any internal queue. The address is used to verify the crawler’s claimed identity and is retained only where that verification succeeded against evidence the vendor publishes. See AI crawler IP addresses. The basis is legitimate interests (Article 6(1)(f)), and the interest is yours as much as ours: knowing which AI systems read your content, what they use it for, and whether a crawl claiming to be a major vendor really was. Why the balance is different from the visitor path. A crawler’s address identifies a company’s infrastructure, not a person. GPTBot’s egress address identifies OpenAI. The vendors publish those ranges themselves, precisely so that site owners can check them. Where that argument is weaker, stated plainly. It does not hold uniformly, and we do not claim it does:
  • User-triggered fetchers. ChatGPT-User, Claude-User, Perplexity-User and similar crawlers fetch a page because a specific person asked a question moments earlier. The address is still the vendor’s, but the event was caused by an identifiable human action. What we hold cannot identify that person: there is no visitor identifier, no cookie, no session, and nothing that joins a crawl record to anyone’s browsing.
  • The unverifiable share. Roughly half of tracked crawlers publish no way to prove their identity, so a record in that bucket cannot be confirmed to be machine traffic at all. Some fraction of it, by construction, will not be. This is exactly why an unverified address is never retained: the hash-only rule exists for the case where the address might belong to a person.
What bounds it. Raw addresses are retained in only two cases: a match against a range the vendor publishes for that crawler, and a forward-confirmed reverse-DNS hostname. That two-case rule is applied at our edge. Underneath it, a database constraint independently rejects any crawl record that carries an address without network verification, so a bug in the edge code cannot store an unverified address. Everything else is hash-only, with no network operator and no country derived. Individual records expire after 90 days on every plan. The rollups that outlive them hold counts, grouped by crawler, by page path, and by page path and crawler, with no address and no personal identifier, but they are not time-bounded, so the page paths themselves are retained indefinitely after the individual records containing them have expired. The feature is off unless you install it, and you choose which categories of crawler to report at all. Your rights over crawl records. The deletion API cannot reach them, because they carry no visitor ID, session ID or email for it to key on. That is a limit of the API rather than of what is possible, and requests are handled by hand: email privacy@traceten.com with the address the crawl came from, which is what a crawl record can be matched on. See AI crawler records. You are the controller. Traceten processes crawl reports on your behalf, from your own server, under the Data Processing Agreement. Your own privacy notice should reflect that crawler request metadata (URL, user agent, IP address) is shared with Traceten for crawler detection. As with everything on this page, this is our assessment of the typical configuration, not legal advice for yours.

Lawful basis for identity linking

Identity linking is a processing activity you instruct us to perform, not one Traceten undertakes on its own account. You are the controller. Traceten is the processor. The email addresses and account IDs involved are yours: you already hold them as the controller of your own customer relationship. You determine whether linking happens at all: it occurs only if you call identify(), connect a revenue integration (Stripe, Shopify, Lemon Squeezy or Polar, each of which sends us the buyer’s email on an order), or send an email to the Payment API yourself. Paddle sends no email, so a Paddle connection links nothing on its own. Traceten never obtains these identifiers from any other source, never uses them for its own purposes, and cannot combine them across customers. Your basis for instructing it will typically be legitimate interests (Article 6(1)(f)). Measuring which channels drive revenue to your own site is a recognised legitimate interest, the processing is limited to that purpose, and the identifiers are hashed rather than stored in the clear. Two things narrow the impact for the balancing test: the linkage is confined to a single site, and it feeds no advertising audience, no segment sold or shared with anyone, and no automated decision about the person. It does produce a per-visitor history within that one site, because joining sessions to conversions is the purpose. Where your own privacy notice relies on consent for analytics, that consent must cover identity linking too. Gate the identify() call behind it, exactly as you would the snippet. This is our assessment of the typical configuration, not legal advice for yours. Your lawful basis depends on your jurisdiction, your privacy notice, and how you obtained the identifiers. Confirm it with your own advisor.

Data subject rights

The table above covers the visitors you track, where you are the data controller and Traceten is your processor. You also hold those rights against Traceten directly, for the personal data we hold about you as our customer (your name, email, and sign-up provider). To exercise the right to erasure, see Deleting your Traceten account. For any other request about your own data, email privacy@traceten.com. Deleting your account does not erase everything. Tax law requires us to retain issued invoices, and those still show the name and email that were on them at the time. The account deletion page sets out exactly what we keep and for how long.

Data residency

When you create a site in Traceten, you select a region. We record that choice against the site, and you cannot change it after creation. Region selection does not yet control where data is stored. All event data currently lands in one region, whichever region you picked. Our sub-processors page lists where each provider holds data. An earlier version of this page said EU-region data was stored only in Ireland and never transferred to the US. That was wrong, and this is the correction. What this means for you today:
  • If you have GDPR obligations that require EU storage, Traceten does not meet them yet. Talk to us before you rely on it.
  • Transfers to the US are covered by the standard contractual clauses in our DPA, and our sub-processors page lists where each provider holds data.
  • The region you select is stored and will be honoured when routing ships. Setting it now means you will not have to recreate the site later.
We will update this page and notify affected accounts when region routing is live.

CCPA

Under the California Consumer Privacy Act, Traceten collects analytics data that may qualify as “personal information” (a broad definition that includes identifiers like pseudonymous session IDs). Your disclosure obligations depend on how you use Traceten. In most cases, this falls under service provider data use, which is exempt from CCPA’s opt-out requirements. You should still disclose analytics collection in your privacy policy. Traceten does not sell or share data with third parties for advertising or commercial purposes.

Right to deletion

California residents may request deletion of their data. See Data deletion for the API and process.

Data Processing Agreement

If your organization requires a signed DPA before using Traceten (common for EU customers), contact us via the dashboard and we’ll send you the standard agreement. The DPA covers:
  • Description of processing activities, including identity linking. The controller/processor allocation described under Lawful basis for identity linking is reflected in the agreement: you remain the controller of the email addresses and account IDs, Traceten processes them solely on your documented instructions, and linking is scoped to a single site
  • Categories of personal data processed, including pseudonymous identifiers (hashed emails and account IDs, visitor and session IDs)
  • Sub-processors list (Cloudflare, AWS, Neon, ClickHouse Cloud)
  • Standard contractual clauses for data transfers
  • Assistance with data subject requests, covering erasure and access across linked identities
  • Data breach notification procedures (72-hour notification)