Skip to main content
RapidDev - Software Development Agency
App Featuresvertical-tools24 min read

How to Add a Personalized Diet Planner to Your App (Copy-Paste Prompts Included)

A personalized diet planner needs a health onboarding quiz, a TDEE calorie calculator, a daily meal plan grid with swap functionality, nutrition progress rings, and a grocery list generator. With FlutterFlow or Lovable you can ship a working mobile feature in 6–12 hours. Running cost is $0–29/mo for small user bases — the Spoonacular free tier covers early usage. Costs scale with recipe API calls and push notification volume.

4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members

Feature spec

Advanced

Category

vertical-tools

Build with AI

6–12 hours with FlutterFlow or Lovable

Custom build

3–6 weeks custom dev

Running cost

$0–29/mo up to 100 users

Works on

Mobile

Everything it takes to ship a Personalized Diet Planner — parts, prompts, and real costs.

TL;DR

A personalized diet planner needs a health onboarding quiz, a TDEE calorie calculator, a daily meal plan grid with swap functionality, nutrition progress rings, and a grocery list generator. With FlutterFlow or Lovable you can ship a working mobile feature in 6–12 hours. Running cost is $0–29/mo for small user bases — the Spoonacular free tier covers early usage. Costs scale with recipe API calls and push notification volume.

What a Personalized Diet Planner Feature Actually Is

A diet planner does more than list foods — it calculates how much a specific user should eat based on their body metrics and goals, then surfaces recipes that match their calorie target and dietary constraints. The core engine is the TDEE (Total Daily Energy Expenditure) calculation using the Mifflin-St Jeor formula applied to the user's weight, height, age, gender, and activity level. From that calorie target, a meal planning API (Spoonacular or Edamam) or a pre-seeded recipe database returns four daily meal slots. The real complexity is handling dietary restrictions and allergens correctly — most first builds get the happy path right but silently serve recipes containing allergens because the API parameters are misused. Push notifications for meal reminders and a grocery list that aggregates the week's ingredients are standard table stakes in 2026.

What users consider table stakes in 2026

  • Multi-step onboarding quiz that captures weight, height, age, gender, dietary preference, and food allergies before showing any meal plans
  • TDEE calorie target displayed prominently with a brief explanation of how it was calculated — users who see the math trust it more
  • Daily meal plan grid with four slots (breakfast, lunch, dinner, snack) showing recipe name, photo thumbnail, and calorie count per slot
  • Swap button on every meal slot that loads 3 alternative recipes matching the same calorie range and dietary constraints without regenerating the full plan
  • Nutrition progress rings (protein, carbs, fat) that fill in real time as meals are logged for the day
  • Auto-generated grocery list aggregating all ingredients for the 7-day plan, grouped by produce, dairy, grains, and proteins
  • Weight log screen with a trend line chart showing the last 30 days of weigh-ins
  • Push notification at a configurable time each morning with the day's meal plan summary

Anatomy of the Feature

Seven components; the TDEE calculation and allergen filtering are where most first builds produce incorrect results. Be explicit about both in your prompt.

Layers:UIDataService

Onboarding quiz flow

UI

Multi-step form wizard collecting age, weight (kg), height (cm), gender, goal (lose weight / maintain / gain muscle), dietary preference (omnivore, vegetarian, vegan, keto, paleo), and food allergies (multi-select). Flutter Stepper widget (mobile) or shadcn/ui multi-step form (web). Calculates TDEE client-side using the Mifflin-St Jeor equation on the final step and saves to user_profiles table.

Note: The TDEE formula is: (10 x weight_kg) + (6.25 x height_cm) - (5 x age) + 5 for male, -161 for female. Then multiply by activity factor (sedentary 1.2, light 1.375, moderate 1.55, active 1.725). A common AI bug is applying the activity factor before completing the base formula.

Meal suggestion engine

Service

Spoonacular Meal Planning API — generates a daily meal plan given a calorie target and diet type. Parameters: targetCalories (TDEE), diet ('vegan', 'keto', etc.), exclude (comma-separated allergen list from user_profiles.allergies). Or Edamam Meal Planning API with equivalent parameters. For pre-seeded apps, use a Supabase recipes table with pgvector similarity search to find recipes matching the user's macro targets.

Note: Always pass BOTH the diet parameter AND the exclude/intolerances parameter. Passing only diet='vegan' does not exclude, for example, gluten — which many vegan recipes still contain.

Daily meal plan grid

UI

Flutter GridView or Column with 4 meal slots per day (breakfast, lunch, dinner, snack). Each slot displays the recipe name, a thumbnail image from the API response, and the calorie count. Tapping a slot expands a modal or navigates to the full recipe detail screen with ingredients and steps. A swap icon in the top-right of each card triggers an alternative recipe fetch.

Note: Store the selected meal plan in the meal_plans table as a JSONB column so the user sees the same plan when they return to the app rather than generating a new random plan each session.

Nutrition progress rings

UI

fl_chart RadialBarChart (Flutter) rendering three concentric rings for protein, carbs, and fat. Each ring fills to the percentage of the daily target consumed so far. Values update in real time when a meal slot is marked as logged. The daily nutrition target (in grams) is derived from the TDEE: 30% protein, 40% carbs, 30% fat by default, or custom macro ratios from user_profiles.

Note: Store the daily macro log in daily_nutrition_logs table rather than computing it from meal_plans every render — this prevents inconsistency when users swap meals mid-day.

Grocery list generator

Data

Client-side Dart or JavaScript function that iterates all 28 meal slots in the 7-day meal plan, extracts ingredient lists from each recipe (stored in meal_plans.meals JSONB), de-duplicates by ingredient name, sums quantities, and groups by food category (produce, dairy, grains, proteins, other). Output is stored in a Supabase shopping_list_items table or displayed in a stateful Flutter list.

Note: Unit normalization is the hard part — recipes use cups, grams, ounces, and tbsp. Normalize to grams/ml before summing to avoid listing '2 cups flour + 300g flour' as two separate items.

Progress tracker

Data

Two Supabase tables: weight_logs (user_id, date, weight_kg) and daily_nutrition_logs (user_id, date, kcal, protein_g, carbs_g, fat_g). Weight log screen displays the last 30 entries as an fl_chart LineChart with a linear regression trend line. Daily log screen shows a summary of what the user consumed vs their targets for the current day.

Note: Log weight in kg internally and convert to lbs for display based on the user's preference stored in user_profiles — avoids decimal precision issues when converting back and forth.

Push notification scheduler

Service

Firebase Cloud Messaging (FCM) — free, unlimited pushes via Google's messaging layer. A Supabase Edge Function triggered by a daily pg_cron job at 7am UTC (or user's local time offset) fetches the day's meal plan for each user and sends a personalized FCM notification with breakfast and lunch names. OneSignal is a simpler alternative with a visual dashboard for scheduling notifications at configurable times per user.

Note: FCM tokens expire and rotate. Store the current FCM token in user_profiles.fcm_token and update it on every app open — stale tokens cause silent notification delivery failures.

The data model

Five tables covering the user health profile, meal plans, weight logs, daily nutrition logs, and push token storage. Run this in the Supabase SQL editor — all RLS policies restrict data to the authenticated user:

schema.sql
1create table public.user_profiles (
2 user_id uuid primary key references auth.users(id) on delete cascade,
3 dob date,
4 weight_kg decimal(5,2),
5 height_cm decimal(5,1),
6 gender varchar(10),
7 goal varchar(30),
8 activity_level varchar(20) not null default 'moderate',
9 dietary_preference jsonb not null default '[]',
10 allergies jsonb not null default '[]',
11 tdee_kcal int,
12 unit_preference varchar(10) not null default 'metric',
13 fcm_token text,
14 notification_time time not null default '07:00:00',
15 updated_at timestamptz not null default now()
16);
17
18create table public.meal_plans (
19 id uuid primary key default gen_random_uuid(),
20 user_id uuid references auth.users(id) on delete cascade not null,
21 week_start date not null,
22 meals jsonb not null default '{}',
23 generated_at timestamptz not null default now(),
24 constraint meal_plans_user_week_unique unique (user_id, week_start)
25);
26
27create table public.weight_logs (
28 id uuid primary key default gen_random_uuid(),
29 user_id uuid references auth.users(id) on delete cascade not null,
30 date date not null default current_date,
31 weight_kg decimal(5,2) not null,
32 created_at timestamptz not null default now(),
33 constraint weight_logs_user_date_unique unique (user_id, date)
34);
35
36create table public.daily_nutrition_logs (
37 id uuid primary key default gen_random_uuid(),
38 user_id uuid references auth.users(id) on delete cascade not null,
39 date date not null default current_date,
40 kcal int not null default 0,
41 protein_g decimal(6,2) not null default 0,
42 carbs_g decimal(6,2) not null default 0,
43 fat_g decimal(6,2) not null default 0,
44 updated_at timestamptz not null default now(),
45 constraint daily_logs_user_date_unique unique (user_id, date)
46);
47
48-- Row Level Security
49alter table public.user_profiles enable row level security;
50alter table public.meal_plans enable row level security;
51alter table public.weight_logs enable row level security;
52alter table public.daily_nutrition_logs enable row level security;
53
54create policy "Users manage own profile"
55 on public.user_profiles for all
56 using (auth.uid() = user_id)
57 with check (auth.uid() = user_id);
58
59create policy "Users manage own meal plans"
60 on public.meal_plans for all
61 using (auth.uid() = user_id)
62 with check (auth.uid() = user_id);
63
64create policy "Users manage own weight logs"
65 on public.weight_logs for all
66 using (auth.uid() = user_id)
67 with check (auth.uid() = user_id);
68
69create policy "Users manage own nutrition logs"
70 on public.daily_nutrition_logs for all
71 using (auth.uid() = user_id)
72 with check (auth.uid() = user_id);
73
74-- Indexes
75create index weight_logs_user_date_idx on public.weight_logs (user_id, date desc);
76create index daily_logs_user_date_idx on public.daily_nutrition_logs (user_id, date desc);
77create index meal_plans_user_week_idx on public.meal_plans (user_id, week_start desc);

Heads up: The meal_plans.meals JSONB column stores the full 7-day plan as a nested object: {monday: {breakfast: {id, name, image, kcal, ingredients}, lunch: {...}, dinner: {...}, snack: {...}}, tuesday: {...}, ...}. This structure lets you fetch the entire week in one query and manipulate individual slots client-side for swaps without additional round-trips.

Build it — pick your path

Each tool fits this feature differently. Switch tabs to compare fit, time, the exact steps, and a copy-paste prompt.

Hand-built by developersFit for this feature:

Required when the diet planner needs Apple Health or Google Health Connect sync, AI-personalized meal recommendations that adapt to user feedback, clinical-grade nutrition tracking with dietitian oversight, or barcode scanning to log packaged foods.

Step by step

  1. 1Apple Health / Google Health Connect sync: use HealthKit (iOS) or Health Connect API (Android) to read weight, steps, and active calories; feed real-time activity data into the TDEE calculation for more accurate daily targets
  2. 2AI personalized recommendations: after a user swaps or rejects a meal, send the feedback to Claude or GPT via a Supabase Edge Function; build a preference profile in a user_meal_feedback table; use it to filter subsequent Spoonacular calls
  3. 3Clinical nutrition tracking: add a dietitian_id foreign key to user_profiles; build a dietitian dashboard where nutritionists can view patient macro logs, override TDEE targets, and add notes; HIPAA considerations apply if storing health data in the US
  4. 4Barcode scanning for packaged foods: integrate mobile_scanner Flutter package with Open Food Facts API lookup; show the product's nutrition facts and let users log a serving size directly to daily_nutrition_logs

Where this path bites

  • HealthKit and Health Connect require platform-specific Swift/Kotlin code or a React Native plugin — not achievable in a pure web or FlutterFlow build without custom code
  • HIPAA compliance for clinical nutrition apps requires a Business Associate Agreement with your database and hosting provider, plus audit logging, encryption at rest, and access controls beyond standard Supabase RLS

Third-party services you'll need

The TDEE calculation runs client-side for free. External services are needed for recipe suggestions and push notifications:

ServiceWhat it doesFree tierPaid from
Spoonacular APIRecipe search and meal planning — returns recipes matched to calorie target, diet type, and allergen exclusions150 points/day (1 meal plan call ≈ 1 point)From $29/mo for 3,000 points/day (approx)
Edamam Meal Planning APIAlternative to Spoonacular with strong nutrition data quality and dietitian-grade accuracyDeveloper tier available (contact Edamam)Contact for commercial pricing (approx)
Firebase Cloud Messaging (FCM)Push notifications for daily meal reminders — Google's messaging layer, no per-message costUnlimited pushes (free)Free
OneSignalAlternative to FCM with a visual dashboard for scheduling notifications at per-user timesUnlimited pushes for mobile$9/mo for advanced segmentation and analytics
SupabaseDatabase (all tables), auth, and Edge Functions for Spoonacular proxy and FCM dispatch500MB DB, 2 Edge Function projects, 50K monthly active users$25/mo (Pro) — 8GB DB, unlimited Edge Functions

Swipe the table sideways to see pricing.

What it costs to run

Drag through the tiers to see how your monthly bill scales with users — no surprises later.

Estimated monthly running cost

$0/mo

Spoonacular free tier of 150 points/day covers early testing if you cache the weekly meal plan on generation (one API call per user per week ≈ 1 point). FCM is free. Supabase free tier covers storage and auth.

Estimates use verified 2026 pricing and assume typical usage per user. Your real bill depends on activity, storage, and third-party plans.

What breaks when AI tools build this

The failures people actually hit on their first build — the symptom, why it happens, and the exact fix.

Recipes match the diet type but still contain allergens

Symptom: Passing only diet='vegan' to Spoonacular or Edamam returns vegan recipes — but many vegan recipes contain gluten, nuts, or soy. The diet parameter controls the overall recipe classification, not ingredient-level allergen exclusion. A user who selects 'vegan + nut allergy' receives recipes with peanuts or tree nuts if the intolerances parameter is omitted.

Fix: Always pass BOTH the diet parameter AND the intolerances or exclude parameter as separate URL parameters. For Spoonacular: ?diet=vegan&intolerances=peanut,tree+nut. For Edamam: &health=vegan&health=peanut-free&health=tree-nut-free. Double-check the exact parameter names in the API docs — they differ between services and AI tools frequently confuse them.

TDEE calculation returns numbers 30–50% off the correct value

Symptom: A common AI bug is applying the activity factor multiplier before completing the Mifflin-St Jeor base formula, or mixing up the gender constant (+5 for male, -161 for female). The result is a TDEE that is either dramatically low (making meal plans with only 800–900 kcal) or implausibly high (over 4,000 kcal for a sedentary person).

Fix: Specify the formula in the prompt step by step: Step 1 — base = (10 x weight_kg) + (6.25 x height_cm) - (5 x age_years) + 5 if male, or -161 if female. Step 2 — TDEE = base x activity_factor. Activity factors: sedentary=1.2, lightly active=1.375, moderately active=1.55, very active=1.725. Add a visible sanity check to the UI: most adults' TDEE falls between 1,400 and 3,500 kcal.

Grocery list shows duplicate ingredients in incompatible units

Symptom: Recipes from Spoonacular use mixed measurement systems — one recipe lists '2 cups flour', another lists '300g flour', a third '10 oz flour'. A naive grocery list aggregation adds these as three separate line items for the same ingredient, and the totals are meaningless. This appears as a real usability failure when users take the grocery list to a store.

Fix: Normalize all ingredient measurements to grams and milliliters on ingest using a unit conversion map (1 cup flour = 120g, 1 oz = 28.35g, 1 tbsp = 15ml). Group by a canonical ingredient name (lowercase singular) after normalization, then sum. Display the final quantity in the most human-friendly unit for that ingredient (e.g., '480g flour' rather than '480000mg flour').

FlutterFlow app crashes on null meal plan slots

Symptom: When the meal_plans.meals JSONB column contains null values for days not yet planned — for example, the plan was only generated for 3 of the 7 days — Flutter tries to access nested properties on a null object. Without null safety checks throughout the Dart model, the app throws a Null check operator used on a null value error and the meal plan page crashes.

Fix: Use ?? null coalescing throughout the Dart meal plan model when accessing nested JSONB properties: mealPlan['monday']?['breakfast']?['name'] ?? 'Not planned yet'. Initialize each day's four meal slots with empty default maps when generating a partial plan so the JSONB structure is always complete even for unplanned days.

Best practices

1

Cache the weekly meal plan in Supabase meal_plans table on first generation and reuse it — regenerating a fresh plan on every session burns Spoonacular API points and disorients users who remember what they planned to eat on Thursday

2

Always pass both diet and intolerances as separate Spoonacular API parameters — diet='vegan' does not exclude nut allergens from vegan recipes; intolerances must be listed explicitly

3

Display the TDEE calculation result with a brief plain-language explanation ('Your daily target: 2,100 kcal, based on your height, weight, and moderate activity level') — users who understand how their target was set are more likely to trust and follow it

4

Normalize ingredient units to grams and milliliters before aggregating the grocery list — incompatible units produce duplicate line items that destroy the grocery list's usefulness at the store

5

Store the FCM token on every app open and update it in user_profiles — FCM tokens rotate and expire, and stale tokens cause silent notification delivery failures that are hard to debug

6

Show a loading skeleton on each meal slot card while the Spoonacular API call is in progress — recipe fetches take 200–800ms and a blank screen makes users think the app has crashed

7

Add a visible sanity check on the TDEE output: flag values below 1,200 kcal or above 4,000 kcal with a warning message and prompt the user to review their inputs before saving

8

Store weight in kilograms internally and convert to the user's preferred unit (kg or lbs) only at display time — this prevents floating-point precision loss from repeated conversion

When You Need Custom Development

A standard diet planner with onboarding, meal plans, and macro tracking ships well with AI tools. These scenarios require a custom build:

  • App requires sync with Apple Health (HealthKit) or Google Health Connect to read real-time weight, steps, and active calories for more accurate daily TDEE adjustment — this requires platform-specific Swift or Kotlin code or a React Native plugin
  • Personalized meal recommendations must adapt in real time to user feedback ('I hated that recipe', 'I don't have time to cook this') using an LLM that builds a preference profile and filters subsequent API calls accordingly
  • App targets clinical or medical nutrition tracking — requires dietitian review workflows, patient-facing and clinician-facing dashboards, audit logging, and HIPAA Business Associate Agreements with all data processors
  • Needs barcode scanning to log packaged foods from a nutrition database (Open Food Facts, Nutritionix) directly to the daily food diary — requires a native camera integration beyond what standard FlutterFlow actions provide

RapidDev builds these features for production

Real auth, database, and payments — fixed price, delivered in weeks. You own 100% of the code.

Get a fixed-price quote

Frequently asked questions

How do I calculate how many calories to show as the daily target?

Use the Mifflin-St Jeor equation: (10 x weight_kg) + (6.25 x height_cm) - (5 x age_years) + 5 for males, or -161 for females. Then multiply by an activity factor — 1.2 for sedentary, 1.375 for lightly active, 1.55 for moderately active, 1.725 for very active. The result is the TDEE (Total Daily Energy Expenditure). For weight loss, subtract 300–500 kcal. For muscle gain, add 200–300 kcal. Apply the goal adjustment after the activity multiplier, not before.

Can the app automatically generate a grocery list from the weekly meal plan?

Yes — iterate all 28 meal slots in the 7-day plan, extract ingredient lists from each recipe, normalize units to grams and milliliters, de-duplicate by canonical ingredient name, sum quantities, and group by food category. The key complexity is unit normalization: recipes use cups, ounces, grams, and tablespoons interchangeably. A unit conversion table (1 cup flour = 120g, 1 oz = 28.35g) handles most cases. Store the output in a shopping_list_items Supabase table or display it as a stateful checklist.

How do I handle users with multiple dietary restrictions at the same time — like vegan and nut allergy?

Use both Spoonacular parameters simultaneously: diet=vegan&intolerances=peanut,tree+nut. The diet parameter controls recipe classification (no animal products) while the intolerances parameter controls ingredient-level exclusion (no peanuts or tree nuts in any ingredient). Never assume the diet parameter handles allergen exclusion — vegan recipes regularly contain nuts, gluten, and soy. Test your API calls with a user profile that has both a diet restriction and an allergen to verify both parameters are being sent.

Can users swap individual meals without regenerating the entire weekly plan?

Yes — store the full 7-day plan in the meal_plans.meals JSONB column keyed by day and meal slot. When the user taps Swap on a slot, call Spoonacular with the same calorie range and dietary constraints but exclude the current recipe's ID. Display 3 alternatives in a bottom sheet. When the user selects one, update only that slot in the JSONB object with an upsert — the other 27 slots remain unchanged. This saves API points and preserves the user's existing plan.

How do I sync the app with Apple Health or Google Fit?

Apple HealthKit requires iOS-native Swift code or a React Native package like react-native-health. Google Health Connect (Android 14+) uses the Android Health Connect SDK. Neither is accessible from a web app or standard FlutterFlow build without a custom widget. The most practical approach for a FlutterFlow app is a custom Dart plugin or a dedicated React Native build. Plan for 2–3 weeks of extra development time for a properly tested HealthKit integration.

What is the best recipe API to use for a diet planner?

Spoonacular is the most commonly used for diet planner apps — its meal planning endpoint generates a full day or week's plan from a calorie target and diet type in a single API call. Edamam has stronger dietitian-grade nutrition accuracy and is preferred for clinical or medical apps. Open Food Facts is free but covers packaged foods rather than recipes. The USDA FoodData Central is best for ingredient-level nutrition lookup rather than complete recipe suggestions.

Can I add a food diary where users log what they actually ate versus what was planned?

Store planned meals in meal_plans.meals JSONB and logged meals separately in daily_nutrition_logs (kcal, protein_g, carbs_g, fat_g). When a user taps 'Log this meal', add the recipe's macros to the daily log via an upsert. The nutrition progress rings read from daily_nutrition_logs, not from meal_plans. This decoupling lets users log meals they cooked themselves or ate out without breaking the planned meal view.

How do I send meal reminders via push notification at the right time of day?

Store the user's preferred notification time (e.g., 07:00) in user_profiles.notification_time alongside their timezone or UTC offset. A Supabase Edge Function triggered by pg_cron every hour fetches all users whose notification_time matches the current UTC hour (adjusted for their offset), retrieves their day's meal plan from meal_plans, and dispatches an FCM push via the Firebase HTTP v1 API. Store the FCM registration token in user_profiles.fcm_token and refresh it on every app open — tokens rotate and stale tokens cause silent delivery failures.

RapidDev

Need this feature production-ready?

RapidDev builds a personalized diet planner into real apps — auth, database, payments — at $13K–$25K.

Book a free consultation

30-min call. No commitment.

Want this built for you?

We ship production apps at a fixed price — $13K–$25K, 6–10 weeks, source code yours. You've seen what it takes; we do it every week.

Get a fixed-price quote

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.