Summary
On a patch's detail screen, parks (parkData) and national forests (forestData)
list their trails with a difficulty and a length. This feature adds, under that list,
one tappable row per trail, "Open <trail name> in AllTrails", that tries to open the
AllTrails app with a search for the trail's name and falls back to an AllTrails web
search. That is the whole feature: a name search handed to another app.
It is built and switched off. The alltrails_integration flag defaults to false
and its own description says "Currently broken — keep off until the deep link /
fallback flow is fixed" (mobile/src/config/feature-flags.ts:39-44). Nobody outside
a development build or an admin's own device can see the row.
Status
Built, flag pinned off, unreachable by users.
- The rows shipped unflagged on 2026-05-11 (
92471eeb) and were gated the same day behindalltrails_integration, default off (b4134380, "gate AllTrails integration behind alltrails_integration flag (off)"). The commit body gives no further reason; the flag description is the only recorded one. - The flag exists only in the mobile registry (
mobile/src/config/feature-flags.ts:39). It has no row in the backend registry (backend/src/admin/feature-flag-definitions.ts, noalltrailskey), andGET /api/feature-flagsiterates the backend's key list (backend/src/admin/api/feature-flags-api.controller.ts:69-91), so the response never mentions it. The app merges{ ...DEFAULT_SERVER_FEATURE_FLAGS, ...flags }(mobile/src/query/queries/featureFlags.ts:33), and the default isfalse(feature-flags.ts:43,:127-133). The admin Feature Flags page lists only backend keys (feature-flags-api.controller.ts:104), so there is nothing to toggle. - The only way the row renders is a device-local override from the in-app Feature
Flags screen (
FeatureFlagsProvider.tsx:40-55, precedence defaults → server → local), which is itself limited to dev builds, the admin account, orfeature_flags_visible(mobile/app/(drawer)/feature-flags.tsx:44). That override affects one phone.
User-facing surfaces
None today. If the flag were on, the row would appear in two places:
- Patch detail → Explore tab (the type tab for
parkData, named "Explore",mobile/src/domain/patch-type-data.ts:21): under Trails, oneExternalLinkRowper trail, testIDtrail-alltrails-<name>, label "Open <name> in AllTrails" (mobile/src/components/patch-detail-v2/tabs/types/ParkTypeTabV2.tsx:86-129). - Patch detail → Nature tab (
forestData,patch-type-data.ts:24): the same row per trail (ForestTypeTabV2.tsx:68-89).
Both tabs are part of the new patch detail screen's type-tab set
(tabs/types/dispatch.ts:21-26, tabs/types/index.ts:75, :78). The previous screen
(new_patch_detail_screen off) keeps only the Battle type tab
(patch-type-data.ts:79-83), so it would never show these rows at all.
A third copy lives in the Scout.* component library for the DEV Library screen
(mobile/src/scout/patch/types/ParkTypeTabV2.tsx, ForestTypeTabV2.tsx; a LinkRow
demo at mobile/src/scout/catalog.tsx:1979 with a no-op press). That is a design
catalogue behind Drawer → DEV, not a user surface.
How it works
- Data. A park or forest patch carries
trails: Array<{ name, difficulty, length }>in itsparkData/forestDataJSON (mobile/src/domain/types.ts:35-39,:128,:146;backend/prisma/schema.prisma:189,:191). The shape is produced by the enrichment script's per-type schema (backend/scripts/patch-enrich.ts:60-69,:84-93). There is no AllTrails id, URL or slug anywhere in the data, the schema or the backend (no match for "alltrails" underbackend/). - Gate.
ParkBody/ForestBodyreadisEnabled('alltrails_integration')fromuseFeatureFlags()(ParkTypeTabV2.tsx:52-53,ForestTypeTabV2.tsx:44-45) and render the rows only when true (:98-100,:77-87). The trails list itself renders regardless. - Tap.
openAllTrails(trailName)URL-encodes the name and callsLinking.openURL('alltrails://search?q=<name>'); if that rejects it trieshttps://www.alltrails.com/search?q=<name>; if that rejects too it gives up silently ("No browser/app available — silently give up. Nothing actionable.",ParkTypeTabV2.tsx:32-43,ForestTypeTabV2.tsx:24-35). Both files carry the same function; nothing is shared. - Nothing comes back. No result is read, nothing is stored, no analytics event fires.
Data model
None of its own. Reads Trail.name from patches.park_data / patches.forest_data
(schema.prisma:189, :191). No table, column or migration mentions AllTrails.
API surface
None. No backend endpoint, no flag row, no server-side code.
Key files
mobile/src/config/feature-flags.ts:39-44— the flag, default false, "Currently broken — keep off"mobile/src/components/patch-detail-v2/tabs/types/ParkTypeTabV2.tsx:32-43,:98-129— the opener and the rows (Explore tab)mobile/src/components/patch-detail-v2/tabs/types/ForestTypeTabV2.tsx:24-35,:77-87— the same (Nature tab)mobile/src/components/patch-detail-v2/tabs/types/_shared.tsx:319—ExternalLinkRowmobile/src/scout/patch/types/ParkTypeTabV2.tsx,ForestTypeTabV2.tsx,mobile/src/scout/data/LinkRow.tsx— library copies (DEV only)mobile/src/providers/FeatureFlagsProvider.tsx:49-60— why a server-less flag stays at its defaultbackend/src/admin/api/feature-flags-api.controller.ts:69-91— why the server never serves itmobile/app.json— contains noalltrailsscheme (iOSLSApplicationQueriesSchemesis not needed foropenURL, only forcanOpenURL, which this code does not call)
Configuration and flags
| Flag | Registry | Default | Prod | Effect |
|---|---|---|---|---|
alltrails_integration |
mobile only (feature-flags.ts:39) |
false |
not served, so false | Shows the "Open in AllTrails" rows under Trails on the Explore and Nature tabs |
There is no backend row to create: the admin page is generated from the backend
registry, and adding the key there would be a code change and a deploy, not a toggle
(feature-flag-definitions.ts:1-7, feature-flags-api.controller.ts:104-110).
Edge cases and known limits
- The deep link is a guess.
alltrails://search?q=is not sourced from any AllTrails documentation in this repo; whether the AllTrails app registers that scheme and honours aqparameter is unverified. The flag description calls the "deep link / fallback flow" broken; the code has not changed since the gate landed. - Name search, not a trail link. A trail called "Rim Trail" opens a search for "Rim Trail" across all of AllTrails, not the trail in this park.
- Silent failure. If neither the app nor a browser opens, nothing is shown.
- Three copies of
openAllTrails. Two shipping tabs and one library tab each hold the function; a fix must land in all three. - Trails without AllTrails coverage (a short interpretive loop, a bluff walk) still get a row; the row does not know.
- Stale docs elsewhere.
docs/features/admin-and-content-ops.md:125correctly records the flag as client-only (dated 2026-08-31);unlock-and-location.md:30lists it by name only.
What this feature does NOT do
- No user can see it. Not in TestFlight, not in the App Store or Play build, not on
iPad. The row exists in the code and nowhere on a customer's screen. Any sentence in an
ad, a store listing or
/contextthat says Scout "links to AllTrails", "opens trails in AllTrails" or "integrates with AllTrails" is false today. - It cannot be turned on from the admin. The flag is not in the backend registry, so
the Feature Flags page does not list it and
GET /api/feature-flagsdoes not carry it. Enabling it for users requires a code change in the backend registry and a decision to lift the "Currently broken" note, then a deploy. - It does not open a specific trail. It opens a text search for the trail's name.
- It does not import, display or sync anything from AllTrails: no trail maps, no reviews, no photos, no distance or elevation, no AllTrails account, no API key. Scout holds no AllTrails credentials and makes no request to AllTrails servers.
- It is not a partnership or affiliate link. There is no referral parameter and no commercial relationship in the code.
- It does not record a tap, change a patch, or affect unlocks, trips or navigation.
- It is not on every patch type. Only
parkDataandforestDatatabs have the rows;trailData(the Trail type's own "Adventure" tab) does not link to AllTrails. - It does not appear on the previous (flag-off) patch detail screen even if the flag were on, because that screen renders only the Battle type tab.
Tests that cover it
None. No screen test, hook test, Maestro flow or unit test references
alltrails_integration, trail-alltrails- or openAllTrails
(searched mobile/screen-tests, mobile/hook-tests, mobile/src/**/__tests__,
mobile/maestro). The feature's off state is covered only indirectly: the type-tab
tests that exercise ParkTypeTabV2 with the flag at its default never render the rows.
Open questions
- What exactly was broken on 2026-05-11. The gating commit carries no body and the
flag description is the only record. Candidates from the code are the unverified
alltrails://search?q=scheme and anopenURLthat may not reject cleanly on every platform (so the web fallback never runs), but neither was reproduced for this doc. - Whether to keep it at all. A name search handed to another app is a thin capability; removing the three copies would be smaller than fixing them. Decision owner: Alan.