Anonymous usage statistics
TravStats can send a small, anonymous usage report to a public adoption-metrics service so the community can see how many installations exist and how they’re used. This is what actually gets sent, reproduced verbatim so you can diff it against your own instance’s traffic.
What this is
Section titled “What this is”- Opt-in. No ping is ever sent unless an admin explicitly agrees.
- Off by default. A fresh install’s consent state is
unset, which behaves identically todenied— nothing is sent. - Instance-wide, admin-controlled. The payload describes the installation as a whole (aggregated across every user), not an individual account, so the decision is made once, by an admin, for the whole instance — not per user.
- You’re asked twice: once during first-run setup, and once via a one-time consent card in the “What’s new” dialog for existing installs. Either surface links back to this page.
The payload, verbatim
Section titled “The payload, verbatim”This is the complete JSON body of every ping. Nothing is added,
nothing is removed — if you capture your instance’s outbound request
to stats.travstats.de/v1/ping, this is what you’ll see, field for
field:
{ "install_id": "<random uuid4 hex>", "version": "2.4.0", "arch": "amd64 | arm64", "enabled_domains": ["flight", "cruise"], "users_bucket": "1 | 2-5 | 6-20 | 20+", "flights_bucket": "<50 | 50-250 | 250-1k | 1k+", "cruises_bucket": "0 | 1-5 | 6-20 | 20+", "distance_km": { "flight": 128400, "cruise": 9200 }, "achievements": { "unlocked_total": 87, "keys": ["globetrotter", "night_owl"] }, "features": { "llm_parser": true, "backups": true, "webdav_sync": false, "historical_enrichment": false, "live_tracking": true }, "flight_api_providers": ["airlabs", "opensky"], "locale": "de | en", "reported_at": "<ISO 8601 UTC>"}Where every field comes from
Section titled “Where every field comes from”| Field | Source |
|---|---|
version | The running app version (any pre-release suffix like -rc.1 is stripped) |
arch | The server’s CPU architecture — x64 → amd64, arm64 → arm64 |
enabled_domains | The union of enabled domains (flight, cruise, …) across every user account on the instance |
users_bucket | A bucketed count of user accounts |
flights_bucket | A bucketed count of logged flights |
cruises_bucket | A bucketed count of logged cruises — "0" is its own bucket, so “cruise domain enabled but never used” doesn’t disappear inside a <50-shaped range |
distance_km.flight | Sum of flight route distances, rounded to the nearest 100 km. Flights without a resolved route contribute nothing, so this is a lower bound |
distance_km.cruise | Sum of cruise leg distances, rounded to the nearest 100 km |
achievements.unlocked_total | Total achievements unlocked across every user |
achievements.keys | Which achievement types have been unlocked at least once, deduplicated — never a per-key count, and never tied to who unlocked it |
features.llm_parser | Whether any LLM parsing backend (Ollama URL, or a global OpenAI/Claude key) is configured |
features.backups | Whether the scheduled backup job is enabled |
features.webdav_sync | Whether off-host WebDAV backup sync is enabled |
features.historical_enrichment | Whether any user has historical flight-data enrichment turned on |
features.live_tracking | Whether any flight on the instance has live tracking data — there is no single instance-wide toggle for this |
flight_api_providers | Which flight-data providers have a key configured (by name only — never the key itself) |
locale | The most common UI language across users; ties resolve to English |
reported_at | Timestamp of the ping, UTC |
What is never sent
Section titled “What is never sent”Regardless of the above, TravStats never includes:
- Your IP address or hostname
- Filesystem paths
- Airport, port, ship, or airline names
- Travel dates
- Usernames or e-mail addresses
- API keys (only which providers are configured, never the values)
- Exact counts — everything is bucketed or rounded, except the two distance sums and the achievement total, which are the only numbers sent as-is (and the distances are themselves rounded to the nearest 100 km)
install_id
Section titled “install_id”A purely random uuid4, generated the first time an admin grants
consent. It is never derived from an IP address, hostname, MAC
address, database id, or any filesystem path — it exists only so a
second ping from the same installation updates the same row instead
of creating a duplicate. It is a dedup key, not a fingerprint.
You can find your instance’s install_id at Admin → Instance →
Anonymous usage statistics. Quote it if you ever need to make an
access or erasure request about your installation’s data.
How to turn it off
Section titled “How to turn it off”Flip the toggle at Admin → Instance → Anonymous usage statistics back to off. This does two things:
- Stops all future pings immediately.
- Fires a request asking the server to delete this installation’s stored row — no e-mail required. If the server can’t be reached at that moment, the request is not retried; the row is then removed automatically once it falls outside the 180-day retention window (see below).
The kill-switch
Section titled “The kill-switch”Self-hosters who want this guarantee enforced in their own configuration, independent of the admin UI, can set:
TRAVSTATS_STATS_ENDPOINT=""An empty value disables all sending, unconditionally — regardless of what the consent toggle says.
Retention
Section titled “Retention”- An installation’s stored row is hard-deleted if it hasn’t been seen for 180 days, by a daily cleanup job on the server.
- The daily active-install count used to draw the public growth
chart is retained indefinitely, but it holds only a date and a
count — no
install_id, no link back to any individual installation.
Rate limiting and IP addresses
Section titled “Rate limiting and IP addresses”The service rate-limits both the ping and erasure endpoints per client address to prevent abuse. The address is hashed in memory the moment a request arrives and the hash is discarded once its short window expires — the raw address is never written to disk, logged, or stored anywhere. The reverse-proxy configuration shipped for this service uses an access-log format that omits the client address entirely for this endpoint.
Cloudflare
Section titled “Cloudflare”The stats endpoint is served through a Cloudflare Tunnel. Cloudflare terminates that tunnel and therefore sees every client’s IP address and full request content before it reaches the service — this is inherent to how a tunnel works and isn’t something TravStats’ code can avoid. Cloudflare, Inc. is a US company, so this is a transfer of personal data (the client IP) to a third country.