Here's a fresh release of Open Wearables - v0.4.1 is out 🚀
This one's packed - two new integrations from community contributors, proper sleep stage tracking across providers, raw payload storage, and a new webhook streaming architecture.
We're currently working on a lot of improvements around integrations and broader data type support for Garmin, Whoop, Oura - as well as sleep scores and external webhooks. There's a lot happening behind the scenes, so expect more frequent releases in the coming days.
Highlights
Fitbit integration
Open Wearables now supports Fitbit via OAuth 2.0 with activity sync out of the box. Huge thanks to @coelho-k for building this one from scratch 🎉
Ultrahuman integration
Another community-driven addition - @gudvin-byte contributed Ultrahuman as a new provider 🎉
Sleep stage tracking for Garmin and Oura
Sleep data just got a lot richer. We now save granular sleep stages (deep, light, REM, awake) from both Garmin and Oura, and adjacent sleep sessions from cloud-based providers are automatically merged so naps and interrupted sleep don't show up as fragmented entries.
Incoming webhook stream architecture
New streaming architecture for incoming webhooks, laying the groundwork for real-time data processing pipelines.
Apple Health: SNS notifications
Apple Health XML uploads now use SNS notifications instead of SQS queues, simplifying the async processing pipeline.
React Native SDK documentation
@dtochetto-tbb contributed documentation for the React Native SDK 🎉
More: https://openwearables.io/docs/sdk/react-native/index
Testcontainers for backend tests
Backend tests now run against real PostgreSQL and Redis instances via testcontainers - no more mocking infrastructure in integration tests.
What's Changed
Integrations
- feat(integrations): add Fitbit OAuth 2.0 and activity sync by @coelho-k in #627
- feat: add Ultrahuman provider by @gudvin-byte in #323
Sleep
- feat(backend): handle sleep stage saving from Garmin by @czajkub in #670
- feat: save sleep stages from Oura by @czajkub in #690
- feat(backend): merge adjacent sleep sessions in cloud based providers by @KaliszS in #679
- fix(backend): avoid race condition while persisting sleep state by @KaliszS in #661
- fix(backend): derive Garmin sleep end_datetime from stage timeline by @bartmichalak in #748
- fix(backend): backfill Garmin sleep end_datetime from stage timeline by @bartmichalak in #752
API & Backend
- feat(backend): Switch from SQS queue to SNS notifications for Apple XML upload by @czajkub in #599
- feat: store raw API responses and webhook payloads for Oura integration by @bartmichalak in #667
- feat: store raw API responses via store_raw_payload by @bartmichalak in #668
- feat: implement deregister on user deletion by @czajkub in #681
- feat(backend): incoming webhook stream architecture by @KaliszS in #750
- feat(backend): delay updating deps due to the security reasons by @KaliszS in #703
- feat(backend): added testcontainer for pytest by @KaliszS in #692
- feat(backend): redis testcontainer by @KaliszS in #747
- refactor(backend): Schema directory refactor by @czajkub in #560
- refactor(backend): Improve Oura 24/7 data extraction by @czajkub in #749
- fix(backend): update last_synced_at when data arrives via Garmin webhook by @bartmichalak in #590
- fix(backend): reset connection status to active on reconnect by @slavarosin in #656
- fix(backend): skip SDK-based providers in sync_vendor_data task by @bartmichalak in #671
- fix(backend): added avg hr calculation for all workouts by @KaliszS in #680
Frontend
- feat: add 'Last Synced' column and simplify users table by @bartmichalak in #674
- feat: move upload and delete actions to dropdown menu by @bartmichalak in #691
- fix: Fix NaN in average heart rate display (#480) by @HeyangQin in #654
- fix: round total minutes before splitting in formatBedtime by @farce1 in #673
- fix(frontend): pair page redirect for unauthenticated users by @bartmichalak in #732
- fix(frontend): inline decimal.js-light to fix SSR build error by @bartmichalak in #731
Docs
- docs: Adds React Native SDK documentation by @dtochetto-tbb in #636
- docs: update supported providers list by @bartmichalak in #657
- docs: add MinIO setup for local raw payload storage by @bartmichalak in #660
- docs: fix 'No users found' troubleshooting section for MCP by @bartmichalak in #669
- fix(docs): update Garmin coverage docs by @czajkub in #677
- docs: add dedicated Open Wearables Mobile App page by @bartmichalak in #775
- docs: add Samsung Health developer mode warning by @bartmichalak in #784
Other
- docs: add CodeRabbit config for documentation enforcement by @bartmichalak in #658
- chore: add CodeRabbit check for data migration impact by @bartmichalak in #751
- chore: migrate docs links from docs.openwearables.io to openwearables.io/docs by @psobusiak in #768
- chore: add bartmichalak as frontend code owner by @bartmichalak in #782
Security
- chore: add Dependabot configuration for Python and npm by @bartmichalak in #734
- chore: set commit-message prefix for Dependabot PRs by @bartmichalak in #745
- chore: remove unused setuptools from dev dependencies by @bartmichalak in #746
- chore: bump faker from 38.2.0 to 40.5.1 in /backend by @dependabot in #743
- chore: bump the npm-minor-patch group across 1 directory with 27 updates by @dependabot in #754
- chore: bump @types/node from 22.19.1 to 25.3.3 in /frontend by @dependabot in #737
- chore: bump jsdom from 27.2.0 to 28.1.0 in /frontend by @dependabot in #738
- chore: bump vite-tsconfig-paths from 5.1.4 to 6.1.1 in /frontend by @dependabot in #741
- chore: bump vitest from 3.2.4 to 4.0.18 in /frontend by @dependabot in #739
New Contributors
- @coelho-k made their first contribution in #627
- @dtochetto-tbb made their first contribution in #636
- @HeyangQin made their first contribution in #654
- @gudvin-byte made their first contribution in #323
- @slavarosin made their first contribution in #656
- @dependabot made their first contribution in #743
Full Changelog: 0.4...0.4.1