Migrating from ExerciseDB to WorkoutX:
Complete Guide with Code Examples
ExerciseDB free tier limits hit? Tired of routing through RapidAPI? This guide walks you through migrating to WorkoutX in under 30 minutes — full endpoint mapping, auth changes, and drop-in code replacements.
verified Published by the WorkoutX team — builders of the exercise API used by fitness app developers. Learn more
Migrating from ExerciseDB to WorkoutX takes about 20-30 minutes: swap the RapidAPI headers for a single X-WorkoutX-Key, remap endpoint paths (e.g. /exercises/bodyPart/{bodyPart} → /v2/exercises?bodyPart={bodyPart}), replace gifUrl images with the media.mp4 video, and adjust for minor JSON field-casing differences. WorkoutX's free tier (500 requests in total) requires no credit card, so you can test the migration before switching production traffic.
Why Developers Are Leaving ExerciseDB
ExerciseDB has been the default exercise API recommendation since 2021 — it's mentioned in hundreds of YouTube tutorials and GitHub repos. But as apps grow, developers consistently run into the same problems:
- RapidAPI dependency: Every request routes through RapidAPI's infrastructure, adding latency and an extra failure point
- Rate limit surprises: The free tier limits (10 req/min) are hit fast in any real app
- Pricing opacity: RapidAPI pricing changes without notice, and costs scale unpredictably
- Missing data fields: No calorie burn data, no difficulty levels, no exercise mechanics — data most fitness apps actually need (e.g., knowing a barbell bent-over row is intermediate difficulty and a compound pull)
- No developer portal: You manage billing through RapidAPI, not through the API provider directly
Good news: WorkoutX is a direct replacement. The exercise data structure is similar, every ExerciseDB endpoint has a WorkoutX equivalent, and the migration takes about 20–30 minutes including testing.
Endpoint Mapping
Here's every ExerciseDB endpoint and its WorkoutX v2 equivalent. ExerciseDB's path-style filters become query parameters, and you can combine them in one request:
WorkoutX also adds things ExerciseDB doesn't have:
GET /v2/exercises?target=Glutes&equipment=Dumbbell&difficulty=beginner— combine any filters (alsocategory,mechanic,force,muscle,model) in one requestGET /v2/exercises/{id}/media— fresh MP4 and poster links for one exerciseGET /v2/exercises/{id}/similarand/alternatives— ranked substitutes, including "same muscle, different equipment"GET /v2/exercises/{id}/calories?weightKg=80&minutes=15— calorie estimate for a body weight and durationGET /v2/categoriesandGET /v2/muscles— the remaining filter values, with exercise counts?model=femaleandcounterpartId— 843 exercises come with both a male and a female model?lang=— names, instructions and tips in Turkish, German, Spanish, French and Chinese (filters stay in English)
Exercise ids are different too: WorkoutX uses ids like ex_SAWOOH. If your app stores ExerciseDB ids in workouts or favorites, look each exercise up once (for example with ?name=) and save the WorkoutX id.
Authentication Change
ExerciseDB requires two RapidAPI headers. WorkoutX uses a single header with your API key (v2 rejects a key in the URL, such as ?api-key=, with a 400):
X-RapidAPI-Key: YOUR_RAPIDAPI_KEY
X-RapidAPI-Host: exercisedb.p.rapidapi.com
X-WorkoutX-Key: YOUR_WORKOUTX_KEY
Get your free WorkoutX API key at workoutxapp.com — no credit card required, 500 free requests.
Base URL Change
https://exercisedb.p.rapidapi.com
https://api.workoutxapp.com/v2
JavaScript Migration
If you're using the ExerciseDB fetch pattern, here's the before/after:
const response = await fetch(
'https://exercisedb.p.rapidapi.com/exercises/bodyPart/chest?limit=10',
{
headers: {
'X-RapidAPI-Key': 'YOUR_RAPIDAPI_KEY',
'X-RapidAPI-Host': 'exercisedb.p.rapidapi.com',
},
}
);
const exercises = await response.json();
const response = await fetch(
'https://api.workoutxapp.com/v2/exercises?bodyPart=chest&limit=10',
{
headers: {
'X-WorkoutX-Key': 'YOUR_WORKOUTX_KEY',
},
}
);
const { results: exercises } = await response.json();
// WorkoutX wraps results in { total, limit, offset, results: [...] }
Note on response shape: WorkoutX wraps paginated results in { total, limit, offset, results: [...] }. ExerciseDB returns a bare array. Update any code that does response.json() directly to response.json().then(r => r.results) for list endpoints. limit is capped at 10 on the Free plan, 100 on Starter and 200 on other plans.
Response Shape Comparison
Here's a side-by-side comparison using the barbell bench press as an example exercise:
{
"id": "0001",
"name": "Barbell Bench Press",
"bodyPart": "chest",
"target": "pectorals",
"equipment": "barbell",
"gifUrl": "https://v2.exercisedb.io/image/...",
"instructions": ["Step 1...", "Step 2..."],
"secondaryMuscles": ["triceps", "shoulders"]
}
{
"id": "ex_SAWOOH",
"name": "Barbell Bench Press",
"bodyPart": "Chest",
"target": "Pectorals",
"equipment": "Barbell",
"instructions": ["Step 1...", "Step 2..."],
"secondaryMuscles": [
{ "group": "Shoulders", "anatomical": ["Deltoids"] },
{ "group": "Triceps", "anatomical": ["Triceps Brachii"] }
],
"media": {
"expiresAt": "...",
"mediaVersion": 1,
"watermarked": false,
"mp4": "https://…/m/v1/ex_SAWOOH/mp4-720.mp4?...",
"poster": "https://…/m/v1/ex_SAWOOH/poster.jpg?..."
},
// Extra fields ExerciseDB doesn't have:
"model": "male",
"counterpartId": "ex_HYOSAB",
"tips": ["Keep your feet flat on the floor...", "..."],
"difficulty": "intermediate",
"category": "strength",
"mechanic": "compound",
"force": "push",
"met": 5,
"caloriesPerMinute": 6.1,
"recommendedSets": "3-4",
"recommendedReps": "6-10",
"description": "Full exercise description..."
}
Python Migration
import requests
url = "https://exercisedb.p.rapidapi.com/exercises/bodyPart/chest"
headers = {
"X-RapidAPI-Key": "YOUR_RAPIDAPI_KEY",
"X-RapidAPI-Host": "exercisedb.p.rapidapi.com"
}
response = requests.get(url, headers=headers, params={"limit": 10})
exercises = response.json() # bare list
import requests
url = "https://api.workoutxapp.com/v2/exercises"
headers = {
"X-WorkoutX-Key": "YOUR_WORKOUTX_KEY"
}
response = requests.get(url, headers=headers, params={"bodyPart": "chest", "limit": 10})
result = response.json()
exercises = result["results"] # { total, limit, offset, results: [...] }
From GIF URLs to MP4 Video
ExerciseDB returns a gifUrl for each exercise. WorkoutX v2 doesn't serve GIFs: each exercise has a media object with a 600×720 MP4 animation (30 fps, typically 100–300 KB) and a JPEG poster. A GIF at the same quality is several times larger, and every platform plays MP4 natively. Replace your <img src={gifUrl}> with a muted, looping video:
<video src="{media.mp4}" poster="{media.poster}" autoplay loop muted playsinline></video>
The links are signed and expire after 24–25 hours (media.expiresAt), so don't save them. Store the exercise id and get fresh links from the exercise response or GET /v2/exercises/{id}/media when you show it. Downloading the files or serving them from your own servers or CDN is not permitted on any plan. On the Free plan, media is a watermarked 300×360 preview.
Field Casing Difference
One small difference: ExerciseDB returns field values in lowercase ("chest", "barbell"). WorkoutX returns them in Title Case ("Chest", "Barbell"). Update any string comparisons in your UI:
if (exercise.bodyPart === 'chest') { ... }
if (exercise.equipment === 'barbell') { ... }
if (exercise.bodyPart === 'Chest') { ... }
// OR use case-insensitive comparison to be safe:
if (exercise.bodyPart.toLowerCase() === 'chest') { ... }
Query filters are case-insensitive, so ?bodyPart=chest and ?bodyPart=Chest return the same results.
Migration Checklist
- ✅ Sign up at workoutxapp.com and copy your API key
- ✅ Replace base URL:
exercisedb.p.rapidapi.com→api.workoutxapp.com/v2 - ✅ Replace headers: two RapidAPI headers → one
X-WorkoutX-Keyheader - ✅ Move path filters to query parameters:
/exercises/bodyPart/chest→/v2/exercises?bodyPart=chest - ✅ Update response parsing: bare array →
response.results - ✅ Replace
gifUrlimages withmedia.mp4videos andmedia.poster - ✅ Store WorkoutX exercise ids (
ex_…), not media URLs - ✅ Update string comparisons: lowercase → Title Case field values
- ✅ (Optional) Use new fields:
difficulty,caloriesPerMinute,mechanic,tips,model - ✅ Remove RapidAPI account dependency
Pricing Comparison
| Monthly Requests | WorkoutX | ExerciseDB (RapidAPI) |
|---|---|---|
| Up to 500 | Free (500 requests in total) | Free (10 req/min cap) |
| Up to 3,000 | $19/mo (Starter, 5,000) | ~$10–15/mo (varies) |
| Up to 10,000 | $39/mo (Growth, 25,000) | ~$25–35/mo |
| Up to 35,000 | $79/mo (Scale, 100,000) | ~$50+/mo |
The WorkoutX Free plan is 500 requests in total, not per month. Every paid plan gets the same 720p media; the plans differ by quota. See pricing for media limits per plan.
Ready to migrate? Get your free WorkoutX API key at workoutxapp.com — 500 requests in total, watermarked video previews included, no credit card required.
Migrate in 20 minutes — it's free
500 free requests, direct API access, no RapidAPI dependency.