Privacy Architecture
Moneat Analytics is designed to be privacy-compliant by default. No cookies, no personal data storage, no cross-site tracking. This page explains exactly how it works at a technical level.
No cookies
Moneat Analytics sets zero cookies. Sessions are identified entirely server-side using a hash-based approach that makes it impossible to track users across days or across sites.
Session identification
Instead of cookies, sessions are derived from a one-way hash computed on the server:
session_id = SHA-256(daily_salt | domain | IP | User-Agent)
| Component | Purpose |
|---|---|
daily_salt | Random value rotated every 24 hours. Ensures the same visitor gets a different session ID each day. |
domain | The website's domain (data-domain attribute). Prevents cross-site tracking. |
IP | Client IP address (from request headers). Used only in the hash, never stored. |
User-Agent | Browser User-Agent string. Used only in the hash, never stored. |
Why this works
- Same visitor, same day, same site → Same session ID (accurate daily analytics)
- Same visitor, next day → Different session ID (no multi-day tracking)
- Same visitor, different site → Different session ID (no cross-site tracking)
- Session ID is irreversible → Cannot be decoded back to IP or User-Agent
Daily salt rotation
The salt is a cryptographically random value stored in Redis with a 48-hour TTL:
- A new salt is generated at midnight UTC each day
- The previous day's salt is kept for an additional 24 hours to handle timezone edge cases
- After expiry, the salt is permanently deleted - old session IDs can never be regenerated
Day 1: salt_abc123 → session_id_X for visitor A
Day 2: salt_def456 → session_id_Y for visitor A (different!)
Day 3: salt_ghi789 → session_id_Z for visitor A (different!)
Data flow
1. Browser sends pageview event
→ Includes: pathname, referrer, UTM params, screen width
→ Does NOT include: cookies, localStorage, fingerprint data
2. Server receives event
→ Extracts client IP from X-Forwarded-For / X-Real-IP / socket
→ Reads User-Agent header
3. Server enriches event
→ GeoIP lookup: IP → country, region, city
→ UA parsing: User-Agent → browser name, OS, device type
→ Session hash: SHA-256(salt | domain | IP | UA)
4. Server DISCARDS personal data
→ IP address: deleted
→ Raw User-Agent string: deleted
5. Server stores enriched event in ClickHouse
→ session_id (hash, not reversible)
→ country_code, subdivision, city (derived from IP, but IP not stored)
→ browser, os, device_type (derived from UA, but UA not stored)
→ pathname, referrer, utm_*, hostname
→ event_name, custom properties
After step 4, there is no way to identify the original visitor from the stored data.
What is stored
| Field | Stored | Example |
|---|---|---|
| Session ID (hash) | Yes | a1b2c3d4e5f6... |
| Page path | Yes | /pricing |
| Referrer source | Yes | Google |
| UTM parameters | Yes | utm_source=newsletter |
| Country code | Yes | US |
| Region | Yes | California |
| City | Yes | San Francisco |
| Browser name | Yes | Chrome |
| Browser version | Yes | 120 |
| OS name | Yes | macOS |
| Device type | Yes | Desktop |
| Screen width | Yes | 1920 |
| Custom event name | Yes | Signup |
| Custom properties | Yes | { "plan": "pro" } |
What is never stored
| Field | Stored | Notes |
|---|---|---|
| IP address | No | Used transiently for GeoIP + session hash, then discarded |
| User-Agent string | No | Used transiently for UA parsing + session hash, then discarded |
| Cookies | No | None set, none read |
| User IDs | No | Not collected |
| Email addresses | No | Not collected |
| Device fingerprints | No | Not collected |
| localStorage/sessionStorage | No | Not accessed |
Do not track
Moneat Analytics respects the browser's Do Not Track (DNT) setting. When navigator.doNotTrack is "1", the tracking script does not send any events.
This behavior cannot be overridden by configuration.
Real-time counting
Real-time visitor counts use Redis HyperLogLog, a probabilistic data structure that:
- Counts approximate unique visitors without storing individual identifiers
- Uses ~12 KB of memory regardless of visitor count
- Provides counts with less than 1% standard error
- Automatically expires after 5 minutes
No visitor-identifying data is ever stored in Redis for real-time counting.
Data retention
Analytics events are stored in ClickHouse and retained according to the analytics retention period configured for your plan. See Billing & Plans for current retention and pageview limits.
GDPR & CCPA compliance
Because Moneat Analytics:
- Does not use cookies → No cookie consent banner required
- Does not store personal data → No personal data processing to disclose
- Does not track across sites → No cross-site tracking to report
- Does not create user profiles → No profiling to opt out of
- Processes data on your infrastructure → No third-party data transfers
Moneat Analytics is compliant by design with GDPR, CCPA, PECR, and similar privacy regulations. No consent dialogs, cookie banners, or opt-out mechanisms are needed.
While Moneat Analytics is designed to be privacy-compliant, consult your legal team for advice specific to your jurisdiction and use case.