Distance Goal

Why Distance Goal is the way it is

Every decision that shapes what the app does, what it will not do, and how it is released — with the date, the reason, and whether it still stands. A decision that was overturned stays on the page, marked, because “we tried that, and here is why it stopped” is what anyone proposing it again needs to read.

23 decisions, newest first: 20 current, 1 superseded, 2 withdrawn.

Rules that bind any future work

These follow from the decisions below. Anything new is checked against them before it is designed.

  1. 1

    If a feature would show one person's content to another, the rules change before it ships. The app becomes a user-to-user service again: the Online Safety Act comes back into scope, and the parts of the terms removed on 6 September 2026 come back before the feature ships, not after. The feature's age gating is decided when it is designed. (6 September 2026, 13 August 2026)

    Terms of Service

  2. 2

    The published documents are legal statements. The privacy policy, the terms, Google Play's Data safety form and Apple's App Privacy label must describe a behaviour before a build ships it. The privacy policy commits to that in its own text. (13 August 2026)

    Privacy Policy

  3. 3

    Health Connect data moves only as the user's own act. It is read on the phone and never sent anywhere by the app. Google's terms cover data derived from or aggregated with Health Connect as well as the records themselves, with no exception for blending — so a goal total that includes auto-tracked distance is still Health Connect data, and it leaves the phone only when the user sees it and sends it themselves, on a card, a link or an export. Never for advertising, data brokers, or insurance, credit or employment decisions, and the app is never marketed to employers or insurers. The terms are a contract, not a preference. (July 2026 onwards)

    How Health Connect is used

  4. 4

    A shared link carries numbers, dates and ids — never free text, and never an identity. (6 September 2026)

    The link format

  5. 5

    Two different builds never share a version name, and a build number is never reused once a signed build exists — even one that no store ever saw. (3 September 2026)

    Changelog

  6. 6

    The Google Play category is Health & Fitness. Never Social. (1 August 2026)

  7. 7

    Reminders are about something the user decided to do — never engagement bait, and never about other people. (13 August 2026)

The decisions, newest first

Status says whether a decision still stands. Superseded means a later finding replaced it; withdrawn means the feature it governed was taken out of the app.

CurrentFrom 2.6.0.

Buddy groups — small groups seeing each other's progress through an end-to-end-encrypted relay server, with app-generated names, invite codes, and ways to rename, hide, report and remove — were withdrawn. In their place the app shares outward: a progress card, and a link that lets whoever receives it start the identical goal on their own phone. The group chat a family, class or club already has does the rest.

Why. Everything heavy about buddy groups followed from one fact: the app carried content from one person to another, which made it a user-to-user service. With nothing carried between people:

  • The Online Safety Act no longer applies — no risk assessments, no children's access assessment, and no section 66 duty to report child sexual exploitation and abuse content.
  • Apple's App Review Guideline 1.2 and Google Play's user-generated content policy no longer apply.
  • Google Play's Families policy has nothing to gate.
  • The encryption leaves the app, so its export-compliance answer to Apple becomes “no encryption”, the app can be offered in France again, and no filing is owed to the US Bureau of Industry and Security.
  • Google Play's Data safety section returns to “No data collected”, Apple's App Privacy label to “Data Not Collected”, and neither age rating involves user-generated content.

Measured by the repository at the time: 790 lines of protocol, carrying 25,522 words of compliance prose.

Given up, knowingly. No live view of other people inside the app, no pooled team total, and sharing is a deliberate act each time.

What it left behind.

  • The buddy-group fields stay in the app's data model. There was no migration: a phone that had groups keeps everything and loses nothing, and an exported backup still leaves the group secrets out.
  • The relay server stays up, untouched, until older Android installs have updated and its 60-day expiry has emptied it. Then it is deleted.
  • An old buddy-group invite (one beginning DG1.) is recognised by the app and the website, and explained rather than treated as an error.
CurrentFrom 2.6.1.

Links are written on distancegoal.bluetorch.co.uk from 2.6.1. Version 2.6.0 wrote them on www.bluetorch.co.uk/distance-goal/join, and both are accepted for ever. A shared link's preview in a chat shows Distance Goal, not the publisher's consulting site.

CurrentFrom 2.6.1.

“Share progress” shows the card and, under it, the message that goes with it; one button, Share my progress, hands both to the share sheet in one go. Copy the message is the fallback. The figures always travel, because the picture shows them anyway — so there is no switch.

The first 2.6.0 screen had “Share the link”, “Copy the link” and an “Include my progress” switch bolted under the old card button. “Share the link” is plumbing vocabulary nobody uses, and two share actions for one intention was a journey nobody had designed.

It needed a native dependency: expo-sharing sends a file and nothing else, and React Native's own Share cannot attach a file on Android. react-native-share sends the image with the text as its caption, on both platforms, from one call. Only its Share.open is used, so its config plugin is not installed.

Current

Nothing in the app measures anything. A shared link is the instrument: the join page records a page view and a cookieless, aggregate Vercel Web Analytics event (which built-in journey, and whether progress was included) — never the figures, and never anything about who tapped.

Installs, retention and crashes come from App Store Connect and Google Play Console. In-app usage counters are deferred until there are enough users for them to mean anything, and would be first-party, anonymous and declared when they come.

Current

The “No account, no ads, no tracking” section came out of the store listing. The facts are unchanged and live where they belong — the privacy policy and the store forms — but the pitch is the goal (13 August, below), not what the app refrains from.

Current
  • iPhone only. No iPad available for testing can run the app, so iPad layouts could never be tested, and declaring iPad support would mean Apple reviewing a layout nobody had seen. The app still installs on an iPad, in scaled iPhone mode.
  • iOS 16.4 is the floor, set by Expo SDK 57's expo-modules-core podspec — stricter than React Native 0.86's own 15.1. When this comes up again, check the podspec, not the React Native constant.
  • Not in the Kids Category. It is optional, and it adds obligations rather than removing any: a parental gate on every link out of the app, and a stricter review. An honest age rating says the same thing without them; a nine-year-old can still download the app.
  • No HealthKit yet. The iPhone app reads no health data at all, and nothing in the iPhone listing may promise auto-tracking.
CurrentSet by the 2.5.1 release.

The Settings screen shows only the version name, so a support question that says “2.5.1” must mean one build. When Android and iPhone builds of the same code carry different names because of this, the changelog says so.

The companion rule came on 6 September: a build number is never reused once a signed build exists, even if no store ever saw it, because a real signed file on disk can be uploaded by mistake. That is why Android build 12 — a signed 2.5.2 bundle that Google Play never saw — was discarded rather than reused.

Current

The version name, the Android versionCode and the iOS build number are in app.json, and eas.json sets appVersionSource to “local”. Until 2.3.0, EAS — Expo's build service — kept the Android counter on its own servers and increased it automatically. The remote value had drifted to 5 while 7 was live on Google Play, so the next build would have been rejected on upload. A number in a file shows up in a diff.

CurrentFrom 2.3, after a user's report.

A goal's activities are “Every activity” or “Just the ones I pick”, and picking starts from nothing, so a tap only ever adds. The chips used to start fully selected, so tapping “Walking” to choose it turned it off — and nothing on any screen showed a goal's activities, so the resulting zero could not be diagnosed.

Now the goal shows what it counts, and an entry that counts toward nothing says which goal nearly matched and why.

WithdrawnShipped in 2.5.0.

Withdrawn on What ended it: Buddy groups withdrawn; sharing goes outward.

Removing someone from an end-to-end-encrypted group means changing the group's secret and handing the new one to everyone except the person removed. Only the group's creator could do that, and a creator who left had to nominate a successor.

Carrying a person's groups across to a new phone (with recovery codes) was parked: it would have needed per-person state on the relay server.

Current

The positioning, replacing “private by design, we take nothing”. Solo-first: the goal is the product; journeys, badges and sharing are what keep you at it.

Not chosen: “walk together” — buddy groups, leaderboards, a community total. It promises a social product the app is not, and at the time half of everyone an invite reached was on an iPhone and could not act on it.

CurrentFrom 2.3.0.

A new user sees three starter goals, and one tap creates a real one:

The table scrolls sideways.

The three starter goals
StarterTargetWindowAbout
A month of moving50 km / 30 miles30 days1.7 km a day
London to Birmingham163 km (a journey)A season1.8 km a day
Land's End to John o'Groats1,407 km (a journey)Two years — “take as long as you like”1.9 km a day

Three ambitions that look nothing alike, and all the same daily habit — that is the pitch in three cards, and a test asserts every starter stays between 1.5 and 2 km a day. A round-number starter carries both a kilometre and a mile target rather than converting one into an ugly number.

No “onboarded” flag, no tour, no change to the stored data. Every question onboarding asks is “do you have a goal, an entry, a badge” — never “have you seen this”. A fact cannot fall out of step the way a flag can. Hints retire against facts. Permissions are asked for at the point of use, never on first run. A dismissible tour is the one thing that would force a stored flag, and it is not being built.

The one judgement call: on Android, the offer to auto-track from Health Connect appears under the ring while Health Connect is off but available and the person has logged three entries or fewer, then retires by itself. Three is arbitrary and the offer has no memory, so someone who deletes their entries sees it again. If that proves annoying, a stored dismissal is the fix — and the change to the stored data that comes with it.

Current

Nothing is refused on principle any more — not a third-party SDK, not a feature that transmits, not an account. We made the call with about three users, all known to us; the cost of changing course would never be smaller.

What did not change, because it was never ours to drop:

  • Controller duties under UK GDPR.
  • The ICO's Children's Code, while the audience includes 9 to 12-year-olds.
  • Google's Health Connect terms.
  • The rule that the published documents change before the app's behaviour does.

The old question was “does this send data anywhere?”. The new one is “does the published policy still describe this, and is it gated properly for an audience that includes nine-year-olds?”.

That the app makes no network connection at all since 2.6 is a consequence of withdrawing buddy groups, not a principle reinstated.

Current
  • Photos between users: version 5 at the earliest, never for under-18s, and only behind real age verification. Images are a different category of service.
  • Accounts: no longer refused on principle. Google Sign-In specifically is wrong for this audience — most 9 to 12-year-olds have no Google account, and under-13s cannot consent under UK GDPR. An anonymous recovery-code account is the cheaper route if carrying data across phones is ever wanted.
  • Home-screen widget: waits for Expo SDK 58.
Superseded

Superseded on What ended it: Buddy groups withdrawn; sharing goes outward.

With buddy groups live, a distance and a target entered by one user and seen by another met the Act's definition of a user-to-user service, and the roadmap at the time (photos, typed group names, leaderboards) would only have deepened that. The finding reversed an out-of-scope assessment of 3 August.

Withdrawing buddy groups returned the app to out of scope. What survives is the first of the rules at the top of this page.

CurrentOn Android.

Android Auto Backup does not copy the app's data to a Google account: the app switches backup off, and its data-extraction rules say the same thing. At the time, that data included buddy-group credentials.

Device-to-device transfer is deliberately allowed. With no account and no cloud copy, it is the only automatic way a person keeps their goals, history and badges when they change phone. Turning it off would mean “new phone, everything gone”. It was once listed as a gap to close; that was corrected, and it is not one.

WithdrawnShipped in 2.0.0.

Withdrawn on What ended it: Buddy groups withdrawn; sharing goes outward.

A small group — 2 to 8 people who already knew each other, a coach being simply another member — saw each other's progress, with no email, username, profile or directory. Progress was encrypted on the phone and passed through a relay server that stored only what it could not read.

Display names were generated from a fixed, vetted list, because free text is the entire harm surface: removing it made “negligible risk” provable rather than asserted. The published figure was distance, not a percentage. Streak and last-active were separate switches, because they reveal illness and travel.

The cost, accepted at the time: Google Play's Data safety form is per app, so the “No data collected” badge went for everyone, including people who never touched the feature. It came back with 2.6.0.

Current

The Google Play target audience is 9 to 12 — the youngest sensible band, because a walking-goal app a family uses together should not pretend to be 18+. The consequence is that the terms and the privacy policy are written to be read by a nine-year-old, and must stay that way.

The category is Health & Fitness, never Social: Google Play's Child Safety Standards follow the category declaration, not the feature set.

CurrentBuilt for 1.8, which was held; first reached people in 2.0.0.

Export offers a spreadsheet, day-by-day totals, plain text, a formatted report, Markdown and a full backup. GPX, TCX and FIT are deliberately not offered: they describe GPS tracks with timestamps and durations, and the app stores a date and a distance — writing one would mean inventing a duration that Strava would then treat as real.

Restore only ever adds. It never overwrites or deletes, so restoring an old backup cannot lose the walking done since. It never changes units, reminders or Health Connect settings on the phone being restored to.

CurrentBuilt for 1.7, which was never released; first reached people in 2.0.0.

Badges belong to the person, not to a goal. The app banks one figure per calendar day — the furthest it has ever seen that day — so deleting an entry, deleting a goal, or a Health Connect source app deleting its history can never un-earn a badge.

CurrentAndroid only; from 1.3, extended in 1.6.
  • Off by default, double opt-in: a setting for the whole app, and a switch on each goal.
  • Two read permissions and no more: distance (READ_DISTANCE) and, from 1.6, exercise (READ_EXERCISE) — used only to tell a walk from a ride, because distance records carry no activity type and a cycling goal would otherwise count walks. From a workout the app takes the start time, end time, activity type and which app recorded it. Never the route: the exercise-routes permission is not declared, so Health Connect cannot return coordinates. Never steps, heart rate, calories or sleep.
  • Records are read again, not stored. Each time the app comes to the foreground it reads again. What it keeps is what the user's own choices need: one figure per day for badges, the activity labels set by hand, the sources excluded, and — for a record marked as a duplicate of a hand-logged walk — that record's start, end, distance and source, so it stays uncounted.
  • Declining the exercise permission is fine. The numbers are simply less well attributed; logging by hand always works.
  • Android 8 (API level 26) or newer has been required since 1.3.
CurrentFrom 1.2.

There is one list of entries. Each entry automatically counts toward every goal whose dates and activities it fits, so overlapping goals can share the same walk. A goal can be left out of any entry, with chips on the entry form. Deleting a goal never deletes an entry.

Considered and rejected: a global “mode” switch — one goal at a time, or each entry assigned to a single goal. This design was chosen instead, and the switch is not coming.

CurrentFrom the first build.

Every stored distance is in kilometres; miles are a display setting (from 1.1). A date that means a calendar day — a goal's window, an entry's date — is stored as a local YYYY-MM-DD string, never a timestamp, so a walk logged on 12 July stays on 12 July in every timezone.

More about Distance Goal

Distance Goal is published by Bluetorch Consulting Ltd.

What has changed in each versionHow it is built