How Shipabase counts visitors without cookies or stored IPs
What the SDK sends, how visitors are counted, and what you should never send.
What is stored in the browser#
Nothing. No cookies, localStorage, sessionStorage or IndexedDB. The session ID lives in memory only.
What the SDK sends#
The event name, your props, and coarse system info: locale, time zone, OS name and version, browser engine and major version, app version, SDK version, a debug flag, the page path (never the query string; IDs become :id on the server), and the traffic source of the page load (the utm_source parameter, or the referring site’s host, never a full URL). Visits from AI assistants such as ChatGPT, Perplexity or Claude are recognized automatically.
How visitors are counted#
IP addresses and User-Agents are never stored or logged. For each request, the server uses them for a moment to derive a country and an anonymous visitor ID, then discards them. The visitor ID is computed exactly like this:
visitor_id = sha256(salt + app_id + ip + user_agent).hexdigest()[:16]saltis 32 random bytes (64 hex characters) generated on the server, one per calendar day, the same for every app. It is never sent to the browser and never stored with events.- The day is the visitor’s local day, taken from the time zone the SDK sends (UTC if there is none). The same visitor keeps the same ID from their midnight to the next, then gets a new one, so visitors can’t be followed from one day to the next.
- Each salt expires at 00:00 UTC two days after its day starts, once that day has ended in every time zone, and is then deleted. Without the salt, nobody can recompute a hash or link it back to an IP.
app_idis your app’s internal ID: the same person gets unrelated IDs in two different apps.- Only the first 16 hex characters (64 bits) of the SHA-256 digest are kept.
- Over 7, 30 or 90 days, a visitor who comes back on another day counts again.
Stored, not stored, derived then discarded#
| Data | Status | Details |
|---|---|---|
| IP address | Derived then discarded | Used for the visitor ID, the country and an in-memory rate limit (keyed by a non-reversible hash), then dropped. Never written to the database or logs. |
| User-Agent | Derived then discarded | Used for the visitor ID, to filter bots, and for OS and browser engine when the SDK didn’t send them. Never stored. |
| Time zone | Derived then discarded | Only picks the visitor’s local day, and so the salt. Never stored. |
| Daily salt | Not stored with events | Kept server-side, apart from events, and deleted about two days later. |
| Visitor ID | Stored | 16 hex characters, valid for one local day in one app. |
| Country | Stored | Two-letter code, looked up from the IP in a local GeoIP database (no third-party call). |
| Session ID | Stored | Generated in memory by the SDK (start time plus a random suffix). Never written to the device. |
| Event | Stored | Event name, your props, page path, traffic source, locale, OS, browser engine, app and SDK version, debug flag. |
| Cookies, localStorage, device IDs | Not stored | Nothing is written to the visitor’s device. |
| Query string, hash, full referrer URL | Not stored | Only the path and the referring host (or utm_source) are sent. |
For the product-level overview, see the privacy page.
Cookie banner#
Nothing is stored on the visitor’s device, so this setup typically needs no cookie banner under the GDPR and ePrivacy rules. You stay responsible for what you send: keep props anonymous and Shipabase stays anonymous too. See Props & privacy.