Fitness apps thrive on sharing and social accountability. A user completes a workout and shares their stats. A friend sends a challenge invitation. A trainer posts a workout program link on social media. A wearable sends a notification with a deep link to the day's activity summary. Every one of these interactions is powered by deep links.
This guide covers deep linking patterns for fitness and health apps. For social sharing strategies, see social sharing for referral programs. For building viral mechanics, see viral mechanics in apps.
Photo by Ketut Subiyanto on Pexels
URL Structure
Fitness Content Types
/workouts/{workout-slug} → workout detail (exercises, sets, reps)
/workouts/{workout-slug}/start → start the workout immediately
/programs/{program-slug} → multi-week program overview
/programs/{program-slug}/week/{n} → specific week of a program
/challenges/{challenge-id} → challenge detail and leaderboard
/challenges/{challenge-id}/join → join a challenge directly
/activities/{activity-id} → completed activity summary
/users/{user-id}/profile → public profile
/groups/{group-id} → fitness group
/groups/{group-id}/join → join a group
/plans/{plan-id} → meal or workout plan
Workout Deep Links
The most shared content type in fitness apps:
func handleWorkoutDeepLink(_ url: URL) {
let slug = url.pathComponents[2] // /workouts/{slug}
let shouldAutoStart = url.pathComponents.last == "start"
WorkoutService.shared.getWorkout(slug) { workout in
if shouldAutoStart {
// Start the workout immediately
navigateToWorkoutPlayer(workout)
} else {
// Show workout details
navigateToWorkoutDetail(workout)
}
}
}
Challenge Deep Links
Challenge Invitations
Challenges are the highest-growth deep link category for fitness apps:
"I challenged you to 10,000 steps a day for 30 days! Join here:
https://yourapp.com/challenges/CHAL-ABC123/join?inviter=user-456"
fun handleChallengeJoinDeepLink(uri: Uri) {
val challengeId = uri.pathSegments.getOrNull(1) ?: return
val inviterId = uri.getQueryParameter("inviter")
challengeService.getChallenge(challengeId) { challenge ->
when (challenge.status) {
ChallengeStatus.ACTIVE -> {
// Show challenge details with join button
showChallengePreview(challenge, invitedBy = inviterId)
}
ChallengeStatus.UPCOMING -> {
showChallengePreview(challenge, invitedBy = inviterId)
showCountdown(challenge.startsAt)
}
ChallengeStatus.ENDED -> {
showChallengeResults(challenge)
suggestSimilarChallenges()
}
}
}
}
Challenge Result Sharing
After completing a challenge, share the results:
func shareChallengeResult(_ result: ChallengeResult) {
let url = URL(string: "https://yourapp.com/challenges/\(result.challengeId)")!
let message = """
I completed the \(result.challengeName) challenge! \
\(result.totalDays) days, \(result.totalSteps) steps. \
My rank: #\(result.rank) of \(result.totalParticipants).
"""
let activityVC = UIActivityViewController(
activityItems: [message, url],
applicationActivities: nil
)
present(activityVC, animated: true)
}
Activity Sharing Deep Links
Post-Workout Sharing
The "share your workout" flow is the most organic growth channel for fitness apps:
https://yourapp.com/activities/ACT-789?ref=share
The web fallback shows the activity summary:
<meta property="og:title" content="Morning Run - 5.2 km in 28:15">
<meta property="og:description" content="Average pace: 5:26/km. Elevation gain: 42m. View in [YourApp]">
<meta property="og:image" content="https://yourapp.com/api/activities/ACT-789/card.png">
Generate a visually appealing activity card image dynamically:
// API endpoint: generate activity card image
app.get('/api/activities/:id/card.png', async (req, res) => {
const activity = await getActivity(req.params.id);
const card = await generateActivityCard({
type: activity.type,
distance: activity.distance,
duration: activity.duration,
pace: activity.pace,
mapSnapshot: activity.mapUrl,
userName: activity.user.displayName
});
res.type('image/png').send(card);
});
Progress Milestone Sharing
Automated sharing prompts at milestones:
"You just hit 100 workouts this year! Share your achievement."
Deep link: https://yourapp.com/achievements/100-workouts-2026
Trainer and Content Creator Deep Links
Program Links
Trainers share their programs via deep links:
"My 12-week strength program is now available:
https://yourapp.com/programs/12-week-strength-foundations"
The deep link should handle:
- Free programs: open directly.
- Paid programs: show preview with purchase option.
- Programs requiring subscription: show subscription CTA.
Live Class Links
"Join my live yoga class at 7 AM:
https://yourapp.com/live/yoga-sunrise-session?date=2026-06-26"
Handle pre-class, during-class, and post-class states:
func handleLiveClassDeepLink(_ url: URL) {
guard let classId = url.pathComponents.last else { return }
LiveClassService.shared.getClass(classId) { liveClass in
let now = Date()
if now < liveClass.startTime.addingTimeInterval(-300) {
// More than 5 minutes before start
showClassPreview(liveClass, withCountdown: true)
} else if now < liveClass.endTime {
// Class is live or about to start
joinLiveClass(liveClass)
} else {
// Class ended
if let recording = liveClass.recordingUrl {
showRecording(recording)
} else {
showClassSummary(liveClass)
suggestUpcomingClasses()
}
}
}
}
Wearable Integration Deep Links
Apple Watch and HealthKit
Deep links can trigger workout recording on wearables:
// iPhone app receives deep link, forwards to Watch
func handleWorkoutStartDeepLink(_ url: URL) {
let workoutSlug = url.pathComponents[2]
// Load workout data
WorkoutService.shared.getWorkout(workoutSlug) { workout in
// Forward to Apple Watch if connected
if WCSession.default.isWatchAppInstalled {
WCSession.default.sendMessage(
["action": "startWorkout", "workout": workout.toDictionary()],
replyHandler: nil
)
}
// Also show workout on iPhone
navigateToWorkoutPlayer(workout)
}
}
Health Data Deep Links
Link from health-related notifications to specific data views:
Push: "Your resting heart rate has been trending down this week"
Deep link: /health/heart-rate?period=7d
Push: "You slept 8 hours last night - your best this month"
Deep link: /health/sleep?date=2026-06-25
Structured Data for Fitness Content
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ExercisePlan",
"name": "12-Week Strength Foundations",
"description": "Build a strong foundation with progressive overload training",
"exerciseType": "Strength Training",
"activityDuration": "PT45M",
"activityFrequency": "4 times per week",
"potentialAction": {
"@type": "ViewAction",
"target": "https://yourapp.com/programs/12-week-strength-foundations"
}
}
</script>
Tolinku for Fitness Apps
Tolinku handles deep link routing for fitness content. Configure routes like /workouts/:slug, /challenges/:id/join, and /programs/:slug in the Tolinku dashboard. Deferred deep linking preserves challenge invitations and workout links through the install flow, so new users land directly on the shared content after installing.
For the broader deep linking trends, see the future of mobile deep linking.
Get deep linking tips in your inbox
One email per week. No spam.