Web apps
Data kogut collects
Stored analytics, visitor ids, retention, and outbound connections.
kogut stores web analytics in SQLite on your server. Use this page for your privacy notice; it is not legal advice.
Browser data
The script does not access cookies, localStorage, sessionStorage, IndexedDB, or Cache
Storage. It does not inspect canvas, fonts, plugins, or hardware for fingerprinting.
| Event | Sent when | Fields |
|---|---|---|
| Page view | Page load, path change, or back/forward cache restore | Page URL, referrer on initial load, window width, and automation flag |
| Web Vitals | Page hide, exit, or route change | Available LCP, INP, CLS, FCP, and TTFB values |
| Error | Uncaught exception or unhandled rejection | Redacted message, source, line, column, stack, and fingerprint |
| Custom event | kogut.track() call or tagged click | Name and properties |
| Outbound link | Click to another host | outbound event with the destination URL |
Events include the page URL, the site domain, and the app version when the tag sets
data-version; the version describes the build of
your app, not the visitor. Snippets with data-website-id omit the domain, and the
server finds the site from the page’s host. Prerendered pages send nothing until
activation.
Page URLs lose credentials, fragments, and query parameters except utm_source,
utm_medium, utm_campaign, utm_term, and utm_content. Referrers and outbound links
lose queries and fragments. Requests use fetch with keepalive, without cookies or a
Referer header. Browsers also send request headers such as the user agent and language.
The visitor id
The server computes a separate visitor id for each site: the first 16 bytes of the SHA-256 hash of the salt, the site id, the length of the IP address, the IP address, and the user agent, in that order.
The salt has 32 random bytes and changes daily at 04:00 in the server’s time zone; the previous salt is deleted. The current salt is stored in SQLite so ids survive restarts. Backups exclude it.
The same visitor gets unrelated ids on different sites and days. Visitor totals over several days add the daily counts. A visit ends after 30 idle minutes or at the salt change.
Raw IP addresses and user agents are not stored. The server uses the IP address for rate limits and visitor ids, and the user agent for ids, bot filtering, browser, operating system, and device class.
Stored data
| Table | Fields |
|---|---|
hit | Site, time, path, referrer host, channel, source, medium, campaign, country, device, browser, operating system, language, app version, visitor id, visit id, and duration |
visit | Id, site, start, last seen, and page view count |
vital | Site, time, path, device, app version, and available metric values, without a visitor id |
custom_event | Site, time, name, properties, and visitor id |
error_group | Id, site, fingerprint, message, source, first seen, last seen, count, and state |
error_event | Group, time, path, browser, app version, and stack |
hit_bucket | Daily totals and counts by dimension, without individual visitor ids |
vital_bucket | Hourly histograms by site, path, and metric |
salt | Current salt day and salt |
Daily rollups cover 04:00 to 04:00 in the server’s time zone. Dimensions include paths, referrers, channels, countries, devices, browsers, operating systems, languages, sources, mediums, campaigns, and app versions. Each keeps up to 1,000 values per day, so rare values can disappear from older breakdowns.
The country comes from Cloudflare’s CF-IPCountry header; without Cloudflare in front of
kogut, no country is recorded. kogut makes no GeoIP lookups and stores no region or city.
Detected bots and automated browsers are dropped before storage.
Errors are redacted in the browser and on the server. Custom event values are redacted on the server, which does not remove all personal data. Event names and property keys are not redacted.
Kept only in memory
These records disappear on restart:
- Up to 50,000 open visits, with visitor id, visit id, and last event time.
- Rate counters for up to 10,000 clients, keyed by a hash of the IP and a startup secret.
- The last 200 page views’ hashed client addresses and visitor ids, for proxy warnings.
- Up to 20 app versions per site, with the time each was last seen.
Retention
Raw analytics, errors, daily rollups, and hourly histograms have separate settings in
[retention]. Error groups remain after their
events expire. The salt lasts until the next salt day.
Outbound connections
Browsers load the script from and post events to your kogut only. The server connects to check targets, DNS resolvers, domain registries and IANA’s RDAP list, notification services, configured OIDC providers, kogut edge, and a configured heartbeat URL. With nothing configured, it opens no outbound connection, not even a DNS lookup.
While a check of a public address exists, the server also
probes connectivity
to the hosts in connectivity_hosts. Agents
connect to your server and their assigned check targets.
kogut sends no telemetry and makes no update checks.
MCP and Copy for AI
MCP requires an mcp token. Its tools return totals, breakdowns,
Web Vitals, and error groups, not visitor ids, individual page views, or custom event
properties.
Copy for AI copies the incident timeline, likely causes, alerts, and log excerpts. Likely causes can include JavaScript error counts.
Consent
Whether you need consent depends on your site and visitors; using no browser storage does not decide it. You can load the script after consent.
Do not send personal data in custom events.