The wearable app development checklist: what you actually need to build (and what you don't)
Key Takeaways
- OAuth flow differs per provider and must be implemented individually unless you use a unified abstraction layer
- Token refresh is required for providers like Strava (6-hour expiry) and Whoop, and must be handled automatically
- Webhook registration is mandatory for Garmin, which does not support polling-based sync
- Unit normalization (heart rate in bpm, distance in meters, timestamps in UTC) must happen at ingestion, not at query time
- Deduplication within a single provider is handled by Open Wearables via
external_id; cross-provider merge logic is your responsibility - Apple Health, Google Health Connect, and Samsung Health require a mobile SDK and cannot be synced from the cloud
- Open Wearables handles the integration plumbing; your business logic, UI, and user authentication are outside its scope
- The most common scoping mistake is underestimating provider-specific edge cases, not the core data model
Scoping a wearable feature is harder than it looks. You know you need heart rate data from Garmin. Maybe sleep from Oura. Maybe workouts from Strava. The first architectural diagram fits on a napkin. Then you start reading the provider docs and the napkin fills up fast: OAuth flows that differ per provider, tokens that expire after six hours, webhook registration requirements, timestamp formats that vary by device firmware, and a deduplication problem that only shows up when a user connects both their Garmin watch and their iPhone.
This checklist is for founders and PMs who are scoping that project right now. It maps what you actually need to build, what Open Wearables handles for you, and what you will still own no matter what.
The checklist
1. OAuth flow per provider
Each provider runs its own OAuth 2.0 implementation with different scopes, redirect requirements, and consent screens. Building this yourself means maintaining multiple OAuth clients, handling provider-specific quirks, and keeping up with API changes.
OW handles this. A single endpoint covers all supported providers:
GET /api/v1/oauth/{provider}/authorize?user_id={id}&redirect_uri={url}
2. Token storage and refresh
Access tokens expire. Strava tokens expire after six hours. Whoop tokens auto-refresh but require an active paid membership on the user's side. Storing tokens securely and refreshing them before they expire is table stakes, but it is also boilerplate you do not want to maintain.
OW handles this. Token lifecycle management, including automatic refresh, is built into the provider integration layer.
3. Webhook endpoint registration and retry logic
Some providers push data to you rather than waiting for you to pull it. Garmin is webhook-only, meaning you must register an endpoint, handle incoming payloads, and implement retry logic for failed deliveries. Missed webhooks mean missing data.
OW handles this. Register a webhook endpoint once:
POST /api/v1/webhooks/endpoints
OW handles the provider-side registration and retry behavior.
4. Polling for providers without webhooks
Not every provider supports webhooks. For those that use polling, you need to manage sync scheduling, backfill windows, and avoiding duplicate ingestion on repeated polls. Garmin's 30-day historical backfill is a specific case: use the dedicated endpoint, not generic /sync.
OW handles this. Provider-specific sync endpoints abstract the polling strategy:
POST /api/v1/providers/garmin/users/{user_id}/sync/historical
POST /api/v1/providers/whoop/users/{user_id}/sync
POST /api/v1/providers/suunto/users/{user_id}/sync?data_type=all
5. Data normalization (units, timestamps, field names)
Garmin reports distance in meters. Some providers use local time. Field names for the same concept differ across APIs. If you normalize at query time, you will do it in every downstream consumer. If you never normalize, you will ship a bug to production.
OW handles this. Normalization is applied at ingestion: heart rate in bpm, distance in meters, temperature in Celsius, all timestamps in UTC. Your app reads clean data.
6. Deduplication within a provider
A user might sync the same workout twice: once from a manual trigger and once from a webhook. Without deduplication, you store duplicate records and your aggregations break.
OW handles this. Records are deduplicated by external_id within a provider. The same workout will not appear twice.
7. Cross-provider deduplication
A user who wears a Garmin watch and uses Strava will generate overlapping workout records. OW stores them as separate records with different provider values. Deciding which source wins, or how to merge them, requires product judgment: do you prefer GPS data from Garmin or the activity metadata from Strava?
You build this. OW does not auto-merge across providers. Cross-provider merge logic belongs in your application layer because it depends on what your product needs.
8. Pagination through large datasets
A user with years of historical data will not fit in a single API response. User listings use offset-based pagination. Data endpoints use cursor-based pagination via next_cursor. Getting this wrong means silently missing records.
OW handles this. Pagination is built into the data retrieval endpoints. Your client code needs to follow the cursor, but the server-side implementation is handled.
9. Mobile SDK integration (Apple Health, Google Health Connect, Samsung Health)
Apple Health has no cloud API. Neither does Google Health Connect or Samsung Health. These providers require a native mobile SDK. There is no server-side workaround.
OW handles partially. OW includes mobile SDK support for these providers. You still need to embed the SDK in your mobile app and handle the platform-specific setup on the client side.
10. Data storage schema
OW provides a storage layer with its own schema, but your application will likely need to join wearable data against your own user records, product events, or business data.
You build this (partially). OW handles storage for the wearable data it ingests. Your schema for connecting that data to the rest of your product is yours to design.
What OW handles out of the box
Stand up the stack:
git clone https://github.com/the-momentum/open-wearables.git
cd open-wearables
docker compose up -d
API at http://localhost:8000. Admin panel at localhost:3000. Full Swagger docs at localhost:8000/docs.
Authenticate with a header on every request:
X-Open-Wearables-API-Key: YOUR_API_KEY
Once a user has connected a provider through the OAuth flow, you retrieve unified data with standard GET requests regardless of which provider it came from:
GET /api/v1/users/{user_id}/events/workouts
GET /api/v1/users/{user_id}/events/sleep
GET /api/v1/users/{user_id}/timeseries
GET /api/v1/users/{user_id}/summaries/
The response format is the same whether the data came from Polar, Oura, or Strava. Units are already normalized. Timestamps are already UTC.
For more granular provider-specific sync:
POST /api/v1/providers/polar/users/{user_id}/sync?samples=true&zones=true&route=true
What you still need to build
OW handles the integration plumbing. It does not handle your product.
Cross-provider merge logic. If a user connects Garmin and Apple Health, you will have two sets of workout records covering the same time window. OW stores both with their respective provider values. Deciding which one to surface, how to avoid double-counting in your dashboard, or how to present conflicts to the user: that is your code.
Your own user authentication. OW uses its own API key auth. Your application has its own user accounts, sessions, and permissions. Mapping your user IDs to OW's user_id parameter and managing that relationship is your responsibility.
Business logic. OW gives you normalized health data. What that data means for your product, what thresholds trigger a notification, what a "good week" looks like for your users: all of that lives in your application layer.
UI. OW has no frontend components beyond the admin panel. Charts, dashboards, summaries, and anything a user sees is yours to build.
Getting started
git clone https://github.com/the-momentum/open-wearables.git
cd open-wearables
docker compose up -d
API at http://localhost:8000. Admin panel at localhost:3000. Swagger at localhost:8000/docs.
MIT-licensed and self-hosted.
Source and full documentation: https://github.com/the-momentum/open-wearables
Related articles
- How to normalize wearable data across providers
- How to sync wearable data from multiple devices
- Strava API integration guide for health and fitness apps
- How to integrate Apple Health data into your app
FAQ
Does Open Wearables work with Apple Health?
Yes, via mobile SDK. Apple Health does not expose a cloud API, so there is no server-side sync path. You need to embed the OW mobile SDK in your iOS or Android app to collect Apple Health data.
How does OW handle token expiry for providers like Strava?
Strava access tokens expire after six hours. OW auto-refreshes tokens before expiry so your syncs do not fail silently. You do not need to implement refresh logic yourself.
What happens when a user connects both Garmin and Strava?
OW stores records from each provider separately, identified by their provider field. There is no automatic cross-provider merge. If the same workout exists in both, you will see two records. Deciding which to use or how to merge them is your application's job.
Can I use OW in a production app or is it only for prototyping?
OW is MIT-licensed and self-hosted, which means you control the infrastructure and can run it in production. It is designed to handle the full integration layer, not just prototype use cases.
What if a provider I need is not supported yet?
The project is open source. You can check the current provider list in the GitHub repo, open an issue to request a new integration, or contribute one. The architecture is designed to make adding providers consistent.
Never miss an update. Join our community. No spam ever.