-
Notifications
You must be signed in to change notification settings - Fork 0
Data Source HealthSync
A fully Strava-API-free alternative. healthsync.app runs on Android or iPhone and exports activities to Google Drive as CSV + GPX + TCX files. healthsync-activities.sh downloads those files, parses them with curl + jq, and produces the exact same activities.json and HTML pages as strava-my-activities.sh.
- Activity summary from CSV (distance, duration, elevation, calories, sport type)
- GPS track from GPX (rendered in-browser via Leaflet polyline, same as Strava)
- Heart rate and cadence from TCX (
<AverageCadence>/AvgRunCadence), or from GPX trackpoint extensions (<gpxtpx:cad>) when no TCX is present - All five pages: My Activities dashboard, activity detail (with map, splits, HR/cadence charts), personal stats, bike service tracker
Strava activity IDs are numeric; HealthSync IDs are date-based strings like 2026-06-22-20-01-ride. All pages handle both transparently.
1. Create a project and enable the Drive API:
- Go to Google Cloud Console
- Create a new project (or use an existing one)
- Enable the Google Drive API (APIs & Services → Enable APIs → search "Drive")
2. Create an OAuth client:
- Go to APIs & Services → Credentials → Create Credentials → OAuth client ID
- Choose Web application as the application type
- Add
https://developers.google.com/oauthplaygroundas an authorized redirect URI - Save; note the Client ID and Client Secret
3. Add yourself as a test user:
- Go to APIs & Services → OAuth consent screen
- Under Test users, add your Google account email
- This lets you authorize without publishing the app (see note on token expiry below)
4. Get a refresh token via OAuth Playground:
- Go to OAuth Playground
- Click the gear icon → check Use your own OAuth credentials
- Enter your Client ID and Client Secret
- In Step 1, find Drive API v3 and select
https://www.googleapis.com/auth/drive.readonly - Click Authorize APIs and grant access
- In Step 2, click Exchange authorization code for tokens
- Copy the Refresh token value
Full step-by-step with screenshots is in config-healthsync.example.
vi /etc/healthsync-activities.confRequired settings:
GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com"
GOOGLE_CLIENT_SECRET="GOCSPX-..."
GOOGLE_REFRESH_TOKEN="1//0..."
DRIVE_FOLDER_ID="1AbCdEfGhIjKlMnOpQrStUvWxYz" # from the Drive folder URLThe DRIVE_FOLDER_ID is the last segment of the Google Drive folder's URL: https://drive.google.com/drive/folders/FOLDER_ID_HERE.
Set HEALTHSYNC_DEFAULT_BIKE to the name of your default bike (used as the seed when no bikes are stored yet).
healthsync-activitiesA healthy run ends with done. and includes:
activities.json: N activities
drive-status.json: ok
Place Magene_MODEL_YYYY-MM-DD_ID_*.fit files (exported from a Magene cycling computer) in the same Google Drive folder as your HealthSync exports. On each run, healthsync-activities.sh:
- Downloads new FIT files
- Converts them to GPX via the free GPS Visualizer API (no account required)
- Caches the GPX locally
Only active in HEALTHSYNC_MODE=full (the default).
If a Magene FIT file covers the same ride as a HealthSync watch export (TCX/GPX) — start times match within ±10 min and end times match within ±5 min — the two records are merged rather than creating a separate Magene activity:
- The watch record keeps its heart-rate data (which the Magene doesn't have)
- The merged record gains the Magene's wheel-sensor-accurate distance, speed, cadence, and elevation
- The merged record carries a
dual_source:trueflag and amagene_idback-reference
FIT odometer. For a standalone Magene activity (no matching watch record), distance is extracted directly from the FIT binary's odometer field — wheel-sensor accuracy, typically more precise than GPS. Falls back to Haversine if the FIT doesn't contain usable odometer data.
Google OAuth refresh tokens for apps in Testing mode expire after 7 days. Apps with a published OAuth consent screen keep their token as long as the script runs at least once every 6 months (cron guarantees this).
When a token refresh fails, healthsync-activities.sh writes drive-status.json with {"ok":false} to the web dir and the My Activities dashboard shows a yellow "Google Drive access expired" banner.
To re-authorize: repeat the OAuth Playground flow (Step D in config-healthsync.example) to get a new refresh token, then update GOOGLE_REFRESH_TOKEN in /etc/healthsync-activities.conf over SSH:
ssh root@192.168.1.1
vi /etc/healthsync-activities.conf # update GOOGLE_REFRESH_TOKEN
healthsync-activities # verify it worksThe banner clears on the next successful run.
Note: Google does not support the device authorization flow for Drive scopes, and the OOB redirect was removed in 2022. The
/cgi-bin/drive-authCGI link is non-functional. Use the OAuth Playground flow described above.
To re-render HTML from the existing local store without making any Drive API calls:
HEALTHSYNC_IMPORT_ENABLED=0 healthsync-activitiesSet in the config or pass as an environment variable. Useful after editing a dashboard helper script to preview changes without re-fetching.
When a run adds no new activities and none of the helper scripts (strava-my-html-*.sh, strava-lib.sh) have been modified since index.html was last written, the script skips re-emitting all HTML output and logs no new activities and scripts up-to-date — skipping re-emit. This keeps nightly cron runs cheap when nothing has changed.
healthsync-activities uses a lock directory (/tmp/healthsync-activities.lock) to prevent overlapping runs — for example if a manual run is still in progress when cron fires. A second instance detects the lock and exits immediately, logging another instance is already running (PID … ). Stale locks left by a previously crashed run are detected by checking whether the recorded PID is still alive; if not, the lock is removed and the run proceeds normally.
See Switching-Data-Sources for migration steps that preserve your full Strava history.