Apple HealthKit Backfill

Data is stored exclusively on the device (iPhone). Backfilling is possible from the moment application user grants permissions and is limited by:
  • What data the user has on their device
  • What permissions your app has been granted (read access for specific data types)
  • User’s health app settings or deletions
  • Your retention policy settings

Manual Data Extraction Required

Because Apple doesn’t offer any other communication except HealthKit framework, you must query needed data manually in order to backfill. Before data is extracted it won’t be available to your backend over API calls. Enabling background data delivery also won’t perform the backfill as it’s designed for new data events.

Implementation

To implement backfill functionality, query historical data using the SDK’s statistics methods for your desired date range:
import SpikeSDK

// Example: Backfill last 7 days of steps data
let calendar = Calendar.current
let today = Date()

for dayOffset in 0..<7 {
    guard let startDate = calendar.date(byAdding: .day, value: -dayOffset, to: today) else { continue }
    guard let endDate = calendar.date(byAdding: .day, value: 1, to: startDate) else { continue }
    
    do {
        let statistics = try await spikeConnection.getStatistics(
            ofTypes: [.steps],
            from: startDate,
            to: endDate,
            interval: .day,
            filter: StatisticsFilter(providers: [.apple])
        )
        
        // Process the statistics data
        for statistic in statistics {
            print("Steps for \(statistic.start): \(statistic.value)")
        }
    } catch {
        // Handle specific error types for better user experience
        if let hkError = error as? HKError {
            switch hkError.code {
            case .errorAuthorizationNotDetermined:
                print("Authorization not determined. Request permissions first.")
            case .errorAuthorizationDenied:
                print("Access denied. Guide user to Health app settings.")
            default:
                print("HealthKit error: \(hkError.localizedDescription)")
            }
        } else {
            print("Error fetching statistics for \(startDate): \(error.localizedDescription)")
        }
    }
}

Best Practices

Performance and User Experience

  • Keep the backfill process asynchronous for the best user experience
  • Segment requests into smaller date ranges to ensure optimal performance
  • Implement rate limiting to avoid overwhelming the HealthKit store
  • Consider implementing a progress indicator for longer backfill operations

Privacy and Security

  • Handle permissions gracefully - users may grant partial access
  • Consider allowing users to control the backfill scope (date range, data types)

Error Handling

  • Implement robust error handling for authorization failures
  • Gracefully handle scenarios where data is unavailable or incomplete
  • Provide meaningful feedback to users about data access issues
  • Guide users to Health app settings when permissions are denied

Data Management

  • Avoid storing HealthKit data outside the HealthKit store unless necessary
  • If external storage is required, ensure data is encrypted and secure
  • Validate data before processing to ensure accuracy and consistency
  • Respect user’s ability to revoke permissions at any time