openGym

Application

DuarteSantos8/openGym

Self-hosted gym and body-weight tracker with passkey login and PWA support.

Overview

openGym is a self-hosted workout and body-weight tracker that keeps all data on your own server. It offers routine planning with 1,300+ exercises, guided sessions with rest timers and PR detection, muscle recovery maps, and imports from FitNotes, Strong and Hevy. Ships as an installable PWA with passkey sign-in, offline support and cross-device sync.

README Preview

\n\n\n\n**A self-hosted gym and body-weight tracker you actually own.**\n\nPlan your week, run guided workouts, log every set and your body weight —\non your phone, synced across your devices, behind your own passkey login.\n\n[](https://discord.gg/e62jY6fwVb)\n[](https://discord.gg/e62jY6fwVb)\n[](https://github.com/DuarteSantos8/openGym/stargazers)\n\n[](https://github.com/DuarteSantos8/openGym/releases)\n[](https://github.com/DuarteSantos8/openGym/actions/workflows/test.yml)\n[](https://gitlab.com/DuarteSantos8/opengym/-/pipelines)\n[](https://gitlab.com/DuarteSantos8/opengym/-/pipelines?ref=main)\n[](LICENSE)\n\n[Website](https://opengym.duarte-santos.ch) ·\n[Live demo](https://opengym.duarte-santos.ch/demo/) ·\n[Android APK](https://github.com/DuarteSantos8/openGym/releases/latest) ·\n[Self-hosting guide](docs/SELF_HOSTING.md) ·\n[Roadmap](ROADMAP.md) ·\n[Changelog](CHANGELOG.md)\n\n\n\n\n\nHome · today's workout and weight\nGuided workout · demos and sets\nStats · heatmap, charts and PRs\n\n\n\n## Why openGym\n\nMost workout apps keep your data on their servers, push you towards a subscription, or vanish\nwhen the company does. openGym runs on your own box, keeps your data in a folder you control, and\nis yours to fork. It still behaves like a modern app: installable on the home screen, passkey\nsign-in, works offline, syncs between your phone and your laptop.\n\nNo account on someone else's server, no subscription, no ads, no telemetry. One\n`docker compose up` and it's running.\n\nThe [in-browser demo](https://opengym.duarte-santos.ch/demo/) is the real app with example data,\nif you want to try it before installing anything.\n\n## Features\n\n**Planning**\n\n- A routine per weekday over a library of **1,324 exercises** with animated demos, searchable and\n  browsable by muscle on a body map. Filter by the equipment you own.\n- Four starter plans (Push/Pull/Legs, Upper/Lower, Full Body, 5×5) that load as ordinary,\n  editable routines.\n- Move a session to a

FAQ (4)

Troubleshooting
Why can't the openGym Android app connect to a self-hosted server using a private CA certificate?

Root cause: since Android API 24, an app without a networkSecurityConfig trusts system CAs only — user-installed CAs are ignored. The WebView inherits this policy, so the TLS handshake to your private-CA server fails silently and requests (e.g. POST /api/pair/redeem) never reach the server. Chrome works because it trusts user CAs. Fix (requires rebuilding the APK): create frontend/android/app/src/main/res/xml/network_security_config.xml with <network-security-config><base-config cleartextTrafficPermitted="false"><trust-anchors><certificates src="system" /><certificates src="user" /></trust-anchors></base-config></network-security-config>, then add android:networkSecurityConfig="@xml/network_security_config" to the <application> tag in AndroidManifest.xml. Workaround without rebuilding: install the PWA from Chrome on the phone instead of the native app — Chrome trusts your user CA, so passkey sign-in and sync work. Note: plain HTTP via LAN IP also fails because the WebView origin is https://localhost and allowMixedContent is false.

GitHub Issue #213
Troubleshooting
Why does the AI Coach return 404 when connecting to an OpenAI-compatible endpoint without a /v1 prefix (e.g. Open WebUI's /openai mount)?

In openGym v1.4.0 the Coach always appends /v1 to the base URL, so it calls {base}/v1/chat/completions, which 404s on servers mounted under a path with no version segment (Open WebUI's /openai proxy in front of llama.cpp/llama-swap, reverse-proxied Ollama, etc.). Fix: upgrade to openGym v1.4.1. There, when {base}/v1 answers 404, the Coach automatically retries {base} directly and remembers the working form, so pasting the endpoint exactly as the provider documents it (e.g. http://127.0.0.1:8099/openai) works for both List models and Test the Coach.

GitHub Issue #508
Troubleshooting
Why does importing from Strong or Hevy merge two workouts on the same day into one?

This is a bug in openGym v1.4.0: the CSV import and the Hevy API import group workouts by calendar date only (see byDate in frontend/src/lib/import-csv.js and parseHevyWorkouts in frontend/src/lib/import-hevy.js), so a morning and an evening session get combined into a single workout. Fix: upgrade to openGym v1.4.1 or later. Since v1.4.1, imports from Strong, Hevy CSV, and the Hevy API group by date plus workout start time, so two sessions on the same day stay as two separate workouts. FitNotes imports are unaffected because FitNotes exports only contain a date (no start time), so they still group by day.

GitHub Issue #505
Troubleshooting
Why is the "Type" (exercise type) line missing when adding an exercise during a workout in openGym?

This is a UI bug fixed in openGym v1.4.1. In earlier versions, the "Add exercise" view during a workout only showed "Muscle" and "Equipment" rows, omitting the "Type" row shown in the Exercise browser. Update openGym to v1.4.1 or later and the Type row will display correctly when adding an exercise.

GitHub Issue #521