Health Sync Overview & Best Practices

b.well Health SDK for Android

Health Sync Overview

Overview

Health Sync lets your app read health data stored locally on the user's phone (via Android Health Connect) and upload it to b.well for processing. It is a separate integration path from Cloud Provider connections — the two solve different problems and are not interchangeable. This page groups every method you need for each path, plus how they fit together.

Cloud Providers vs. Native On-Device Sync

  • Cloud Providers: connects a cloud-hosted provider account (e.g. a fitness platform's web API) via a browser-based OAuth flow. b.well pulls data directly from that provider's servers — no on-device SDK is involved.
  • Native On-Device Sync: connects to health data stored locally on the user's phone. Your app must call sync periodically (or in response to a trigger) to push data from the phone to b.well — there is no server-to-server pull. Data from a wearable only reaches this path indirectly, if the wearable's own app already writes it into Android Health Connect.

Use Cloud Providers when the data lives with a third-party provider's servers. Use Health Sync when the data lives on the phone itself.

1. Reading Health Data

Regardless of which path below populated the data, reading it back always goes through HealthDataManager (BWellSdk.health):

2. Syncing with Cloud Providers

  • Get Device Providers — discover which providers are currently available to connect and their slug values. This list is dynamic (backend-driven) — there is no fixed set of provider names; always fetch it live rather than hardcoding one.
  • Retrieve an Oauth URL — start the OAuth flow for a provider slug from the list above.
  • Disconnect (deleteConnection) — remove an existing cloud provider connection.

Don't confuse this with the Native On-Device Sync disconnect below. They're two unrelated methods: deleteConnection removes a Cloud Provider's OAuth connection; BWellSdk.healthSync.disconnect() (section 3) ends an on-device sync session. Calling one does not affect the other.

3. Syncing with Android Health Connect (Native On-Device Sync)

These 4 methods compose the native on-device path. All 4 live on BWellSdk.healthSync:

  • ConnectBWellSdk.healthSync.connect(). Provisions backend credentials for the on-device adapter and starts its sync session.
  • Request PermissionsBWellSdk.healthSync.requestPermissions(types). Requests OS-level authorization for the health data types you need.
  • SyncBWellSdk.healthSync.sync(types, window). Reads data from the phone; with the registered on-device adapter, that read is what feeds data into b.well as a side effect. To see the data afterward, use the methods in Reading Health Data above — sync does not return records itself. See the Sync page for foreground and permission-related limitations.
  • DisconnectBWellSdk.healthSync.disconnect(). Ends the session and removes the connection.

sourceId is technically a parameter on all 4 methods, but omit it — there's currently only one supported on-device adapter, auto-selected when not specified.

Switching accounts on the same device: call disconnect for the current user before calling connect for a new one. Calling connect while a different user's session is still active fails with a session-conflict error rather than silently overwriting it — see Session Conflict Handling below.

Configure the on-device adapter once, at app startup, before calling any of the 4 methods above. The exact adapter class comes from whichever on-device health source package you add — per the ports & adapters design, the SDK's public methods behave identically regardless of which adapter is registered:

BWellHealthSync.configure(
    YourOnDeviceHealthSource(applicationContext) { types ->
        // Launch the OS permission dialog for `types` and return the results
    }
)

Session Conflict Handling

Only one on-device sync session can be active per user per device at a time.

var connectResult = BWellSdk.healthSync.connect()
if (!connectResult.success() && /* result indicates a session conflict */) {
    BWellSdk.healthSync.disconnect()
    connectResult = BWellSdk.healthSync.connect()
}

Async Data Ingestion

sync returns per-type record counts, not the records themselves — reading a type is what feeds it into b.well's pipeline, but processing on b.well's side happens asynchronously after that. Don't assume data is immediately readable right after sync returns; poll Retrieve Device Metrics Groups after a short delay, or on your app's next natural data-refresh point, to confirm the data was processed.

Best Practices

  • Call configure exactly once per app process, before any other Health Sync method.
  • Request only the health data types your app actually uses.
  • Always disconnect before connecting a different user or source on the same device.
  • Treat sync's return value as a record-count receipt, not as the synced data itself.
  • Call sync while your app is in the foreground — see Sync for why.
  • A FAILED count from sync usually means a missing permission for that type, not a real error.
  • Fetch getDeviceProviders() live rather than hardcoding provider slugs — availability changes per org.

Did this page help you?