This describes what stopdash keeps, what leaves the device, and — in detail — what its
on-device diagnostic log carries. It is the disclosure AGENTS.md requires to exist
before any on-device logging ships. The full store-facing Play Data Safety statement is
finalized at release (see TODO.md Phase 5); this document is the engineering-level
truth those answers are built from.
StopDash is a client-only app. By default it makes network calls to just two places, plus a
third only if you add a National Rail key: Transport for London’s Unified API, the calls that
are the product; — on a release build only — Google Play, to ask whether an app update is
available (detailed below; it carries nothing about you); and, with a National Rail key, National
Rail’s live departure boards (the Rail Data Marketplace, detailed below). Firebase is added
only if you turn on Help make StopDash better (off by default; see Crash reports and usage stats
below). Your location, the stops and lines you look up, and your API keys go only to TfL, or
with a National Rail key also to National Rail (if you opt in, Firebase sees only the rough region
Google infers from your IP address), and only ever what a request needs to answer your question
about departures: the details of what you’re looking up (your location for “near me now” and for
a trip you plan from it —
precise if you grant precise and a precise fix is available, otherwise approximate (if you grant
only approximate, or if no precise fix can be obtained) — or the stop or line you’re after) and, if
you’ve set an optional TfL API key (app_key), that key as your own credential, sent with your own
TfL calls and nowhere else. Location is sent only on demand, never in the background. The one
use beyond that is a trip you start: it’s checked on the phone while you walk to a stop you’re
boarding at, while you wait there, just after you board, and as your train nears the station you get
off at, app open or closed, and never sent (see On the way, below).
National Rail times (optional). If you paste a National Rail API key (from the Rail Data
Marketplace) in Settings, stopdash also asks National Rail’s live departure boards for the
departures at a railway station you’re looking at. That request carries only the station’s
three-letter National Rail code (e.g. WAT for Waterloo) and your key, never your location. Your
key is your own credential, sent only with those requests, never logged. Without a key, no
request goes there. The station codes themselves come bundled with the app, built from NaPTAN,
the Department for Transport’s public stop list.
Nothing else leaves the device to stopdash unless you turn on Help make StopDash better in Settings, which is off by default (see Crash reports and usage stats below): no third-party tracker, no ads, and no server of stopdash’s own.
On a release build, stopdash makes one other kind of network call — to Google Play, asking whether an app update is available (this drives the “update available” dot on the menu). It is a Play Services query about the app’s own version; it sends no location, watched stops, API key, or any other user data — nothing about you or your travel — so it adds no new Play Data Safety category beyond Google Play’s existing role as the app’s distributor. It is free, runs release-only (a debug build isn’t a Play app), and silently does nothing if Play is unavailable.
Three channels other than a TfL or National Rail request can carry user data off the device, and all three are under your control rather than stopdash’s. The first is the crash reports and usage stats you can opt in to (see below): off unless you turn them on, they send Firebase crash details, app interactions, device details and identifiers, and the approximate region Google derives from your IP address, but never your location, stops or journeys. The second is your own Android backup and device-to-device transfer, if you have it enabled: like any app’s data, your saved stopdash data (your settings and its last-good departures snapshot) rides it, so a phone swap keeps your setup — all but the crash-report opt-in, which stays with the install, and the rows your watch’s complications show, which the phone relearns from the watch. That is Android’s channel, tied to your Google account — not something stopdash sends. The third is a bug report you choose to send (see Sending a bug report below): it hands the app you pick a diagnostic report that, unlike everything else here, includes your exact location and a screenshot of the screen you sent it from — but only after a consent screen that says so, and then to your clipboard and the app you pick (the clipboard copy happens as soon as you confirm — detailed below). So the guarantee is precise rather than absolute: without your opt-in, the only user data stopdash itself sends off the device goes in its TfL requests, and its National Rail requests if you’ve added a key (the Play update check carries none), plus, if a paired watch has the StopDash watch app, the widget’s stops and departures to that watch (above); with it, the crash reports and usage stats above go to Firebase too. Android’s backup carries your saved data under your control, and a bug report carries what you consent to share.
Your Wear OS watch (optional; not released yet). If a watch paired with your phone has the StopDash watch app installed, the phone sends it what your home-screen widget shows, so the watch can show it too: the widget’s stops (their names and IDs, and the nearby stops each is compared against, which are worked out from your phone’s last location), their departures, TfL’s public service status for their lines (such as “Severe Delays”), for each direction where TfL says an alert only affects one way, and whether you dismissed it in the app, which rows you’ve starred, and which kinds of transport you’ve hidden. It never sends your coordinates or your API keys, and the watch never contacts TfL, National Rail or anything else itself. In the other direction, the watch sends the phone its requests to refresh, which carry only a random request number, and the row each StopDash complication shows (its stop ID, line and direction), so the phone keeps those rows in what it sends. This goes through Google Play services’ Wearable Data Layer: over Bluetooth when the watch is near, but when it isn’t (a watch on Wi-Fi or mobile data) it may pass through Google’s servers. Nothing is sent when no paired watch has the app. The watch keeps only the latest copy, never backs it up, and doesn’t log it. For Play’s Data Safety form, the determination is that this moves your own data between your own devices and stopdash never receives it, so it adds no data type collected by the developer; the relay’s handling by Google (its encryption and retention) is to be confirmed against Google’s documentation, and the form re-checked, before the watch app is released.
Find a station (the menu’s From… and To…, and a station’s To…) sends the name you type to TfL’s stop search, once you pause typing, and then the chosen station’s id to look up its stops and departures, and the station’s own position (a public place, not yours) to find the stops around it (for To…, the stops and the routes of the lines leaving where you start from; a To… from the near-me list starts from the location the near-me list was found from, which goes to TfL’s Journey Planner as the trip’s start — see Trips with a change — and refreshing it or coming back to the app finds your location again, exactly as the near-me list does). The name isn’t saved, logged or sent anywhere else. The last eight stations you open from From…, and separately the last eight destinations you pick in To…, are remembered on the device to list under Recent, in app storage that Android never backs up or transfers; they are never logged or sent anywhere, and clearing the app’s data removes them. So that a starred stop can be listed by name there, the place each starred row belongs to (its stop area or station, as TfL names it) is kept the same way, and forgotten once you unstar it. The search also lists and matches your starred stops and the stops the app has lately shown you, all read on the device; none of that is sent anywhere either.
Favorite places (Home, Work, School or a place of your own, saved from Settings) are stored by location. When you add or edit one, the stop or station you type is sent to TfL’s stop search, once you pause typing, to find its position — the same search Find a station uses. You can instead type a postcode: when you tap to look it up, it is sent to TfL’s Journey Planner, which returns the place(s) it names for you to choose from. A postcode is the same kind of location data the app already sends to plan a trip — no new kind of data leaves the device. Either way the text you type in the search field isn’t saved, logged or sent anywhere else; only the place you then choose is saved — by its coordinate and the name it resolved to (for a postcode, that name may be the postcode itself), the same as choosing a stop. The saved place — its coordinate, its label, and the name of the stop or station it resolved to (shown under the label, e.g. “Oxford Circus”) — is kept on the device with your other settings, so it rides your own Android backup and device transfer like the rest (above); it is never logged or put in a bug report, and deleting the place or clearing the app’s data removes it. Tapping a saved place plans a trip to it from where you are (see Trips with a change below).
Trips with a change (To… from the near-me list or a From… station) send both ends of the trip together to TfL’s Journey Planner. A trip from the near-me list starts from your location, the position the near-me list was found from, so the Planner can walk you to whichever stop or station serves the trip best. That is usually the position the nearby-stops lookup has just sent TfL; when the app reused a recent lookup of the same spot instead (below), opening the trip is what sends it; a trip from a From… station starts from that station’s stop id. The destination goes as the stop you picked. When you pick a station complex such as King’s Cross St. Pancras, the Planner is asked once for each of its stations and once for its bus stops, each request carrying the same start. A trip to a saved favorite sends its stored coordinate as the destination — the Planner walks the last leg to it — while the favorite’s name and id stay on your device. Your location and a favorite’s coordinate are the same Location data the app already shares with TfL, so they add no Play Data Safety category. The Planner is asked when a trip opens, again when you’ve moved on from where it was planned, about every 15 minutes while it stays on screen (every 5 while a route’s arrival can’t be told without a fresh plan), and when you tap Try again; while a trip is on screen, the departures at each stop where a route boards are fetched from TfL like any other stop’s, along with its lines’ status. The plan is held in memory only, never saved or logged beyond coarse diagnostics (a stop id, an HTTP status), and nothing runs once you leave the trip.
A trip on the way (after you tap Start on a route) is kept on the device until you arrive or end it: the route’s stops and lines, the leg you’re on and the train followed, in app storage that Android never backs up or transfers, so the trip survives the app being closed. It’s never logged beyond coarse diagnostics (a line id, an error kind) or sent anywhere. While a trip is on the way, app open or closed, stopdash asks TfL about every 30 seconds where the followed train will call next, by TfL’s own id for that train, and for the departures at a stop where the next leg boards; neither says anything about you that the trip’s departures don’t already. Ending the trip, or arriving, deletes it. The “get off soon” alert names the stop and the trip’s destination on your lock screen, like any notification; you can turn it off in Android’s settings for StopDash. While a trip is on the way, an ongoing notification shows its next step, until you arrive or end the trip (or, for a trip left running, four hours after it started). If you’ve allowed location, stopdash takes your precise position about every 30 seconds while you walk to a stop you’re boarding at, only to see whether you’ve reached it, and for the first ten minutes you wait there for your train, only to see whether you’ve already left on another (at a later stop of the ride, or well along it), a few times in the five minutes after your train leaves that stop, only to see whether you got on (you’re still at the stop if not), and a few times as your train nears the station you get off at, only to see whether you’re already there. Each is compared on the device with the public positions of the ride’s stops (and a station’s entrances) and then dropped: never logged, kept, or sent anywhere.
Starred journeys (two stops you travel between) are kept on the device with your other settings and stars, so they ride your own Android backup like the rest (above); they are never logged or sent anywhere. For the widget, the departures at a journey’s nearer stop, and which of them reach the other end, are saved with the widget’s other departures on the device. Showing a journey’s trains fetches the departures at its nearer stop from TfL, like any other stop.
Held in memory only: the last precise (GPS) position, for up to 10 minutes, so a rough network position that comes in while you haven’t moved doesn’t replace it. It is never written to storage or logged, is sent only as the position of a nearby-stop lookup or as the start of a trip you open from the near-me list (and, when a lookup used it, in a bug report you choose to send, as described below). Past 10 minutes it is no longer used, and it is deleted the next time the app takes a location or when the app’s process ends, whichever comes first.
Kept on the device, never backed up: to skip a repeat stop lookup when you reopen the app near where you last used it, stopdash keeps the positions of its last few nearby-stop lookups (up to four places) and the stops found around each, for up to a day, in the app’s cache directory. Android never includes that directory in a backup or device transfer, it is never logged or sent anywhere, and clearing the app’s cache removes it; an entry older than a day is deleted the next time the app looks up nearby stops.
The routes and stop areas the app fetched (a line’s stops, and the stops grouped with a journey’s starting stop) are kept the same way, for up to a day, so reopening a route doesn’t ask TfL again. They are TfL’s public network data, but which ones are there says which routes you looked at, so they stay in the app’s cache directory too: never backed up, logged, or sent anywhere, and an entry older than a day is deleted the next time the app starts or looks up a route or stop area.
If — and only while — you turn on Help make StopDash better in Settings, stopdash sends crash reports to Firebase Crashlytics and usage statistics to Google Analytics for Firebase (Google). It is off by default: nothing is collected until you turn it on, and a crash from before you did is discarded rather than sent (if one is waiting, reporting starts the next time you open the app).
What it sends:
•••, and an error’s message text is dropped (its type and code location stay).
Errors the app catches and survives are reported the same way, and so is a crash that closes
the app: its message text is dropped before Crashlytics sees it.What it never sends: your location (coordinates), the stops or stations near you, your starred rows or journeys, what you searched for, or your TfL API key. stopdash strips the advertising-ID permission, so the advertising ID isn’t collected either.
Turning it off stops collection at once, discards any crash report not yet sent, and resets the Analytics app-instance ID. The choice is kept on this device only: restored onto a new phone from a backup, it starts off again until you turn it back on. Development (debug) builds never send anything. Firebase is free at stopdash’s scale; uploads are batched by the SDKs, with no extra wakeups or location requests. For the Play Data Safety form this adds Crash logs, Diagnostics, App interactions, Device or other IDs and Approximate location (the region Analytics infers from your IP address), all optional (user-controlled).
StopDash keeps a diagnostic log on the device so a misbehaving routing or departure decision can be explained — for example, why “couldn’t get your location” appeared, or why a line showed “couldn’t check for disruptions”. Diagnosing those needs a record of what the app saw, so the log carries coarse state and reasons, and nothing more:
victoria, 940GZZLUOXC),429, offline),network, gps), the accuracy radius that provider
reported (or “unknown”), and how old it was; when a remembered precise fix is weighed
against a rough network one, how far apart the two are — never a coordinate,IllegalStateException), or a fixed “no app to open the Play listing” reason — never any
Play account, device, or version detail,IOException) —
never the place’s label, its coordinate, or the typed search text.The log never carries:
app_key or your National Rail key,These diagnostics are written to Android’s Logcat (visible to a developer with the
device connected) and to a persisted log file on the device — a small rotating file in
the app’s private cache (excluded from backup), kept so that a crash or a silent process
kill still leaves a record of the last thing the app saw. The persisted log stays on the
device. The one off-device destination is Crashlytics, and only while you’ve opted in (above):
it receives the log’s off-device rendering, with every stop ID, line ID and coordinate
replaced by ••• before it leaves the app. The logging runs through one shared on-device buffer
(mikelward/androidlog), wired incrementally: a feature whose warning seam isn’t connected
yet is discarded rather than recorded.
Two ways to get the log off the device for a bug report are foreseen, and they draw the
privacy line differently. A location-safe export — the log shared with its travel data
(stop IDs and line ids) redacted, since a shared file is otherwise subject to the same rule
as any other artifact that leaves the machine (AGENTS.md Privacy) — is still planned
(TODO.md). The other is the consent-gated bug report described next, which does the
opposite on purpose: it keeps the location in, openly and under consent, because that is the
context a routing bug is diagnosed from.
StopDash can send a bug report from its overflow menu. This is the one channel that deliberately carries what the on-device log never does — so it is gated by an explicit consent screen that names exactly what leaves, and nothing is assembled or sent until you pass it. The report carries:
It is user-initiated and £0: stopdash runs no service of its own for it. Tapping Send bug report opens the consent screen; on Continue the report is copied to your clipboard (on-device, but readable by other apps from then) and handed to Android’s share sheet, where you choose the app it goes to — an email, an issue, a chat. So the clipboard copy happens as soon as you tap Continue; nothing is sent to a destination you pick until you pick it, but the report has left the composing screen at that point. A “don’t ask again” option skips the consent screen on later reports; it never sends anything on its own, and it lapses whenever the report starts carrying more, so you see the new list before it is sent.
This is an honest trade, not a location-safe one: a report useful for a where did routing go wrong bug has to say where you were, so this one says so plainly rather than stripping the context to look safe. For Play Data Safety it is a user-initiated share of app diagnostics, a screenshot, and a coarse-or-precise location to an app you choose — disclosed here as such.