Self-hosted health and fitness tracker. Vanilla HTML/CSS/JS, Supabase backend, Claude AI assistant for natural-language logging. No framework, no build step, no subscriptions.
Try the demo at gonespral.github.io/my-tracker.
Note
This project is heavily vibecoded. It exists because every fitness tracker I tried either lacked the one feature I actually needed, buried it behind a subscription, or couldn't integrate with Strava and Google Fit without janky middleware. So I built my own. Expect rough edges and code that works because it works.
- AI Logging: Chat with Claude to log food, workouts, and weight in plain English. Attach photos and Claude uses vision to identify meals. Frequently logged items are suggested as presets automatically.
- Nutrition: Daily food tracking with calorie and macro targets (rest vs. training day). Meal presets for quick re-logging.
- Workouts: Manual logging with intensity, duration, distance, and heart rate. Activity presets.
- Voice input: Dictate food or workout entries via the Web Speech API.
- PWA: Installable, mobile-first, dark mode, smooth animations.
- Privacy-first: Your Supabase instance, your data. Row-Level Security on all tables. API keys live only in
localStorage.
- Auto-sync: Pulls the last 90 days of activities from Strava on load. Deleted Strava activities are removed locally on the next sync.
- Push to Strava: Manually logged workouts can be pushed to Strava directly from the Workouts tab.
- Auto-push: Optionally push every new locally logged activity to Strava automatically.
- Cross-push: Optionally push Google Health imports to Strava automatically.
- Calorie spoofing: Strava doesn't allow setting calories on manually created activities via the API. When enabled, the app derives a synthetic heart rate from your logged calories, duration, weight, age, and sex (Keytel et al. 2005), uploads the activity as a TCX file, and lets Strava compute the calories from heart rate data. Requires weight, age, and sex set in Settings → Profile.
- Delete from Strava: Delete synced activities from Strava directly within the app, with a confirmation prompt.
- Sync controls: Pause/resume Strava sync without disconnecting.
- Duplicate detection: Activities already in your Supabase database are never re-imported.
- Stacked duplicate cards: When the same activity is detected from multiple sources (e.g. both Strava and Google Health), they are displayed as stacked cards with expand/collapse.
- Custom credentials: Use your own Strava API app instead of the shared one.
- Auto-sync: Pulls the last 90 days of activities from Google Health on load.
- Push to Google Health: Manually logged workouts can be pushed to Google Health directly from the Workouts tab.
- Auto-push: Optionally push every new locally logged activity to Google Health automatically.
- Cross-push: Optionally push Strava imports to Google Health automatically.
- Delete from Google Health: Delete synced activities from Google Health directly within the app, with a confirmation prompt.
- Sync controls: Pause/resume Google Health sync without disconnecting.
- Duplicate detection: Activities already in your Supabase database are never re-imported.
- Custom credentials: Use your own Google Cloud OAuth client instead of the shared one.
- Bidirectional sync: The same activity type mapping is used in both directions, so a run synced from Strava and pushed to Google Health keeps its type.
A persistent indicator in the header shows which integrations are currently syncing and highlights any that have failed, with a spinner on the refresh button during active sync.
See SETUP.md for full step-by-step instructions.