DEV Community

Amr
Amr

Posted on

3 3 2 2

Automatically Map Workouts to the Right Apple HealthKit Type -HKWorkoutActivityType

Introduction

If you've ever tried integrating Apple HealthKit into your fitness app, you've probably faced this frustrating step:

"Which HKWorkoutActivityType should I use for this workout?"

Choosing the wrong type means poor sensor activation (or none), inaccurate data, and a worse user experience. Apps get bad reviews because of this β€” especially if the user just paid $400 for their new Apple Watch.

In this tutorial, I'll walk you through how to automatically classify any workout to its correct HKWorkoutActivityType using Fit2Apple.

Fit2Apple is an API that uses a research-backed 4-stage pipeline to classify and score workouts based on exercise names, sets, durations, rest, and intensity. Whether you're using standard workouts or custom routines from your app, this saves you hours of guesswork and gives your users better Apple Watch tracking instantly.


πŸ› οΈ What You'll Build

By the end of this tutorial, you'll:

  • βœ… Send a workout to the Fit2Apple API
  • βœ… Receive the best-matched HealthKit activity type (e.g. .functionalStrengthTraining)
  • βœ… Use that value to correctly start an HKWorkoutSession in your app

πŸš€ Step 1: Sign Up and Get Your API Key

Head to Fit2Apple on RapidAPI and subscribe to the free plan.

You’ll get an API key to use in the request headers.


πŸ“¦ Step 2: Build Your Workout Object

Here's an example of a typical workout JSON:

{
  "workout": {
    "exercises": [
      {
        "name": "Push Up",
        "reps": 15,
        "sets": 3,
        "restBetweenSets": 30
      },
      {
        "name": "Squat Jumps",
        "duration": 45,
        "sets": 2,
        "restBetweenSets": 60
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

The more precise your data (reps, sets, rest, etc.), the more accurate the classification.


πŸ”Œ Step 3: Send a POST Request

Using JavaScript (Fetch)

const url = 'https://fit2apple.p.rapidapi.com/api/workout/rapid';
const options = {
  method: 'POST',
  headers: {
    'x-rapidapi-key': 'your key',
    'x-rapidapi-host': 'fit2apple.p.rapidapi.com',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    workout: {
      exercises: [
        {
          name: 'Push Up',
          duration: 30,
          sets: 3,
          restBetweenSets: [10, 10]
        },
        {
          name: 'Pull Up',
          reps: 12,
          sets: 3,
          restBetweenSets: [15, 15]
        },
        {
          name: 'Mountain Climbers',
          duration: 45
        },
        {
          name: 'Hip Flexor Stretch',
          duration: 60,
          sets: 2,
          restBetweenSets: [30]
        }
      ],
      restIntervals: [30, 30, 20],
      rounds: 2,
      restBetweenRounds: 50
    }
  })
};

try {
  const response = await fetch(url, options);
  const result = await response.json();
  console.log(result);
} catch (error) {
  console.error(error);
}
Enter fullscreen mode Exit fullscreen mode

Using Swift

import Foundation

let headers = [
  "x-rapidapi-key": "your keys",
  "x-rapidapi-host": "fit2apple.p.rapidapi.com",
  "Content-Type": "application/json"
]

let parameters = [
  "workout": [
    "exercises": [
      [
        "name": "Push Up",
        "duration": 30,
        "sets": 3,
        "restBetweenSets": [10, 10]
      ],
      [
        "name": "Pull Up",
        "reps": 12,
        "sets": 3,
        "restBetweenSets": [15, 15]
      ],
      [
        "name": "Mountain Climbers",
        "duration": 45
      ],
      [
        "name": "Hip Flexor Stretch",
        "duration": 60,
        "sets": 2,
        "restBetweenSets": [30]
      ]
    ],
    "restIntervals": [30, 30, 20],
    "rounds": 2,
    "restBetweenRounds": 50
  ]
] as [String : Any]

let postData = try! JSONSerialization.data(withJSONObject: parameters, options: [])

var request = URLRequest(url: URL(string: "https://fit2apple.p.rapidapi.com/api/workout/rapid")!)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData

let session = URLSession.shared
let task = session.dataTask(with: request) { data, response, error in
  if let error = error {
    print(error)
  } else {
    print(response as? HTTPURLResponse ?? "No response")
  }
}

task.resume()
Enter fullscreen mode Exit fullscreen mode

πŸ“ˆ Step 4: Use the Result

You’ll get a response like this:

{
  "workoutType": "functionalStrengthTraining",
  "info": {
    "isIntervalBased": true,
    "avgRest": 45,
    "intervalWorkToRestRatio": 1.2,
    "related": ["traditionalStrengthTraining", "coreTraining"]
  }
}
Enter fullscreen mode Exit fullscreen mode

Use workoutType when initializing the workout session in your Apple Watch app.

You can find full API documentation, request/response structure, and limits on RapidAPI Docs.


✨ Why It Matters

  • πŸ’‘ Sensor Accuracy: Apple Watch sensors activate based on the workout type getting this wrong means lost data.
  • ⚑ Developer Simplicity: No need to maintain mapping logic. Focus on building great workouts, not classifications.
  • πŸ“Š Future-Proof: Our dataset and pipeline (classification, calculation, matching, scoring) improve over time β€” automatically.

Dynatrace image

Frictionless debugging for developers

Debugging in production doesn't have to be a nightmare.

Dynatrace reimagines the developer experience with runtime debugging, native OpenTelemetry support, and IDE integration allowing developers to stay in the flow and focus on building instead of fixing.

Learn more

Top comments (0)