-
Notifications
You must be signed in to change notification settings - Fork 0
Telemetry
- Accshift counts a few anonymous things. It is a handful of counters, not a profile.
- Settings > Privacy, two switches, both off means nothing is ever sent again. Nothing is gated on it and the app is identical either way.
- Nothing at all is sent before you finish the first-launch screen. After it, the anonymous counters are on. That screen asks about the enhanced tier, not about the counters, so turning those off is a separate deliberate action. Said plainly: the anonymous tier is opt-out, the enhanced tier is opt-in.
- Data goes to a Cloudflare Worker that stores nothing, which forwards to PostHog in the EU. Resend is used only for operational alert emails.
The canonical version of this page lives in the repository, at
docs/analytics.md,
so that git log shows every change ever made to what is collected. Where this
page and the repository disagree, the repository is right.
Accshift manages game accounts, so this list matters more than the one after it. None of the following ever leaves your machine, in any mode:
- Account names, usernames, display names, nicknames
- Platform account identifiers of any kind (SteamID, Riot PUUID, Epic account id)
- Passwords, tokens, cookies, session files, or anything derived from them
- Persona names, folder names, custom labels, avatars
- File paths, directory names, screenshots, window contents
- Your IP address, which is never stored anywhere
- Log files. Logs stay on your machine and are only ever shared by hand, when you choose to attach one to a bug report
An event can say "an account was added on Steam". It cannot say which account, because the app never puts that in the payload.
Events are sent, and they are deliberately made hard to link together.
A random UUID is generated on your machine. The server never stores it: it stores a keyed hash of it, used only to avoid counting the same installation twice in the daily active count. Every other event is attributed to a different hash that changes every night, derived from your IP address and User-Agent, so two switches you make on Monday and Tuesday cannot be tied to the same installation.
No user profile is created on the analytics side. This mode exists so the project can answer "how many people use this, on what OS, in what country" and nothing more.
A second random UUID, the install id, is generated and attached to every event. It stays the same over time, which is exactly the point: it makes it possible to see whether people come back after a week, which features get used together, and how many accounts a real library holds.
This is the mode where a profile does exist on the analytics side. It is a separate opt-in for that reason, and it is the only mode where export and deletion are possible, because they need an identifier to act on.
When both switches are on, events are sent once, under the enhanced identifier. They are not duplicated. Turning the enhanced switch off falls back to the anonymous identifiers.
Every event carries the app version, the OS version and your locale. The server adds the country code, derived from your IP address without storing the address. Nine events, and that is the complete list:
| Event | Extra fields | Notes |
|---|---|---|
ping |
none | daily active-install counter |
app_launched |
launch duration | |
platform_switch |
platform id, duration, success | never the account |
persona_switch |
platform count, success count | never the persona name |
account_added |
platform id | never the account |
streamer_mode_activated |
none | streaming software was detected |
deep_link_used |
none | never the link itself, it contains account ids |
session_ended |
session duration | |
accounts_snapshot |
platform id, account count | enhanced mode only |
platform is always a fixed identifier like steam or riot, never anything
you typed. accounts_snapshot is the only event that counts anything about
your library, and only how many accounts exist per platform; the app drops it
before upload in anonymous mode.
This table is checked against the code on every release.
Batches are sent at most once every five minutes and are held in memory only. Analytics is never written to your disk, so an app that never reaches the network simply forgets its events.
- Your machine sends the batch to a Cloudflare Worker, open source and readable
in
server/. - The Worker derives the country code from your IP address, computes the anonymous-mode hashes, and discards the address. It stores nothing itself: it has no database of any kind.
- It forwards the events to PostHog, in their EU region, hosted in Germany. Every forwarded event explicitly overrides the IP field and disables location lookup, so PostHog stores no address and infers no location beyond the country code computed in step 2.
Rate-limit alert emails contain a masked /24 IPv4 or /48 IPv6 prefix and
never an event payload.
On first launch the GUI shows a one-time screen. It asks whether you want the enhanced tier; declining leaves the anonymous counters on, and the note under the buttons says so and points at Settings > Privacy for the full opt-out.
The choice increments one aggregate counter carrying no installation identifier, so the project can tell whether the screen is understood. Even a refusal is recorded against a single shared id, never one tied to your machine.
Enhanced mode only. Settings > Privacy, Export my data copies everything held against your install id to the clipboard as JSON: the person properties and up to 10000 events.
Anonymous-mode events cannot be exported. They carry no install id and their identifier rotates nightly, which is the entire point of that mode.
Enhanced mode only, same reason.
Turning the enhanced switch off asks the server to delete everything tied to your install id. Before making that request the app moves the old id into a machine-local deletion queue, so a failed request stays pending across restarts, with Retry deletion and Export my data still available in Settings. The id leaves the queue only once the server confirms.
Your profile and its properties are removed immediately. The events themselves are queued for a batch job that the analytics provider runs during off-peak hours, weekly on their cloud. "Deleted" therefore means "irreversibly scheduled", not "already gone", so allow up to a week for that part. The job only sweeps events captured before the request; the app closes its queue before calling, so the residual window is a batch already on the wire, and a second deletion request clears any residue.
Re-enabling enhanced mode creates a new id and does not cancel older pending requests.
The enhanced tier runs on your explicit consent, GDPR Article 6(1)(a), and withdrawing it is one click that never degrades the app.
The anonymous tier is on after onboarding rather than opt-in, so the project relies on its legitimate interests in knowing whether the software is used and what to fix first, GDPR Article 6(1)(f). Your right to object is the switch in Settings > Privacy, which takes effect immediately and permanently. The same basis covers the identifier-free onboarding counter and the abuse-prevention controls on the endpoint.
Depending on your jurisdiction you may also have rights of information, access, rectification, erasure, restriction, portability and complaint to a data-protection authority. Export and deletion are in Settings > Privacy for the enhanced tier. Use GitHub Issues, without personal data, for anything the app cannot handle.
Events older than 12 months are deleted.
Aggregated monthly counts, which contain no identifier of any kind, are kept beyond that so the project can see a multi-year trend.
Nothing here has to be taken on trust. The code that decides what is sent is small and self-contained, and it is all linked from docs/analytics.md in the repository.
Settings > Privacy:
- Toggle the enhanced switch off. This triggers the deletion request above; if Settings reports it pending, use Retry deletion when the service is reachable.
- Toggle the anonymous switch off.
No further event is sent after both are off. The one aggregate onboarding counter was recorded when the original choice was made and cannot be tied back to an installation.