Important
This release comes with some breaking changes for self-hoster. Please read carefully.
New features
Sync with Apple Health and Health Connect
The mobile app can now import your body metrics from Apple Health (iOS) and Health Connect (Android). Once enabled in the settings, the data your smart scale, blood pressure monitor, smartwatch or what other health apps record is imported automatically and shows up alongside your manually entered entries. At the moment we support these:
- body weight
- body fat
- lean body mass
- height
- blood pressure
- heart rate, summarised as one entry per day with the daily average, minimum and maximum
- resting heart rate
- blood oxygen, summarised as the daily average
- sleep, with the total per night plus the light, deep, REM and awake phases
- steps, distance and active energy, each as the daily total
Imported entries are marked as such and can only be changed or deleted in the app they came from, otherwise they could be overwritten in a future import. You can however still add entries by hand in every category, e.g. your blood pressure taken from a non-connected device.
Improvements to the Measurements
To support the data from the health sync, we have revamped the measurements. Each category can now have a type (body fat, heart rate, etc.), so that we can e.g. show the correct chart type. Additionally, the category list can be reordered.
It's also possible to save multi-value entries, such as the blood pressure.
Added a range selector for the period you want to look at. This should make loading measurements be considerably faster, which is noticeable with histories of several thousand entries.
We have also updated the available charts:
- the line chart now shows a moving average and a trend line besides the measured value
- the chart for body weight, body fat now shows when the different nutrition plans were active
- new bar chart, used for values such as the blood pressure
- heatmap, used for categories such as daily steps
- new change chart, one bar per week showing how far the value moved in it
- new distribution chart, showing how often each value occurred, with the median and the newest reading marked
Which chart a category gets follows from its type, but you can also pick it yourself when you edit the category. Only the charts that suit the type are offered, and a group is always drawn from what its components are.
Calculated categories
A measurement category can now be calculated by wger instead of typed in by you. At the moment there's available:
- BMI, from your body weight entries and the height
- waist to height ratio, from a category you measure your waist in
- the one-rep max of an exercise, estimated from your logged sets
- the total of two to five exercises, the classic being bench press, squat and deadlift added up
OAuth2 provider
wger can now act as an OAuth2 provider itself, so that other applications can let their users log in with their wger account and access the API on their behalf. This is switched off by default unless configured, see the docs for the setup.
Python client for the API
There is now an official Python client, generated from the openAPI spec, for anyone writing scripts or tools against a wger instance. For non-python users, the openAPI spec was cleaned up and expanded, so you can use it to generate clients for your language.
pip install wger-api-clientOthers
- Reworked internal structure for workout sessions. This now allows sessions to span midnight, and to log more than one session per day, e.g. morning cardio and evening gym.
- New exercise names are checked against the existing ones during submission. A name too similar to an existing exercise is rejected with an error
- Improved openAPI spec. The spec now properly describes the different parts of the API and can be used to generate clients.
- Emails are now send asynchronously via the celery queue, this should make registration, password resets, etc. feel a bit snappier. If celery is not configured, the emails are send as before
- Faster and stronger password hashing: passwords are now hashed with argon2 instead of PBKDF2. Argon2 is what Django itself recommends, but PBKDF2 is only the default because it needs no additional library. Existing passwords keep working and are migrated automatically on the next login.
- Streaks, calendar days and trophies are now calculated in your own timezone. The apps report it automatically, until they have, or for accounts that only ever use scripts, the server's timezone is used like before.
- Every body weight entry now remembers the unit it was entered in and is converted when needed. Previously, changing the unit in the profile from metric to imperial silently reinterpreted all past entries.
Bug fixes
- Ingredient search now finds matching words in long ingredient names and ranks more relevant results first
- Exercise search now finds matching words in long exercise names, e.g. "curl" finds "Alternating Biceps Curls With Dumbbell", and sorts the results by relevance
- Gated progressions (configs with
requirements) now advance exactly one step per qualifying workout instead of back-filling increments for skipped, non-qualifying iterations - Gated progressions now reach configs scheduled for later iterations, so multi-phase plans (e.g. bigger increments from week 6 on) work when the requirements are only met intermittently
- Ungated configs no longer back-apply increments of earlier gated configs whose requirements were never met
- Progression requirements are now checked against the rounded values as they are displayed, so reaching the shown prescription always counts
- The min and max configs of a field now advance together, following the requirements of the base config
New settings
(for self-hoster)
WGER_MAX_SESSION_LENGTH_HOURS(default 5) caps how long a workout session may be, now that sessions can span midnight.WGER_SHOW_APP_STORE_LINKShides the links to the mobile app storesUSE_X_FORWARDED_HOSTfor setups behind a reverse proxyIDP_OIDC_PRIVATE_KEYholds the signing key of the OAuth2 provider, see the docs for the management command that generates one.
Breaking API changes
(only relevant if you have your own scripts or interact with the REST API)
WeightEntry is gone
Under the hood, weight entries are measurements now: they live in the official body weight category, which is created automatically.
The /api/v2/weightentry/ endpoint will keep working during this release, so tools like openScale do not need any changes.
Measurement API
- Measurement categories gained
metric_type,parent,orderandis_official. There can be only one category per account and metric type, categories can be nested one level deep to group multi-value metrics, and measurements can only be added to categories that are not a group.is_officialis read-only and filterable, official categories cannot be deleted and theirmetric_typecannot be changed. - Measurements gained
source,external_idandextra_data. The unit of a body weight entry is stored inextra_data.unit(kgorlb). If it is missing, the unit of the category applies.extra_datais replaced as a whole on PATCH, so send back the keys you want to keep. - Categories gained
dynamic_typeanddynamic_paramsfor the calculated categories described above./api/v2/measurement-category/dynamic-types/lists what the server can calculate and which parameters each category takes. Only free-form categories without entries of their own can be calculated, and the calculation cannot be changed once it is set. sourcegained the valuecalculatedfor the entries such a category holds. They are refused on POST, PATCH and DELETE, since the server replaces them whenever what they are computed from changes.
Workout sessions
-
/api/v2/workoutsession/now usesdatetime_startanddatetime_end. The olddate,time_startandtime_endfields are gone from the responses and can no longer be filtered or sorted by. They are still accepted when writing so that offline writes queued by an older app version still arrive, but that is a temporary measure and will be removed in the next release. -
Sessions are no longer unique per user, day and routine.
-
datetime_startanddatetime_endsupportgt,gte,lt,lteanddate, so a single day is selected with?datetime_start__date=2026-01-15and a range with?datetime_start__gte=....
Userprofile
- New field
time_zoneon/api/v2/userprofile/for the user's IANA timezone name, e.g.America/Toronto. Date sensitive calculations, like the trophies are done using this value.
Removed
- Removed the temporary
/api/v2/issue-refresh-tokenendpoint. It existed only so the mobile app could exchange a permanent DRF token for a JWT refresh token. That migration has shipped and the app no longer calls it.
Upgrade steps
- Make sure
TIME_ZONEis set correctly before upgrading, and treat it as fixed afterwards. The migration converts the old session dates using this zone, and it stays the fallback for users whose apps have not reported their own one yet. Changing it later shifts those users' past training days. - Pull new changes from the docker repo. There were changes to the sync rules due to the new measurements. It is recommended to stop the powersync service while the db migrations are running:
docker compose pull docker compose down powersync docker compose up -d web docker compose up -d powersync
What's Changed
Features
- feat(exercises): prevent duplicate exercise names on submission and edit (#2357) by @pankaj-basnet in #2360
- Require POST for password reset and user (de)activation by @amitmishra11 in #2415
- refactor(weight): migrate WeightEntry to Measurement (wger#2328) by @pankaj-basnet in #2421
- Allow configuring wger as an OIDC provider by @rolandgeider in #2475
- fix(manager): advance gated progression exactly one step per qualifying iteration by @bentucker in #2465
- Improve ingredient search relevance for long names by @MikaelSiidorow in #2486
- Add Finnish language support by @MikaelSiidorow in #2487
- Improve exercise search by @rolandgeider in #2490
- Release 2.7 by @rolandgeider in #2483
- Feature/dynamic measurements by @dylans-dev in #2338
- Fix: Refactor WorkoutSession to support overnight workouts (#2379) by @deepu4402020 in #2422
- Remove old API token exchange by @rolandgeider in #2470
- Rework measurements by @rolandgeider in #2476
- feat(core): store timezone information per user (#2472) by @pankaj-basnet in #2482
Dependencies
- Update django-allauth[mfa] requirement from ~=65.17.0 to ~=65.18.0 by @dependabot[bot] in #2395
- Bump faker from 40.18.0 to 40.23.0 by @dependabot[bot] in #2394
- Bump reportlab from 4.5.0 to 5.0.0 by @dependabot[bot] in #2399
- Bump django-environ from 0.13.0 to 0.14.0 by @dependabot[bot] in #2400
- Bump django-simple-history from 3.11.0 to 3.12.0 by @dependabot[bot] in #2411
- Bump actions/cache from 5 to 6 by @dependabot[bot] in #2412
- Bump icalendar from 7.1.0 to 7.2.0 by @dependabot[bot] in #2413
- Bump django-prometheus from 2.4.0 to 2.5.0 by @dependabot[bot] in #2358
- Bump django-debug-toolbar from 6.3.0 to 7.0.0 by @dependabot[bot] in #2407
- Bump actions/checkout from 6 to 7 by @dependabot[bot] in #2398
- Bump tornado from 6.5.5 to 6.5.7 by @dependabot[bot] in #2388
- Bump pillow from 12.2.0 to 12.3.0 by @dependabot[bot] in #2418
- Bump coverage from 7.14.0 to 7.15.0 by @dependabot[bot] in #2420
- Bump actions/setup-python from 6 to 7 by @dependabot[bot] in #2438
- Bump django from 6.0.5 to 6.0.6 by @dependabot[bot] in #2433
- Update drf-spectacular[sidecar] requirement from ~=0.29.0 to ~=0.30.0 by @dependabot[bot] in #2423
- Bump faker from 40.23.0 to 40.28.1 by @dependabot[bot] in #2419
- Bump django-formtools from 2.6.1 to 2.7 by @dependabot[bot] in #2426
- Bump django-filter from 25.2 to 26.1 by @dependabot[bot] in #2450
- Bump openfoodfacts from 5.2.0 to 5.3.0 by @dependabot[bot] in #2424
- Bump tqdm from 4.68.1 to 4.70.0 by @dependabot[bot] in #2452
- Bump django-simple-history from 3.12.0 to 3.13.0 by @dependabot[bot] in #2451
- Bump django from 6.0.6 to 6.0.7 by @dependabot[bot] in #2468
- Bump sqlparse from 0.5.5 to 0.6.0 by @dependabot[bot] in #2488
- Bump wheel from 0.47.0 to 0.48.0 by @dependabot[bot] in #2485
- Bump flower from 2.0.1 to 2.1.0 by @dependabot[bot] in #2491
- Bump gunicorn from 26.0.0 to 26.1.0 by @dependabot[bot] in #2492
New Contributors
- @amitmishra11 made their first contribution in #2415
- @bentucker made their first contribution in #2465
- @MikaelSiidorow made their first contribution in #2486
- @dylans-dev made their first contribution in #2338
- @deepu4402020 made their first contribution in #2422
Full Changelog: 2.6...2.7