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.

AWS Q Developer image

Build your favorite retro game with Amazon Q Developer CLI in the Challenge & win a T-shirt!

Feeling nostalgic? Build Games Challenge is your chance to recreate your favorite retro arcade style game using Amazon Q Developer’s agentic coding experience in the command line interface, Q Developer CLI.

Participate Now

Top comments (0)

👋 Kindness is contagious

Discover fresh viewpoints in this insightful post, supported by our vibrant DEV Community. Every developer’s experience matters—add your thoughts and help us grow together.

A simple “thank you” can uplift the author and spark new discussions—leave yours below!

On DEV, knowledge-sharing connects us and drives innovation. Found this useful? A quick note of appreciation makes a real impact.

Okay