Install
openclaw skills install @chrischall/alltrails-fpxQuery alltrails.com (trail search, trail detail, reviews, photos, weather, and a signed-in user's saved lists / completed trails / activity feed) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the alltrails-mcp server — one-shot calls through a signed-in browser tab. Use when you want AllTrails data without the MCP, in a script, or on a machine where the MCP isn't installed.
openclaw skills install @chrischall/alltrails-fpxAllTrails has no public API; alltrails-mcp reverse-engineers the internal
one alltrails.com itself uses, fronted by DataDome. DataDome fingerprints
the HTTP client, not just the cookie — a Node/curl replay of a captured
cookie gets 403'd even the same day an identical in-tab fetch succeeds.
So every request must ride a same-origin fetch inside the user's own signed-in
tab, which fpx provides (no stored-cookie mode, unlike some other fleet
skills).
Every request also needs an x-at-key app header — a static, anonymous
client-identifier the web app sends on every /api/alltrails/* call. It is
not stored anywhere — capture it live from the tab's own traffic (below).
An in-tab fetch does not add it automatically, so it (plus
x-at-caller/x-language-locale) must be attached explicitly on every fpx
call, same as the MCP's client.ts does.
npm install -g @fetchproxy/cli # provides `fpx`
fpx profile add alltrails --domain alltrails.com
fpx profile declare alltrails \
--capture-header 'x-at-key@www.alltrails.com/api/alltrails/*'
fpx pair -p alltrails # prints a pair code → approve in Transporter
Requirements: the Transporter browser extension installed, its Chrome
Site access allowing alltrails.com, and an open, signed-in
www.alltrails.com tab (the per-user tools need a real session; the trail
tools work signed-out too). Pairing persists after the first approval.
x-at-key is captured from the tab's own API traffic — the capture only
fires while the tab makes a request. fpx session triggers the capture and
returns everything declared, including capturedHeaders:
AT_KEY=$(fpx session -p alltrails | jq -r '.capturedHeaders["x-at-key"] // empty')
If AT_KEY comes back empty, the tab hasn't made an /api/alltrails/*
request recently — feed it one and retry:
open 'https://www.alltrails.com/explore' # or refresh the open tab
AT_KEY=$(fpx session -p alltrails | jq -r '.capturedHeaders["x-at-key"] // empty')
Attach it (plus the other two protocol headers — defaults match the MCP's
ALLTRAILS_CALLER/ALLTRAILS_LOCALE) on every fpx get/post-json call:
fpx get 'https://www.alltrails.com/api/alltrails/v3/trails/10236086?detail=medium' -p alltrails \
-H "x-at-key: $AT_KEY" -H 'x-at-caller: Mugen' -H 'x-language-locale: en-US' \
| jq '.trails[0] | {name, overview, length, elevation_gain}'
Without x-at-key the API answers 400; a stale/rotated key answers 400
or 401 — re-run the fpx session capture to get a fresh one and retry.
Ready-to-run request bodies for every read endpoint are in
references/endpoints.md.
/me shapeGET /api/alltrails/me wraps the signed-in user as {"users":[{"id":...}]}
— not {"user":{...}}. Get your own numeric user id with:
fpx get 'https://www.alltrails.com/api/alltrails/me' -p alltrails \
-H "x-at-key: $AT_KEY" -H 'x-at-caller: Mugen' -H 'x-language-locale: en-US' \
| jq -r '.users[0].id'
The per-user endpoints (lists, completed trails, activity feed) take that id in the path.
0 — success (still check the JSON body — a non-2xx AllTrails error can
arrive as a 200 with an HTML/interstitial body; a non-JSON 2xx response
from fpx is almost always a DataDome challenge page, not real data).2 — bridge unavailable: extension not connected or pairing pending →
fpx pair -p alltrails, confirm an alltrails.com tab is open.3 — bot wall: the tab hasn't cleared DataDome → open/refresh a
www.alltrails.com tab and retry.4 — upstream non-2xx from AllTrails (400/401 usually means a missing or
stale x-at-key — re-capture and retry).GET/read POST (search, reviews) endpoints —
AllTrails write endpoints are unverified and out of scope.miles = meters / 1609.344,
feet = meters * 3.28084).fpx health -p alltrails shows bridge connection state when a call fails.