How it's private

Most analytics tools need a consent banner because they set a cookie or store a persistent identifier on the visitor's device. Satsu does neither. This page explains the mechanism behind "no cookie banner", including where it has edges.

No cookies, no stored IDs

Satsu never writes a cookie, never uses localStorage for identity, and never assigns a persistent visitor ID. Satsu sets nothing on the device and stores no identifier there; the only read is the optional satsu_ignore opt-out flag. The session ID stored with each event is a one-way hash that changes every UTC day.

Sessions are derived from a daily fingerprint

To group a visit's pageviews together — to know that three pageviews came from the same session — Satsu derives a short-lived fingerprint on the server:

session = sha256(site · ip · user-agent · day · salt)

The components are hashed together (NUL-separated) into a single opaque value:

sha256("site_id" | "203.0.113.7" | "Mozilla/5.0 …" | "2026-07-14" | secret_salt)
→ 9f2c... (a one-way hash)

A few things make this safe:

  • It's one-way. SHA-256 can't be reversed. The stored value can't be turned back into an IP or user-agent.
  • The raw IP and user-agent are never written to the analytics database. They pass through our message queue only until they are processed, at most 24 hours.
  • It includes the day. Because day (YYYY-MM-DD, UTC) is part of the input, the fingerprint changes at 00:00 UTC. Tomorrow the same visitor produces a completely different hash — there's no way to connect the two.
  • The secret rotates daily, too. The salt is 32 random bytes created fresh for every UTC day. It is kept in a short-lived cache only — never in the analytics database or in logs — and is deleted after about 48 hours. From then on nobody, including us, can recompute that day's fingerprints, even with a known IP address and user-agent.

Why the daily rotation matters

The daily rotation is the core design decision. It means Satsu cannot build a profile that follows someone across days or sites. No retention cohorts, no cross-day journeys, no "returning visitor" tracking spanning weeks. That's a deliberate limit, and it's why, in our assessment, Satsu works without a consent banner: there's no durable identifier to consent to.

Heartbeats are presence-only

The live visitor count comes from presence entries: a session hash and the current path, kept in a short-lived cache. A visitor counts as live for 60 seconds after their last pageview, event or heartbeat, and the entries expire within ten minutes. Heartbeats are never written to the analytics store and never counted against your plan; they exist only to power the real-time "who's here now" number.

What this means for compliance

Built for GDPR. No cookies and no persistent identifiers, so in our assessment no consent banner is needed; check with your own counsel for your site.

  • Analytics database — no IP addresses, no user-agents, no identifiers that survive the day. The IP address is processed briefly on our servers to derive the daily fingerprint and the country.
  • Visitor's device — Satsu sets nothing on the device and stores no identifier there; the only read is the optional satsu_ignore opt-out flag.

We're happy to provide a Data Processing Agreement (DPA) for business customers — email hello@satsu.pro.

The site check

We don't store or log the address you check — only how many checks ran.

While you try the check, the domain you entered stays in your own browser tab (sessionStorage) only until the site is created after signup. It is never sent to us for storage, and "no localStorage IDs" still holds.

Two more per-tab sessionStorage entries sit next to satsu.check.domain: satsu.check.via (which page linked you to the check) and satsu.check.ran (a check finished in this tab). Neither holds an identifier, and the only values ever sent are from a closed list of page names, never an address. When you register, satsu.check.ran is read once to send signup_completed with a yes/no after_check flag, and nothing else.

The honest caveats

We'd rather tell you the edges than oversell:

  • The daily secret exists for about 48 hours, not 24: events that arrive shortly after midnight still need the secret of the day they belong to. Until it is deleted, someone holding both the secret and a visitor's exact IP address and user-agent could recompute that day's fingerprint. The IP and user-agent are never written to the analytics database; they pass through our message queue only until they are processed, at most 24 hours.
  • Country is derived from the IP at the country level only. The derivation reads the IP from the queued event; the analytics database stores the country, never the IP.

None of this changes the core design: no cookies, no persistent IDs, no identifier that survives the day.

See also: What we track for the full field-by-field list.