First-party visitor tracking — how Turtini replaced Google Analytics

Turtini doesn't use Google Analytics. We run our own first-party visitor analytics so users aren't tracked into Google's advertising graph just by visiting a Turtini page.

What gets recorded on every page view:

• A visitor id (generated client-side, persisted in localStorage)
• A session id (regenerated every ~30 minutes of inactivity)
• The page path you're on (truncated at 512 chars)
• The HTTP Referer (so we know which page led here)
• A coarse device category (mobile / tablet / desktop) parsed from the User-Agent
• A two-letter country code resolved from your IP
• When identifiable, the *company* associated with the visit. For signed-in users we use the email domain (free-mail domains like gmail.com are excluded). For anonymous visitors we use a reverse-IP company lookup performed by our provider IPinfo. This identifies organizations only, never individuals, and resolves only a portion of traffic — residential IPs, mobile carriers, and consumer ISPs are filtered out and stored as a "miss."

What we explicitly do NOT record:

• Your raw IP address. We resolve it to a country code at the edge (cf-ipcountry / x-vercel-ip-country / x-appengine-country headers) or via a cached IP→country lookup, and pass it transiently to IPinfo for the company lookup described above. The raw IP is never written to any event document.
• The individual behind a visit. Reverse-IP gives a company, not a person — we don't attempt to identify "who at Carahsoft" looked at a page.
• Your user-agent string in full. We extract device category only.
• Cross-site identifiers. The visitor id is per-Turtini-origin and isn't shared with any other property.
• Your name or email on page views. Signed-in views carry your uid (so we can count signed-in vs anonymous active users) but no PII.

Where the data goes:

• `pageEvents/{auto}` — one document per page view (carries company fields when resolved)
• `visitors/{visitorId}` — first-seen / last-seen / country / linked uid / last-known company
• `ipCountryCache/{hashedIp}` — the IP→country cache (30-day TTL); admin-readable only
• `ipCompanyCache/{hashedIp}` — the IP→company cache (30-day TTL, including negative caching for ISP / hosting / residential ranges); admin-readable only

Who can see analytics:

• Platform admins via the Admin → Analytics tab (see: Platform Analytics)
• Org admins for their OWN site's visitors (a slimmer view filtered to their org's pages)
• No one else. Cross-org page-view data is opaque to org admins.

Opting out: there is no consent banner because we don't load third-party trackers. If you ever want to suppress your own visits during testing, set `localStorage.turtini_track = 'off'` in your browser — the tracker no-ops on every subsequent page load.

GDPR / CCPA posture: country-level location data is "non-precise location" under both regimes and doesn't require consent in most jurisdictions. We keep the raw IP only in transit (resolving to a country at the edge) and never persist it to event documents — so there's no PII stored even for users in regulated jurisdictions.

If a country code can't be resolved (local dev, anonymous proxy, very rare misses) it's stored as `ZZ` — flagged in the dashboard so we know the gap exists.