Back to Blog
·7 min

Fitness & Habit Tracker App Templates: Build Health Apps Fast

Health and fitness apps are one of the most popular mobile app categories. From workout tracking to meditation and habit building, the demand for health-focused applications continues to grow. Building a fitness app requires integration with Apple Health and Google Fit, workout logging, progress visualization, and subscription management.

Fitness tracker app templates provide all of this infrastructure so you can launch your health app quickly.

Key Platform Features

A complete fitness tracker template includes:

  • Workout logging with exercise library
  • Progress charts and statistics
  • Goal setting and tracking
  • Apple Health / Google Fit sync
  • Meal planning and nutrition logging
  • Social features and challenges
  • Subscription plans for premium content
  • Push notifications for reminders

The Fitness Tracker template includes all of these features with health API integration.

Workout Logging Component

'use client'

import { useState } from 'react'
import { Plus, Dumbbell, Timer, Flame } from 'lucide-react'

interface Exercise {
  id: string
  name: string
  sets: { reps: number; weight: number }[]
}

export function WorkoutLogger() {
  const [exercises, setExercises] = useState<Exercise[]>([])
  const [exerciseName, setExerciseName] = useState('')

  const addSet = (exerciseIndex: number) => {
    const updated = [...exercises]
    updated[exerciseIndex].sets.push({ reps: 10, weight: 0 })
    setExercises(updated)
  }

  const addExercise = () => {
    if (!exerciseName.trim()) return
    setExercises([
      ...exercises,
      { id: Date.now().toString(), name: exerciseName, sets: [] },
    ])
    setExerciseName('')
  }

  const totalVolume = exercises.reduce(
    (sum, ex) => sum + ex.sets.reduce((s, set) => s + set.reps * set.weight, 0), 0
  )

  return (
    <div className="space-y-6">
      <div className="grid grid-cols-3 gap-4">
        <div className="rounded-xl border bg-white p-4 text-center">
          <Dumbbell className="mx-auto h-6 w-6 text-brand-600" />
          <p className="mt-2 text-2xl font-bold">{exercises.length}</p>
          <p className="text-xs text-gray-500">Exercises</p>
        </div>
        <div className="rounded-xl border bg-white p-4 text-center">
          <Timer className="mx-auto h-6 w-6 text-brand-600" />
          <p className="mt-2 text-2xl font-bold">45</p>
          <p className="text-xs text-gray-500">Minutes</p>
        </div>
        <div className="rounded-xl border bg-white p-4 text-center">
          <Flame className="mx-auto h-6 w-6 text-brand-600" />
          <p className="mt-2 text-2xl font-bold">{totalVolume.toLocaleString()}</p>
          <p className="text-xs text-gray-500">Volume (kg)</p>
        </div>
      </div>

      <div className="flex gap-2">
        <input
          type="text"
          value={exerciseName}
          onChange={e => setExerciseName(e.target.value)}
          placeholder="Add exercise..."
          className="flex-1 rounded-xl border px-4 py-2.5"
        />
        <button
          onClick={addExercise}
          className="rounded-xl bg-brand-600 px-4 py-2.5 text-white"
        >
          <Plus className="h-5 w-5" />
        </button>
      </div>

      {exercises.map((exercise, i) => (
        <div key={exercise.id} className="rounded-xl border bg-white p-4">
          <h4 className="font-semibold">{exercise.name}</h4>
          <div className="mt-3 space-y-2">
            {exercise.sets.map((set, j) => (
              <div key={j} className="flex items-center gap-3 text-sm">
                <span className="w-16 text-gray-500">Set {j + 1}</span>
                <input
                  type="number"
                  value={set.reps}
                  onChange={e => {
                    const updated = [...exercises]
                    updated[i].sets[j].reps = Number(e.target.value)
                    setExercises(updated)
                  }}
                  className="w-20 rounded-lg border px-3 py-1.5 text-center"
                />
                <span className="text-gray-400">reps ×</span>
                <input
                  type="number"
                  value={set.weight}
                  onChange={e => {
                    const updated = [...exercises]
                    updated[i].sets[j].weight = Number(e.target.value)
                    setExercises(updated)
                  }}
                  className="w-20 rounded-lg border px-3 py-1.5 text-center"
                />
                <span className="text-gray-400">kg</span>
              </div>
            ))}
            <button
              onClick={() => addSet(i)}
              className="mt-2 text-sm text-brand-600 hover:text-brand-700"
            >
              + Add Set
            </button>
          </div>
        </div>
      ))}
    </div>
  )
}

Health Data Sync

// lib/health/sync.ts
import { supabase } from '@/lib/supabase'

export async function syncHealthData(userId: string, platform: 'apple' | 'google') {
  if (platform === 'apple') {
    // Apple HealthKit integration
    const { data: workoutData } = await fetch('/api/health/apple/workouts').then(r => r.json())

    await supabase.from('health_sync').upsert({
      user_id: userId,
      platform: 'apple',
      last_sync: new Date().toISOString(),
      workouts: workoutData,
    })
  } else {
    // Google Fit integration
    const { data: fitnessData } = await fetch('/api/health/google/fitness').then(r => r.json())

    await supabase.from('health_sync').upsert({
      user_id: userId,
      platform: 'google',
      last_sync: new Date().toISOString(),
      activities: fitnessData,
    })
  }
}

Launch your health and fitness app with the Fitness Tracker template.

Browse all 200+ templates and starter kits.

Ready to Build?

Get started with our production-ready starter kits and ship your project faster.

Browse Starter Kits