Understanding the technical difference between platform APIs (HealthKit, Health Connect) and direct device OAuth is critical for choosing the right health data aggregation strategy.
The Core Question
Do you integrate with platform APIs that unify device data (HealthKit on iOS, Health Connect on Android)? Or do you build direct OAuth connections to each device manufacturer (Fitbit, Garmin, Oura, etc.)?
This decision impacts coverage, implementation complexity, data precision, and long-term maintenance burden.
The Two Approaches Explained
📱 Platform API Approach
What it is: Use Apple HealthKit (iOS) and Google Health Connect (Android) as unified data sources
Data flow:
- Wearables sync to HealthKit/Health Connect
- Your app requests permission once
- Data flows from platform API to your app
- No direct device authentication needed
Supported by: Sahha, Rook, some Terra implementations
🔗 Direct OAuth Approach
What it is: Build individual OAuth integrations with each device manufacturer
Data flow:
- User authenticates with Fitbit, Garmin, Oura, etc.
- Your app stores OAuth tokens per device
- Poll each manufacturer API separately
- Manage token refresh for each connection
Supported by: Terra (300+ devices), custom implementations
Technical Comparison
Factor | Platform API (HealthKit/Health Connect) | Direct OAuth (Device-by-device) |
---|---|---|
Implementation Complexity | Low - 2 platform SDKs (iOS + Android) | Very High - 300+ device-specific APIs |
User Coverage (iOS) | ~70% (any device syncing to HealthKit) | ~30% (only supported devices) |
User Coverage (Android) | ~50% (Health Connect adoption growing) | ~30% (only supported devices) |
Onboarding Friction | 1 permission prompt | Device selection + OAuth flow per device |
Token Management | Platform handles refresh | Manual refresh per device (hourly/daily) |
Data Latency | Hours (device → platform → app) | Minutes (device → API → app) |
Data Precision | Platform-normalized (some loss) | Device-native (full fidelity) |
Maintenance Burden | Low - Platform updates handled by OS | High - Track 300+ API changes |
Device Support | Automatic (any HealthKit/Health Connect device) | Manual (build each integration separately) |
Smartphone Data | ✓ Built-in (accelerometer, etc.) | ✗ Not available |
Code Examples: Implementation Complexity
Platform API Approach (HealthKit - iOS)
import HealthKit
let healthStore = HKHealthStore()
let typesToRead: Set
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.categoryType(forIdentifier: .sleepAnalysis)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!
]
healthStore.requestAuthorization(toShare: nil, read: typesToRead) { success, error in
// Access granted - data flows automatically
}
Step 2: Query data (universal for all devices)
let stepType = HKQuantityType.quantityType(forIdentifier: .stepCount)!
let query = HKStatisticsQuery(quantityType: stepType, ...) { _, result, _ in
let steps = result?.sumQuantity()?.doubleValue(for: .count())
// Works for Apple Watch, Fitbit, Garmin, etc. - all via HealthKit
}
healthStore.execute(query)
Total implementation: ~200 lines of code for full HealthKit integration
Direct OAuth Approach (Fitbit + Garmin + Oura)
// Redirect to Fitbit OAuth
const fitbitAuthUrl = `https://www.fitbit.com/oauth2/authorize?
client_id=${FITBIT_CLIENT_ID}&
response_type=code&
scope=activity heartrate sleep`
// Handle callback, exchange code for token
const tokenResponse = await fetch('https://api.fitbit.com/oauth2/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `grant_type=authorization_code&code=${code}&...`
})
// Store access_token + refresh_token
// Set up refresh logic (expires every 8 hours)
Step 2: Query Fitbit API
const steps = await fetch('https://api.fitbit.com/1/user/-/activities/steps/date/today/1d.json', {
headers: { 'Authorization': `Bearer ${fitbitToken}` }
})
Step 3: Repeat for Garmin (different OAuth, different API)
// Garmin uses OAuth 1.0a (different flow!)
const garminAuthUrl = `https://connect.garmin.com/oauthConfirm?
oauth_token=${requestToken}`
// ... completely different implementation
Step 4: Repeat for Oura (different OAuth, different API)
const ouraAuthUrl = `https://cloud.ouraring.com/oauth/authorize?
client_id=${OURA_CLIENT_ID}&response_type=code`
// ... yet another different implementation
Step 5: Build token refresh scheduler for all devices
Step 6: Handle device-specific errors and rate limits
Step 7: Normalize data formats across 300+ devices
Total implementation: ~10,000+ lines of code for 300+ device integrations
Implementation Time Comparison
- Platform API (HealthKit + Health Connect): 1-2 weeks for both platforms
- Direct OAuth (10 major devices): 2-3 months
- Direct OAuth (300+ devices like Terra): 12-18 months + ongoing maintenance
This is why platforms like Terra exist - they've already built the 300+ integrations so you don't have to.
Token Management: The Hidden Complexity
Platform API: Zero Token Management
- ✅ User grants permission once
- ✅ Platform handles authentication
- ✅ No token expiration to manage
- ✅ No refresh logic needed
- ✅ Works offline (local device data)
Direct OAuth: Complex Token Lifecycle
Device | Token Expiry | Refresh Strategy | Edge Cases |
---|---|---|---|
Fitbit | 8 hours | Refresh token (expires in 60 days) | User must re-auth if 60 days pass |
Garmin | 1 year | OAuth 1.0a (no refresh, manual re-auth) | Annual re-authentication required |
Oura | 24 hours | Refresh token (no expiry) | Refresh daily or lose access |
Whoop | 1 hour | Refresh token (expires in 30 days) | Hourly refresh or 30-day re-auth |
Polar | 10 days | No refresh token (re-auth every 10 days) | User interruption every 10 days |
With 300 devices, you're managing 300 different token lifecycles.
The Token Refresh Problem at Scale
If you have 10,000 users with 3 devices each (30,000 connections):
- Fitbit: 30,000 tokens × 3 refreshes/day = 90,000 refresh operations/day
- Oura: 30,000 tokens × 1 refresh/day = 30,000 refresh operations/day
- Whoop: 30,000 tokens × 24 refreshes/day = 720,000 refresh operations/day
Total: ~850,000 token operations per day just to maintain connections. Platform APIs eliminate this entirely.
Data Flow: Latency vs Coverage Trade-off
Platform API Flow (HealthKit Example)
- Device sync: Apple Watch syncs to iPhone HealthKit (real-time when nearby, hourly when apart)
- Platform storage: HealthKit stores data locally on device
- App query: Your app queries HealthKit (instant, local access)
- Total latency: 1-60 minutes (depends on device sync)
Coverage: Any device that syncs to HealthKit (Apple Watch, Fitbit, Garmin, Oura, 100+ devices) ✅
Direct OAuth Flow (Fitbit Example)
- Device sync: Fitbit syncs to Fitbit cloud (every 15 minutes when connected)
- API polling: Your app polls Fitbit API (rate limit: 150 req/hour)
- Data transfer: Fitbit API returns data via REST
- Total latency: 15-30 minutes (depends on sync + poll frequency)
Coverage: Only Fitbit devices (must build separate integrations for Garmin, Oura, etc.) ❌
Latency Misconception
Many assume direct OAuth is "faster" because you're closer to the device API. In practice:
- Platform API: 1-60 min latency, but 100% coverage (all synced devices)
- Direct OAuth: 15-30 min latency, but ~5% coverage per device (must build each integration)
The coverage penalty far outweighs the latency benefit for most use cases.
When to Use Each Approach
✅ Use Platform API (HealthKit/Health Connect) When:
Consumer Apps
- Need broad device coverage (any brand)
- Want low onboarding friction
- Prefer simple implementation
- Can tolerate 1-hour data latency
Examples: Fitness apps, habit trackers, mental health apps
Enterprise Programs
- Insurance wellness programs
- Corporate health initiatives
- Research studies (observational)
- Population health monitoring
Why: 70% user coverage vs 30% with device-specific integrations
⚠️ Use Direct OAuth When:
Device-Specific Features
- Need proprietary metrics (Whoop recovery score, Oura readiness)
- Require real-time data (<5 min latency)
- Access device-native analytics
- Support specific device brands only
Examples: Whoop coaching platform, Oura analytics tools
Clinical Trials
- Controlled device list (all participants use same device)
- Need device-native precision (no platform normalization)
- Require audit trails per device
- Compliance mandates specific devices
Why: Clinical trials control the device, so coverage isn't a concern
The Hybrid Approach (Recommended)
Sahha and Rook support both strategies:
- Primary: Platform APIs (HealthKit/Health Connect) for 70% coverage
- Fallback: Direct OAuth for device-specific features (Whoop, Oura proprietary scores)
- Smartphone: Built-in sensors for 100% coverage (no wearable required)
This maximizes coverage while still allowing access to proprietary device features when needed.
Platform Support Comparison
Platform | Platform API Support | Direct OAuth Support | Smartphone Sensors | Best For |
---|---|---|---|---|
Sahha | ✓ HealthKit + Health Connect | Limited (major devices) | ✓ Full support | Consumer apps, insurance, 100% coverage strategy |
Rook | ✓ HealthKit + Health Connect | ✓ Select devices | ~ Limited | Platform-first with selective OAuth |
Terra | ✓ Optional (via HealthKit/Health Connect) | ✓ 300+ devices (primary) | ✗ None | Device breadth, enthusiast apps, device-specific features |
Spike | ✗ None | ✓ Medical devices only | ✗ None | Clinical trials, medical equipment integration |
Implementation Checklist
For Platform API Implementation:
- ✅ Add HealthKit capability to iOS app (Xcode)
- ✅ Add Health Connect dependency to Android app (Gradle)
- ✅ Request user permissions (one-time prompt)
- ✅ Query data types needed (steps, sleep, heart rate, etc.)
- ✅ Handle background updates (optional for real-time)
- ✅ Test with various devices syncing to platform
Estimated time: 1-2 weeks for both platforms
For Direct OAuth Implementation:
- ✅ Register developer accounts (Fitbit, Garmin, Oura, Whoop, etc.)
- ✅ Build OAuth flows for each device (different per manufacturer)
- ✅ Implement token storage and refresh logic
- ✅ Build API clients for each device (different endpoints, formats)
- ✅ Normalize data formats across devices
- ✅ Handle rate limits, errors, edge cases per device
- ✅ Monitor token expiry and trigger re-auth flows
- ✅ Test with physical devices for each brand
Estimated time: 2-3 months for 10 devices, 12-18 months for 300+ devices
Why Use an Aggregator?
Platforms like Sahha, Terra, and Rook have already built these integrations. By using an aggregator:
- Save 12-18 months of development time
- Avoid token management complexity (handled by aggregator)
- Get automatic updates when device APIs change
- Access unified data format regardless of source
Cost: ~$50-500/month vs $400k-1.6M to build in-house
Decision Framework
Your Use Case | Recommended Approach | Why |
---|---|---|
Consumer fitness app | Platform API (HealthKit/Health Connect) | Broad coverage, low friction, simple implementation |
Insurance wellness program | Platform API + Smartphone | 70-100% member coverage (vs 30% wearable-only) |
Mental health platform | Smartphone + Platform API | Behavioral data from smartphone, activity from platform |
Device-specific app (Whoop/Oura only) | Direct OAuth (single device) | Access proprietary metrics, controlled device list |
Clinical trial (controlled devices) | Direct OAuth or Spike | Device-native precision, audit trails, compliance |
Multi-device aggregator (like Terra) | Hybrid: Platform API + Direct OAuth | Maximum coverage + device-specific features |
Next Steps
- 📱 Smartphone vs Wearable Data - Coverage vs precision trade-off
- 🎯 Choosing a Health Data API - Platform selection guide
- 🔧 Integration Best Practices - Implementation tips
- 📖 Integration Approaches - Comprehensive decision framework