MyFitnessPal deprecated its public API in 2019. To build nutrition tracking features in Lovable, use FatSecret Platform API (free with OAuth1) or Nutritionix API for food search and nutritional data. Store API credentials in Cloud Secrets, create an Edge Function to proxy food database queries, and build a calorie and macro tracking dashboard. Setup takes 40 minutes.
Building nutrition tracking without the MyFitnessPal API
MyFitnessPal was the gold standard for calorie tracking apps for over a decade, with a food database of 14 million items and a clean API that third-party apps could query. In 2019, MyFitnessPal deprecated their public API without official announcement, cutting off access for hundreds of developers who had built nutrition tracking features around it. The API endpoints still technically exist but return errors for new developers.
The nutrition tracking space has robust alternatives. FatSecret Platform API is the most developer-friendly replacement — it's free for up to 5,000 requests per day, has a food database of comparable size to MyFitnessPal, returns detailed nutritional profiles (calories, protein, carbs, fat, fiber, vitamins, minerals), and uses OAuth1 authentication. Nutritionix API is another strong option with NLP-powered natural language food input ("I ate a chicken sandwich and diet coke") and branded food data from thousands of restaurant chains.
For Lovable developers, the architecture for nutrition tracking is: a food search Edge Function that queries FatSecret or Nutritionix, a food diary stored in Supabase with daily logs, calorie and macro totals calculated from the diary, and a dashboard showing progress toward daily nutrition goals. This gives you complete control over the UI and features — something that MyFitnessPal's deprecated API never would have provided anyway.
Integration method
MyFitnessPal has no public API as of 2019. Building nutrition tracking in Lovable means using alternative food databases: FatSecret Platform API (free, OAuth1) or Nutritionix API (freemium, API key). Store your chosen provider's credentials in Cloud Secrets, create an Edge Function to search the food database and return nutritional data, and build a food diary with calorie and macro tracking backed by Supabase. All API requests run through Edge Functions to keep credentials server-side.
Prerequisites
- A Lovable project with Cloud enabled
- A FatSecret developer account — register free at platform.fatsecret.com/api (or a Nutritionix account at developer.nutritionix.com)
- FatSecret API credentials: consumer_key and consumer_secret from the developer portal
- Basic understanding of food macro tracking concepts (calories, protein, carbs, fat)
Step-by-step guide
Register for FatSecret Platform API credentials
Register for FatSecret Platform API credentials
Go to platform.fatsecret.com/api and click 'Register'. FatSecret's registration is straightforward — you provide your name, email, and a description of how you'll use the API. There's no approval process; you receive API credentials immediately after registration. After registering, log into the developer portal and navigate to 'My Apps'. Click 'Create a new application'. Fill in the application name and description. FatSecret generates a Consumer Key and Consumer Secret for your application. Copy both — the Consumer Secret is shown on the credentials page and can be retrieved later if needed (unlike some APIs that show it only once). FatSecret uses OAuth1 for authentication, which is older than OAuth2 but straightforward in practice. Unlike OAuth2 where you redirect users to authorize access, FatSecret's food data API is public — you use your app's Consumer Key and Secret to authenticate each request without user involvement. The free tier provides 5,000 calls/day and 300,000 calls/month, which is more than sufficient for most nutrition apps. Key FatSecret endpoints: food.search (search by name), food.get (get full nutritional data by ID), food.get.v2 (returns more detailed data), foods.search.v2 (returns more structured results). All responses are available in JSON (add &format=json to requests) or XML.
Pro tip: FatSecret's API documentation also includes recipes, meal plans, and exercise databases beyond food items. If you're building a comprehensive nutrition app, explore these endpoints to add features beyond basic food logging without additional API providers.
Expected result: You have your FatSecret Consumer Key and Consumer Secret from the developer portal. You can test them by sending a signed food.search request and receiving food results.
Store FatSecret credentials in Cloud Secrets
Store FatSecret credentials in Cloud Secrets
Open your Lovable project, click '+', select 'Cloud', and expand Secrets. Add FATSECRET_CONSUMER_KEY with your Consumer Key value and FATSECRET_CONSUMER_SECRET with your Consumer Secret value. Also add FATSECRET_API_URL with 'https://platform.fatsecret.com/rest/server.api' as the base endpoint URL. FatSecret uses OAuth1 signature generation, which requires computing an HMAC-SHA1 signature for each request. The signature incorporates your Consumer Secret along with the request parameters and a timestamp/nonce for replay protection. Because the Consumer Secret is part of every request signature, it must never appear in frontend code. If you prefer Nutritionix over FatSecret, add NUTRITIONIX_APP_ID and NUTRITIONIX_APP_KEY instead. Nutritionix uses simple API key authentication (x-app-id and x-app-key headers) which is easier to implement than OAuth1, and their NLP endpoint ('natural' endpoint) accepts plain text descriptions like 'grilled chicken breast 6oz' and returns parsed nutritional data — a significant usability advantage for natural language input.
Pro tip: Choose FatSecret if you need the largest free food database and OAuth1 is acceptable. Choose Nutritionix if you want NLP food input or branded food data from restaurants (Nutritionix's commercial database includes McDonald's, Starbucks, etc. with up-to-date nutritional data directly from the brands).
Expected result: FATSECRET_CONSUMER_KEY, FATSECRET_CONSUMER_SECRET, and FATSECRET_API_URL appear in your Cloud Secrets list.
Create the nutrition data Edge Function
Create the nutrition data Edge Function
FatSecret requires OAuth1 request signing. Each API call needs: a timestamp (Unix epoch seconds), a nonce (unique random string per request), the request parameters sorted alphabetically, a signature base string combining HTTP method + encoded URL + encoded parameter string, and an HMAC-SHA1 signature computed using Consumer Secret + '&' (no token secret since this is app-only auth). While OAuth1 looks complex, implementing it in Deno is manageable using the built-in crypto.subtle API for HMAC-SHA1. The key steps are: collect all parameters (method params + oauth params), sort them alphabetically by key, percent-encode both keys and values, join as key=value pairs with '&', prepend the HTTP method and encoded endpoint URL, compute HMAC-SHA1 with the Consumer Secret as the key, and Base64-encode the result. For food search, the main parameters are method='food.search', search_expression (the search term), max_results (up to 50), page_number, and format='json'. The response includes a list of foods with basic info. To get full nutritional data, follow up with food.get using the food_id from search results. Build the Edge Function to support: action='search' (search by text query, returns list with basic nutrition), action='get-food' (get full nutrition by food_id), and action='log-food' (save diary entry to Supabase).
Create a Supabase Edge Function at supabase/functions/nutrition-api/index.ts. Read FATSECRET_CONSUMER_KEY, FATSECRET_CONSUMER_SECRET from Deno.env. Implement OAuth1 signing: generate nonce and timestamp, build sorted parameter string, create HMAC-SHA1 signature using crypto.subtle with the consumer secret. Support: action='search' with query param — call FatSecret food.search and return array of {food_id, food_name, food_type, calories_per_serving, protein, carbs, fat, serving_description}; action='get-food' with food_id — call FatSecret food.get and return full nutrition data with all servings; action='log-food' with user_id, date, meal_type, food details — insert into Supabase food_diary table.
Paste this in Lovable chat
1// supabase/functions/nutrition-api/index.ts2import { serve } from "https://deno.land/std@0.168.0/http/server.ts";3import { createClient } from "https://esm.sh/@supabase/supabase-js@2";45const CONSUMER_KEY = Deno.env.get("FATSECRET_CONSUMER_KEY") ?? "";6const CONSUMER_SECRET = Deno.env.get("FATSECRET_CONSUMER_SECRET") ?? "";7const API_URL = "https://platform.fatsecret.com/rest/server.api";8const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "POST, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization" };910function percentEncode(str: string) { return encodeURIComponent(str).replace(/!/g, "%21").replace(/'/g, "%27").replace(/\(/g, "%28").replace(/\)/g, "%29").replace(/\*/g, "%2A"); }1112async function fatSecretRequest(method: string, params: Record<string, string>) {13 const nonce = crypto.randomUUID().replace(/-/g, "");14 const timestamp = Math.floor(Date.now() / 1000).toString();15 const allParams: Record<string, string> = { ...params, method, format: "json", oauth_consumer_key: CONSUMER_KEY, oauth_nonce: nonce, oauth_signature_method: "HMAC-SHA1", oauth_timestamp: timestamp, oauth_version: "1.0" };16 const sortedParams = Object.entries(allParams).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${percentEncode(k)}=${percentEncode(v)}`).join("&");17 const baseString = `GET&${percentEncode(API_URL)}&${percentEncode(sortedParams)}`;18 const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(`${CONSUMER_SECRET}&`), { name: "HMAC", hash: "SHA-1" }, false, ["sign"]);19 const sig = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(baseString));20 const signature = btoa(String.fromCharCode(...new Uint8Array(sig)));21 const url = `${API_URL}?${sortedParams}&oauth_signature=${percentEncode(signature)}`;22 const res = await fetch(url);23 return res.json();24}2526serve(async (req) => {27 if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders });28 const supabase = createClient(Deno.env.get("SUPABASE_URL") ?? "", Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "");29 try {30 const body = await req.json();31 const { action } = body;3233 if (action === "search") {34 const data = await fatSecretRequest("foods.search.v2", { search_expression: body.query, max_results: "20", page_number: "0" });35 const foods = (data.foods_search?.results?.food ?? []).map((f: any) => ({ food_id: f.food_id, food_name: f.food_name, food_type: f.food_type, servings: f.servings?.serving ? (Array.isArray(f.servings.serving) ? f.servings.serving : [f.servings.serving]) : [] }));36 return new Response(JSON.stringify({ foods }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });37 }3839 if (action === "log-food") {40 const { user_id, date, meal_type, food_id, food_name, serving_size, calories, protein, carbs, fat } = body;41 await supabase.from("food_diary").insert({ user_id, date, meal_type, food_id, food_name, serving_size, calories, protein, carbs, fat, created_at: new Date().toISOString() });42 return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });43 }4445 return new Response(JSON.stringify({ error: "Unknown action" }), { status: 400, headers: corsHeaders });46 } catch (err) {47 return new Response(JSON.stringify({ error: err.message }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } });48 }49});Pro tip: FatSecret's food search results include both brand-name and generic foods. Generic foods (like 'Chicken Breast, Grilled') are available free. Some branded foods require a premium FatSecret account. For most calorie tracking apps, generic foods cover the vast majority of what users log.
Expected result: The nutrition-api Edge Function searches FatSecret and returns structured food data. Searching for 'chicken breast' returns multiple matching foods with calorie and macro data. Logging a food entry saves it to the Supabase food_diary table.
Build the food diary and nutrition dashboard
Build the food diary and nutrition dashboard
With the Edge Function handling food data, build the calorie tracking UI. The main interface consists of three parts: a food search and logging flow, a daily diary view showing all logged items, and a nutrition summary dashboard. For the search and log flow, display a search bar that queries the nutrition-api Edge Function on each keystroke (debounced to 500ms to avoid excessive API calls). Show results as a dropdown list with food name, serving description, and calories. When a user selects a food, show a serving size selector and a 'Log to Diary' button that adds the entry via action='log-food'. For the diary view, query the food_diary Supabase table for today's entries grouped by meal_type (breakfast, lunch, dinner, snack). Show each meal section with its entries and a subtotal. Show a daily total at the top. For the summary dashboard, calculate totals from the food_diary table: total calories vs. daily goal (configurable in user settings), protein/carbs/fat macros as gram amounts and percentages of total calories, a circular progress ring for calorie goal, and a horizontal macro distribution bar. Add a nutrition settings page where users can set their daily calorie goal (default 2000) and macro targets. Store these in a user_nutrition_goals Supabase table.
Build a nutrition tracking dashboard. Top section: daily calorie progress ring showing calories consumed vs. goal (default 2000), macro bars showing protein/carbs/fat consumed vs. targets. Middle section: food diary with sections for Breakfast, Lunch, Dinner, and Snacks — each showing logged foods with calories and a section subtotal. Bottom: search bar that queries nutrition-api, shows results dropdown, and adds selected foods to the diary with a meal selector. Add a Settings button to configure calorie and macro goals stored in Supabase. All diary data reads from and writes to the food_diary Supabase table.
Paste this in Lovable chat
Pro tip: Macro percentages should sum to 100%. Calculate as: protein % = (protein_grams * 4 / total_calories) * 100, carb % = (carb_grams * 4 / total_calories) * 100, fat % = (fat_grams * 9 / total_calories) * 100. Note that protein and carbs have 4 calories per gram while fat has 9 calories per gram.
Expected result: Users can search for foods, select from results, and add them to their daily diary. The nutrition dashboard shows calories consumed, remaining calories, and macro distribution. All data persists in Supabase between sessions.
Common use cases
Calorie and macro tracking food diary
A nutrition app lets users search for foods by name, select serving sizes, and log meals throughout the day. Each food entry adds to a running calorie and macro total. The dashboard shows remaining calories for the day, a macro breakdown (protein, carbs, fat as percentages), and a meal-by-meal log with the option to delete entries.
Build a food diary app. Add a food search bar that calls an Edge Function to search FatSecret for matching foods and returns name, calories per serving, protein, carbs, and fat. When a user selects a food, show a serving size selector and Add to Diary button. Store diary entries in Supabase with user_id, date, meal_type (breakfast/lunch/dinner/snack), food_id, food_name, serving_size, calories, protein, carbs, fat. Show today's totals: calories consumed vs. 2000 calorie goal, and macro percentages with progress bars.
Copy this prompt to try it in Lovable
Weekly nutrition report with trend charts
A nutrition coaching app shows weekly averages of calorie intake, protein consumption, and adherence to macro targets. An Edge Function retrieves the past 7 days of diary entries from Supabase and calculates daily totals. The frontend shows day-by-day calorie bars with the target line, average macro breakdown for the week, and days where protein goal was hit.
Build a weekly nutrition summary page. Query the Supabase food_diary table for the past 7 days of entries for the current user. Calculate per-day totals for calories, protein, carbs, and fat. Display: a bar chart of daily calories with a horizontal target line at 2000, a 7-day average macro breakdown as percentages (protein/carbs/fat), total days this week where protein goal (150g) was met shown as a streak counter, and the single highest-calorie day with the foods logged.
Copy this prompt to try it in Lovable
Recipe nutrition calculator
A meal prep app lets users build recipes by searching for ingredients and entering quantities. The app calculates the total nutritional profile of the recipe and allows dividing by serving count to get per-serving nutrition facts. Saved recipes can be quickly added to the food diary as a single entry.
Build a recipe builder. Let users add ingredients by searching the FatSecret food database and entering a quantity with unit (grams, oz, cups). Calculate the total calories, protein, carbs, and fat for all ingredients combined. Add a 'Servings' field and divide totals by servings to show per-serving nutrition facts in an FDA-style nutrition label format. Save recipes to a Supabase recipes table. Add a 'Log Recipe' button on saved recipes that adds the per-serving values to today's food diary.
Copy this prompt to try it in Lovable
Troubleshooting
FatSecret API returns 'Invalid signature' error
Cause: OAuth1 signature generation is exact — any difference in parameter sorting, encoding, or the signature base string construction causes invalid signatures. Common mistakes include not percent-encoding the parameters correctly, not sorting parameters alphabetically, or including the signature parameter itself in the signed parameters.
Solution: Implement signature debugging by logging the base string before signing in Cloud Logs (with the Consumer Secret redacted). Compare each component: the sorted parameter string, the base string structure (METHOD&url¶ms), and the final signature. FatSecret's documentation includes example requests with expected signatures that you can use to verify your implementation.
1// Debug: log the base string (REMOVE before production)2console.log('Base string:', baseString.substring(0, 100) + '...');Food search returns no results for common foods
Cause: FatSecret's search API requires an exact URL parameter format and the method 'foods.search.v2' (not 'food.search'). Older documentation references the deprecated 'foods.search' method which returns fewer results. Also, FatSecret may return results in XML format by default if the format=json parameter is missing.
Solution: Verify your Edge Function uses 'foods.search.v2' as the method and includes 'format': 'json' in the parameters before signing. Test the search with common terms like 'apple' or 'rice' before testing complex queries. Check Cloud Logs for the raw FatSecret response to see if it's returning XML instead of JSON.
1const data = await fatSecretRequest("foods.search.v2", {2 search_expression: query,3 max_results: "20",4 page_number: "0",5 // format is already added in fatSecretRequest as format: 'json'6});Calorie totals don't match the sum of logged food entries
Cause: FatSecret returns calorie values as strings, not numbers, in JSON responses. If your JavaScript adds string values instead of numbers, '200' + '150' = '200150' instead of 350.
Solution: Always parse calorie and macro values as floats: parseFloat(food.calories ?? '0'). Also check for serving size multipliers — if a user logs 2 servings of something, multiply the per-serving macros by the serving count before logging to the database.
1const calories = parseFloat(selectedServing.calories ?? '0') * servingMultiplier;Best practices
- Debounce food search input to 400-500ms before calling the Edge Function — FatSecret has a 5,000 call/day limit and a user typing quickly could exhaust it in minutes with unthrottled requests.
- Cache common food searches in Supabase for 24 hours — foods like 'chicken breast' or 'rice' return the same results every time and don't need fresh API calls.
- Store calorie and macro values as numbers (not strings) in the food_diary table — FatSecret returns values as strings in JSON and failing to parse them will cause calculation errors.
- Add a 'Quick Add Calories' option for users who don't want to search — a simple integer input that adds a calories-only entry is faster for users who know their calorie count but don't need macro tracking.
- Include a 'Recently Logged' section in the food search interface showing foods the user has logged in the past 7 days — most users eat the same foods repeatedly, making recent history more useful than searching.
- For recipe logging, implement a multiplication factor — when logging a recipe, multiply all macros by the number of servings consumed, not just record the recipe totals.
- Validate that macro grams yield calories close to the calorie total (protein grams * 4 + carb grams * 4 + fat grams * 9 ≈ total calories) as a data quality check — large discrepancies indicate data issues in the food database entry.
Alternatives
Fitbit API provides nutrition data from the Fitbit food diary if users already track nutrition in Fitbit, alongside activity and sleep data in one integration.
Apple HealthKit aggregates nutrition data from any iOS health app including MyFitnessPal; use HealthKit when users already have nutrition data in another app on iPhone.
Google Fit stores nutrition data from Android health apps and can aggregate food logs from multiple sources for Android users.
Frequently asked questions
Why did MyFitnessPal shut down their API?
MyFitnessPal deprecated their public API in February 2019 without a public explanation, though the reasons likely include monetization strategy changes, privacy concerns around third-party data access, and resources focused on their premium subscription features. The API endpoints technically still exist but return authentication errors for new applications. Existing integrations may still work with older API keys, but new development must use alternatives like FatSecret or Nutritionix.
Is FatSecret's free API reliable enough for a production app?
FatSecret's free tier (5,000 calls/day, 300,000/month) is sufficient for small to medium applications with good caching. They've maintained their developer API for over 15 years, making them a reliable long-term partner. For high-traffic apps, FatSecret offers premium plans with higher limits. Their food database (over 15 million items) is comparable in size to MyFitnessPal's.
Can I import existing MyFitnessPal diary data into my Lovable app?
MyFitnessPal allows exporting diary data as a CSV file through their website (Settings → Diary Settings → Export Data). You can build a CSV import feature in Lovable that reads this export and populates your Supabase food_diary table. The MFP export format includes date, meal, calories, protein, carbs, and fat per entry — all the fields needed for your nutrition database.
What's the difference between FatSecret and Nutritionix?
FatSecret has a larger generic food database, free OAuth1-based API, and has been available to developers longer. Nutritionix excels at branded/restaurant food data (McDonald's, Starbucks, Chipotle with current menu data), natural language food input ('I had a large Big Mac meal'), and barcode lookup. For a general calorie counter, FatSecret is the better free choice. For a restaurant-focused or NLP-powered app, Nutritionix is worth the paid tier.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation