Insights

Open Wearables 0.8.0: Withings, sync history, and a platform built to run in production

Author
Bartosz Michalak
Published
September 14, 2026
Last update
September 14, 2026

Table of Contents

Key Takeaways

  1. Withings joins as a new provider, with the body, activity, sleep, and workout data categories available straight away.
  2. Historical sync status moved from Redis, which kept it for 24 hours, into the database. A new sync history API records when a long historical sync actually finished and where it stopped if it dropped, so it can be resumed from that range. Live syncs are deliberately not recorded.
  3. Data ingestion is roughly 3.7 times faster on large batches after a rewrite of the bulk upsert path, and Apple Health XML uploads now handle files up to 5 GiB.
  4. Four account takeover vulnerabilities are closed, all of them backwards-compatible. API keys are stored hashed, password changes revoke refresh tokens, developer records are restricted to their own account, and Garmin webhooks verify the client ID header.
  5. Apple Health imports now run identically against AWS S3 and self-hosted MinIO, which means a fully local deployment with no AWS dependency can ingest multi-gigabyte exports.

Is Your HealthTech Product Built for Success in Digital Health?

Download the Playbook
Playbook ebook illustration

Open Wearables, our open-source platform for health intelligence, just shipped version 0.8.0. Withings joins as a new provider, and alongside it this release concentrates on what happens after the data starts flowing: knowing whether a sync worked, moving large volumes without falling over, and closing the gaps that matter when a platform holds real users' health data.

Withings is the headline addition. The parts that will change day-to-day operations are underneath it.

Withings: a new provider, fully wired from day one

Withings is now a supported provider in Open Wearables. Body, activity, sleep, and workout data categories are all available straight away, using the same normalized data model as every other source.

Withings covers a device category that wrist-worn trackers do not. Body composition from connected scales, blood pressure and heart rate, blood glucose, blood oxygen, and body temperature all come through the same integration, alongside daily activity, sleep, and workouts. For teams building around weight management or cardiometabolic programs, that is data a fitness band does not report.

Two things to know before you plan a rollout. Sleep stage timelines, ECG, and HRV are not supported for Withings. And syncing runs by polling the Withings APIs by default: webhook push is optional, and because Withings creates notification subscriptions per user rather than once per application, an app without compliant webhooks is capped by Withings at 10 linked users. Full setup detail is in the provider documentation.

Historical syncs now leave a trace

Sync completion status was already being tracked, but it lived in Redis, and Redis keeps it for 24 hours. Anything older was gone. 0.8.0 moves that state into the database so it persists.

Three problems drove this, and all three are specific to historical syncs.

Redis was not durable. A 24-hour window is fine for checking whether last night's sync worked. It is useless for understanding what happened to a user's backfill a week ago.

Long historical syncs had no completion signal. Historical syncs pull large ranges, often a full year. On Apple that can take a very long time. The Redis status arrived when the sync started, not when it finished, so there was no way to tell a sync still running from one that died. The database now records when a historical sync actually ended.

Dropped syncs could not be resumed precisely. When a historical sync covering a year of data broke partway through, for example on a connection drop, there was no record of how far it had got. Restarting meant guessing. The per-data-type breakdown now shows where the run stopped, so it can be continued from that range rather than restarted from scratch.

0.8.0 introduces a sync run record capturing the provider, the scope, the status, timing, how many items came back, and any errors encountered. A companion record gives one row per data type per run, so a sync that pulled sleep successfully but failed on workouts shows exactly that instead of an opaque blob.

Live syncs are deliberately not written to the table. The data model supports them, but recording every live sync would flood it. Historical syncs are where the durability and resumability actually matter.

Runs that stop reporting are closed by a stale sweep, which checks Redis for liveness first so that a slow backfill is not cut off prematurely.

Two endpoints expose the data:

GET /users/{id}/sync/history
GET /sync/history/{run_key}

The data is available through the API in this release. Surfacing it in the admin panel is planned for the next frontend iteration.

Ingestion got substantially faster

The data point series bulk upsert was rewritten. The previous implementation issued chunked INSERT statements carrying an enormous number of bind parameters. A batch is now copied into a temporary staging table and merged into the target with a single statement.

Locally, that is a 3.7x speedup on a 50,000-row batch: 6.10 seconds down to 1.67.

Why it matters in practice: health data arrives in bursts. A user connects a new device and backfills months of history. A cohort syncs overnight within the same window. An Apple Health export lands with years of samples in one file. Ingestion throughput determines whether those bursts clear quickly or queue up behind each other, and queued ingestion means users looking at stale dashboards.

XML imports also moved to their own dedicated Celery queue, so a large Apple export no longer competes with routine provider syncs for worker capacity.

Multi-gigabyte Apple Health exports

The Apple Health XML upload limit moved from 1 GiB to 5 GiB, with a progress dialog on the frontend so large uploads are visible rather than appearing to hang.

Apple Health exports from long-term users are genuinely large, and users with years of accumulated history are often exactly the ones worth onboarding, because they bring that history with them. The old limit rejected those exports outright.

The flow now works identically against AWS S3 and self-hosted MinIO. Previously the XML path used a hard-coded AWS client and depended on SNS, which MinIO cannot emit. A fully local, AWS-free deployment can now ingest multi-gigabyte Apple exports through the portal, which matters for any organization with a policy against third-party cloud storage.

Security hardening

Four ways to take over an account or a deployment are now closed, all of them backwards-compatible, so upgrading does not require changes to your integration.

API keys are stored hashed. The raw value is shown only once, on create or rotate. The migration hashes existing keys in place, so current integrations keep working.

Changing a password revokes every refresh token the developer holds. Refresh tokens have no expiry, so previously a leaked token worked forever, including after the password was changed in response to the leak.

The developer patch endpoint is restricted to the caller's own account. Before this fix, any team member could set another developer's password.

Garmin webhooks compare the client ID header against the configured value, instead of only checking that the header is present.

Better provenance and richer workout data

Three providers were already sending per-workout provenance and the platform was dropping it. Workouts now carry entry source, intensity, and label fields, so you can tell a measured workout from a manually entered one and see the name the user gave it. Oura, Strava, Garmin, and Apple all populate these fields. Whether a workout was measured or typed in by hand changes how much weight it should carry in anything built on top.

Oura's intraday MET series is new data, not a change to anything you already have. Oura sends this series alongside daily activity, and the platform was not storing it at all. It is now parsed into individual timestamped samples at the provider's own interval and stored as physical effort, giving a continuous picture of how intense someone's movement was across the day.

Nothing about existing Oura data changes, so there is no daily-to-intraday migration to plan for. This is an additional series that starts appearing after you upgrade. Oura is the only provider exposing MET at this granularity today, so it is currently Oura-only.

The Ultrahuman integration now parses granular sleep stages from the sleep graph and stores skin temperature as a proper series. Suunto gained pause-aware stop times, recovered sleep windows that were previously dropped, awake time, and SpO2Max and average HRV from sleep sessions. Whoop's HRV is now split into RMSSD and SDNN as distinct metrics, with the recovery score field deprecated in the recovery summaries endpoint. Whoop also gained cycle endpoint support and a fix to the recovery endpoint.

Running it: Docker images and deployment

Official Docker images are the recommended deployment path:

  • Backend: themomentum/open-wearables-backend
  • Frontend: themomentum/open-wearables-frontend

Both now publish for linux/amd64 and linux/arm64 under the same tags as before, so ARM hosts pull a native image.

Tags follow a predictable scheme. The latest tag tracks the newest stable release, 0.8.0 and 0.8 pin to this one, and the nightly tag is unstable but always up to date with main, deployed every night. For production, pin a version.

The production Docker Compose setup has been replaced by a proper deployment guide, and provider and webhook documentation has been refreshed with deployment guidance.

Upgrading

Standard Docker Compose update. Database migrations run automatically on startup.

Two things to check before you upgrade:

If you track the nightly tag and updated between 2026-09-07T17:46:43Z and 2026-09-08T14:55:55Z, you may have pulled a version containing a faulty migration. Verify that your workout details table contains the entry source, intensity, and label columns. If they are missing, add them manually:

ALTER TABLE workout_details
  ADD COLUMN IF NOT EXISTS entry_source VARCHAR(32),
  ADD COLUMN IF NOT EXISTS intensity    VARCHAR(10),
  ADD COLUMN IF NOT EXISTS label        VARCHAR(255);

If you use the Garmin backfill controls, the cancel and retry endpoints are removed in this release and the status endpoint is deprecated. Garmin allows one backfill request per timeframe per type and answers 409 afterwards, so retry could never do anything useful. The per-type timeout and lock TTL cover what those controls were handling, and the periodic garbage collection task is gone as a result.

The full changelog is at github.com/the-momentum/open-wearables/releases/tag/0.8.0.

Community

Open Wearables is approaching 2,500 stars on GitHub, with 485 forks and 59 contributors to date. Six contributors made their first contribution in this release.

That last number is the one worth watching. Provider integrations, bug fixes, and documentation improvements increasingly arrive from people running the platform in their own products.

The project is at github.com/the-momentum/open-wearables. The Discord community is the fastest place to get an answer.

Frequently Asked Questions

What does the Withings integration actually add that we did not have before?
A device category that wrist-worn trackers do not cover. Body composition from connected scales, blood pressure and heart rate, blood glucose, blood oxygen, and body temperature, alongside the usual daily activity, sleep, and workouts. If your product touches weight management or cardiometabolic programs, that is data a fitness band does not report.
Are there limits on Withings we should know about before committing to it?
Two. Sleep stage timelines, ECG, and HRV are not supported. And Withings creates webhook subscriptions per user rather than once per application, so an application without compliant webhooks is capped by Withings at 10 linked users. Syncing works by polling the Withings APIs by default, so polling does not carry that cap.
Is the upgrade to 0.8.0 breaking?
No. All four security fixes are backwards-compatible and database migrations run automatically on startup. Two situations need a look first: if you track the nightly Docker tag and updated in a specific window in early September, one migration may have been faulty and needs three columns added by hand; and if you call the Garmin backfill cancel or retry endpoints, those are removed. Both are covered in the upgrading section above.
Do we need to reissue API keys after upgrading?
No. The migration hashes existing keys in place and current integrations keep working. From this release on, a newly created or rotated key is displayed once and cannot be retrieved afterwards, so store it when it is shown.
Where does sync history show up for our support team?
Through the API in this release, via two endpoints that return sync runs for a user or the detail of a single run. Surfacing it in the admin panel is planned for the next frontend iteration, so for now it is something you query or wire into your own tooling.
Why are live syncs not tracked?
Deliberate choice. The data model supports them, but writing a row for every live sync would flood the table. The problems this solves, durability beyond 24 hours, knowing when a long run finished, and knowing where a dropped run stopped, are specific to historical syncs.
How much faster is ingestion in practice?
Locally, 3.7 times faster on a 50,000-row batch, which measured 6.10 seconds before the rewrite and 1.67 after. It applies automatically with no configuration. The gain shows up where batches are large: backfills, cohort syncs, and Apple Health imports.
Can we run this without any AWS dependency?
Yes. The Apple Health XML upload flow now behaves identically against AWS S3 and self-hosted MinIO. The path previously used a hard-coded AWS client and depended on SNS, which MinIO cannot emit, so fully local deployments could not ingest those files. That gap is closed.
Is Open Wearables still open source and self-hosted?
Yes. MIT licensed, running on your own infrastructure, with official Docker images for backend and frontend now published for both amd64 and arm64.

Written by Bartosz Michalak

Director of Engineering
He drives healthcare open-source development at the company, translating strategic vision into practical solutions. With hands-on experience in EHR integrations, FHIR standards, and wearable data ecosystems, he builds bridges between healthcare systems and emerging technologies.

See related articles

Green background with decorative circles

Running wearable data in production?

Let's Create the Future of Health Together

Open Wearables is self-hosted and MIT licensed, so your health data stays on your own infrastructure. Momentum provides enterprise support, custom provider integrations, and HIPAA compliance guidance for teams moving to production.

Looking for a partner who not only understands your challenges but anticipates your future needs? Get in touch, and let’s build something extraordinary in the world of digital health.

Newsletter

Bartosz Michalak