Add anonymous telemetry#626
Conversation
Opt-out (with first-foreground prompt) weekly check-in to https://lf.bjorkert.se/api/telemetry/checkin. Trigger fires from both AppDelegate.didFinishLaunchingWithOptions (covers background launches) and SceneDelegate.sceneDidBecomeActive (covers foregrounds), keeping cadence honest for follower-style usage where the app is rarely opened. Payload covers app/iOS/device version, build origin (TestFlight or not), time zone, and a few selected settings (units, remoteType, appearanceMode, contactEnabled, calendarEnabled, backgroundRefreshMethod). Salted-and-truncated SHA-256 hashes of Dexcom username and Nightscout host are sent only when those backends are configured. A sliding 7-day cold-launch counter rides along as a stability signal. No glucose, insulin, carbs, Nightscout URL/token, Dexcom credentials, or logs leave the device. Settings -> Diagnostics has the toggle, a privacy summary, and a "What's sent" inspector that renders the exact JSON about to be posted.
|
I tested this - so you should be getting data from my mope site. |
- Drop hashed Nightscout host and hashed Dexcom username; replace with usesNightscout / usesDexcom booleans. The salt is committed in source, so a hashed NS URL is reverse-lookupable from a forum post, and the hashed host is effectively a patient identifier the patient never consented to. - Drop timeZone from the payload. - Send IDFV raw rather than hashed — it's already an opaque per-vendor UUID, hashing it with a public salt is purely cosmetic. - Add followingApp (Loop / Trio / ...), omitted when device isn't yet known. - Switch cadence from "weekly + every cold launch + on build change" to once per 24h via TaskScheduler. Startup fires one immediate ping when the build SHA changed since the last successful send. The settings toggle re-arms the scheduler when flipped from off to on.
IDFV (sent raw) plus the existing instance field already gives a stable per-install identifier, so the separate generated UUID is redundant. One fewer stable identifier in the wire.
AppDelegate handles the launch-time SHA-change shortcut and TaskScheduler handles the 24h cadence; the foreground hook also calling maybeSend produced two pings per cold launch (and two first-seen Telegram alerts). The hook keeps its other job — presenting the consent sheet on first foreground when the user hasn't decided yet.
TestTest again with some privacy issues updated. I saved the json of what was sent in prior instance and then saved again the one now that some security issues were updated. This is what is sent after the update: These items are no longer included: |
Browser-build vs TestFlight is already covered by isTestFlight; the hashed team ID added a stable per-builder fingerprint without enough analytic value to justify the privacy cost.
|
Approving based on code review after continued discussions in private chat . |
Test✅ Acceptable list of items to share. Test yet again with one final privacy issues addresses (discussed via PM). This is what is sent after the update with commit 3c82b3d: |
marionbarker
left a comment
There was a problem hiding this comment.
approve by test and review of what is included.
Summary
AppDelegate.application(_:didFinishLaunchingWithOptions:): cold-launch is recorded for the rolling 7-day count, an immediate send fires only when the build SHA has changed since the last successful send, andTaskSchedulercarries the steady-state 24h cadence from there.https://lf.bjorkert.se/api/telemetry/checkinwith a Bearer token committed in source. The token is intentionally not a secret — the backend's TLS, NGINX rate limit, schema validation, MongoDB dedup index, and an insert+find-only role are what bound abuse.User-facing documentation
loopandlearn/loopfollowdocs#30 — adds a new Privacy → Anonymous Telemetry page covering what is and isn't sent, opt-out, frequency, and where reports go.
Payload
{ "appVersion": "6.0.7", "buildDate": "2026-04-15", "isTestFlight": true, "instance": "LoopFollow", "idfv": "<UIDevice.identifierForVendor UUID>", "device": "iPhone15,2", "platform": "iOS", "osVersion": "17.5", "usesDexcom": false, "usesNightscout": true, "followingApp": "Trio", "backgroundRefreshMethod": "Silent Tune", "units": "mg/dL", "remoteType": "none", "appearanceMode": "dark", "contactEnabled": false, "calendarEnabled": false, "coldLaunches7d": 12 }followingAppis omitted until the followed app has been detected. The server addsreceivedAtanddayBucketbefore storing.What is NOT sent
No glucose, insulin, carbs, treatments, or any other health data. No Nightscout URL or API token. No Dexcom credentials. No remote-command secrets or APNS keys. No time zone. No location data. No logs — logs are only ever shared if the user explicitly exports them via the existing flow.
User-facing surfaces
Cadence and resilience
telemetryLastSentAt, so the next launch / next tick retries naturally.Files
LoopFollow/Helpers/Telemetry.swiftTelemetryClientplus three SwiftUI views (consent, preview, privacy).LoopFollow/Storage/Storage.swiftLoopFollow/Helpers/BuildDetails.swiftcommitShaaccessor mirroring the existingbranchaccessor.LoopFollow/Application/AppDelegate.swiftLoopFollow/Application/SceneDelegate.swiftLoopFollow/Settings/GeneralSettingsView.swiftLoopFollow/Log/LogManager.swift.telemetrylog category.LoopFollow/Task/TaskScheduler.swift.telemetrytask ID.LoopFollow.xcodeproj/project.pbxprojTelemetry.swift.