Skip to content
CARP Docs
Ask AISystemLightDark
On this page

Workouts

Write exercise sessions with an activity type, energy burned and distance using writeWorkoutData.

Copy MarkdownOpen inOpen in GitHubView as MarkdownOpen in Scira AIOpen in ChatGPTOpen in ClaudeOpen in Cursor

writeWorkoutData writes an exercise session with its activity type, time range and optional energy and distance totals. To read workouts back, see Aggregate data.

Signature

Future<bool> writeWorkoutData({
  required HealthWorkoutActivityType activityType,
  required DateTime start,
  required DateTime end,
  double? totalEnergyBurned,
  int? totalEnergyBurnedUnit,
  double? totalDistance,
  int? totalDistanceUnit,
})
ParameterTypeRequiredDescription
activityTypeHealthWorkoutActivityTypeYesType of workout activity
startDateTimeYesWorkout start time
endDateTimeYesWorkout end time
totalEnergyBurneddoubleNoCalories burned
totalEnergyBurnedUnitintNoEnergy unit (default: kilocalories)
totalDistancedoubleNoDistance covered
totalDistanceUnitintNoDistance unit (default: meters)

Return value

  • true: the workout was saved.
  • false: the write failed.

Examples by activity

Running

await health.writeWorkoutData(
  activityType: HealthWorkoutActivityType.RUNNING,
  start: workoutStart,
  end: workoutEnd,
  totalDistance: 5000.0, // 5 km in meters
  totalEnergyBurned: 350.0, // kcal
);

Cycling

await health.writeWorkoutData(
  activityType: HealthWorkoutActivityType.CYCLING,
  start: DateTime.now().subtract(Duration(hours: 1)),
  end: DateTime.now(),
  totalDistance: 15000.0, // 15 km
  totalEnergyBurned: 400.0,
);

Swimming

await health.writeWorkoutData(
  activityType: HealthWorkoutActivityType.SWIMMING_OPEN_WATER,
  start: workoutStart,
  end: workoutEnd,
  totalDistance: 1500.0, // 1.5 km
  totalEnergyBurned: 300.0,
);

Strength training

await health.writeWorkoutData(
  activityType: HealthWorkoutActivityType.TRADITIONAL_STRENGTH_TRAINING,
  start: workoutStart,
  end: workoutEnd,
  totalEnergyBurned: 200.0,
  // No distance for strength training
);

Yoga

await health.writeWorkoutData(
  activityType: HealthWorkoutActivityType.YOGA,
  start: DateTime.now().subtract(Duration(minutes: 60)),
  end: DateTime.now(),
  totalEnergyBurned: 150.0,
);

Activity types

Common HealthWorkoutActivityType values include:

WALKING, RUNNING, CYCLING, SWIMMING_OPEN_WATER, SWIMMING_POOL, HIKING, YOGA, TRADITIONAL_STRENGTH_TRAINING, FUNCTIONAL_STRENGTH_TRAINING, HIGH_INTENSITY_INTERVAL_TRAINING, DANCING, ELLIPTICAL, STAIR_CLIMBING, ROWING, SOCCER, BASKETBALL, TENNIS, GOLF, SKIING.

Many more are available. For the full list, see the HealthWorkoutActivityType enum in the API reference.

Warning

Activity types are platform-specific. The plugin validates the activity type and throws if it is not supported on the current platform.

Track a workout session

This class records the start time, then writes the workout when it finishes:

class WorkoutSession {
  final HealthWorkoutActivityType type;
  final DateTime startTime;
  DateTime? endTime;
  double distance = 0.0;
  double calories = 0.0;
  
  WorkoutSession({
    required this.type,
    DateTime? start,
  }) : startTime = start ?? DateTime.now();
  
  void finish({double? distance, double? calories}) {
    endTime = DateTime.now();
    this.distance = distance ?? 0.0;
    this.calories = calories ?? 0.0;
  }
  
  Future<bool> save(Health health) async {
    if (endTime == null) {
      throw StateError('Workout not finished');
    }
    
    return await health.writeWorkoutData(
      activityType: type,
      start: startTime,
      end: endTime!,
      totalDistance: distance,
      totalEnergyBurned: calories,
    );
  }
}

// Usage
final workout = WorkoutSession(
  type: HealthWorkoutActivityType.RUNNING,
);

// ... workout in progress ...

workout.finish(distance: 5000.0, calories: 350.0);
final saved = await workout.save(health);

if (saved) {
  print('Workout saved!');
}

Accumulate metrics during the workout

class LiveWorkoutTracker {
  final Health health;
  final HealthWorkoutActivityType type;
  late DateTime startTime;
  double totalDistance = 0.0;
  double totalCalories = 0.0;
  
  LiveWorkoutTracker({
    required this.health,
    required this.type,
  });
  
  void start() {
    startTime = DateTime.now();
    print('Workout started: ${type.name}');
  }
  
  void updateMetrics(double distance, double calories) {
    totalDistance += distance;
    totalCalories += calories;
    print('Distance: ${totalDistance}m, Calories: ${totalCalories}');
  }
  
  Future<bool> finish() async {
    final endTime = DateTime.now();
    final duration = endTime.difference(startTime);
    
    print('Workout finished: ${duration.inMinutes} minutes');
    
    return await health.writeWorkoutData(
      activityType: type,
      start: startTime,
      end: endTime,
      totalDistance: totalDistance,
      totalEnergyBurned: totalCalories,
    );
  }
}

// Usage
final tracker = LiveWorkoutTracker(
  health: health,
  type: HealthWorkoutActivityType.RUNNING,
);

tracker.start();

// During workout
tracker.updateMetrics(500.0, 35.0); // Every 500m
tracker.updateMetrics(500.0, 35.0);
// ...

final saved = await tracker.finish();

Estimate calories

If energy burned was not measured, you can estimate it from MET (Metabolic Equivalent of Task) values:

double estimateCalories({
  required HealthWorkoutActivityType type,
  required Duration duration,
  required double weightKg,
}) {
  // MET values (Metabolic Equivalent of Task)
  final metValues = {
    HealthWorkoutActivityType.WALKING: 3.5,
    HealthWorkoutActivityType.RUNNING: 9.8,
    HealthWorkoutActivityType.CYCLING: 7.5,
    HealthWorkoutActivityType.SWIMMING_OPEN_WATER: 8.0,
    HealthWorkoutActivityType.YOGA: 2.5,
    // Add more as needed
  };
  
  final met = metValues[type] ?? 5.0; // Default to moderate intensity
  final hours = duration.inMinutes / 60.0;
  
  // Calories = MET × weight (kg) × duration (hours)
  return met * weightKg * hours;
}

// Usage
final duration = workoutEnd.difference(workoutStart);
final estimatedCalories = estimateCalories(
  type: HealthWorkoutActivityType.RUNNING,
  duration: duration,
  weightKg: 70.0,
);

await health.writeWorkoutData(
  activityType: HealthWorkoutActivityType.RUNNING,
  start: workoutStart,
  end: workoutEnd,
  totalDistance: 5000.0,
  totalEnergyBurned: estimatedCalories,
);

Write multi-segment workouts

For workouts with distinct phases, write one workout per segment:

Future<void> saveMultiSegmentWorkout() async {
  final workoutStart = DateTime.now().subtract(Duration(hours: 1));
  
  // Warm-up: 10 minutes walking
  await health.writeWorkoutData(
    activityType: HealthWorkoutActivityType.WALKING,
    start: workoutStart,
    end: workoutStart.add(Duration(minutes: 10)),
    totalDistance: 800.0,
    totalEnergyBurned: 40.0,
  );
  
  // Main workout: 30 minutes running
  await health.writeWorkoutData(
    activityType: HealthWorkoutActivityType.RUNNING,
    start: workoutStart.add(Duration(minutes: 10)),
    end: workoutStart.add(Duration(minutes: 40)),
    totalDistance: 5000.0,
    totalEnergyBurned: 300.0,
  );
  
  // Cool-down: 10 minutes walking
  await health.writeWorkoutData(
    activityType: HealthWorkoutActivityType.WALKING,
    start: workoutStart.add(Duration(minutes: 40)),
    end: workoutStart.add(Duration(minutes: 50)),
    totalDistance: 600.0,
    totalEnergyBurned: 30.0,
  );
}

Validate before writing

Future<bool> writeValidatedWorkout({
  required HealthWorkoutActivityType type,
  required DateTime start,
  required DateTime end,
  double? distance,
  double? calories,
}) async {
  // Validate duration
  final duration = end.difference(start);
  if (duration.isNegative || duration.inSeconds < 60) {
    print('Invalid workout duration');
    return false;
  }
  
  // Validate distance
  if (distance != null && distance < 0) {
    print('Invalid distance');
    return false;
  }
  
  // Validate calories
  if (calories != null && (calories < 0 || calories > 10000)) {
    print('Invalid calorie value');
    return false;
  }
  
  return await health.writeWorkoutData(
    activityType: type,
    start: start,
    end: end,
    totalDistance: distance,
    totalEnergyBurned: calories,
  );
}

Platform differences

AndroidiOS
  • Activity types are mapped to Health Connect exercise types.
  • Some iOS-specific types may not have an exact Android equivalent.
  • Requires the Health Connect SDK.
  • Other apps may not display all workout details.
  • Supports all HealthWorkoutActivityType values.
  • Workouts appear in the Apple Fitness app.
  • Can include route data (requires a separate API).
  • Heart rate is associated automatically if available.

Quick links

Page · DocumentationCARP DocumentationPage · DocumentationIntroductionPage · DocumentationQuickstartPage · DocumentationTerminologyPage · DocumentationArchitecture