# How to Integrate Lovable with MyFitnessPal

- Tool: Lovable
- Difficulty: Intermediate
- Time required: 40 minutes
- Last updated: March 2026

## TL;DR

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.

## Before you start

- 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

### 1. 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.

**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.

### 2. 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.

**Expected result:** FATSECRET_CONSUMER_KEY, FATSECRET_CONSUMER_SECRET, and FATSECRET_API_URL appear in your Cloud Secrets list.

### 3. 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).

```
// supabase/functions/nutrition-api/index.ts
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";

const CONSUMER_KEY = Deno.env.get("FATSECRET_CONSUMER_KEY") ?? "";
const CONSUMER_SECRET = Deno.env.get("FATSECRET_CONSUMER_SECRET") ?? "";
const API_URL = "https://platform.fatsecret.com/rest/server.api";
const corsHeaders = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "POST, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization" };

function percentEncode(str: string) { return encodeURIComponent(str).replace(/!/g, "%21").replace(/'/g, "%27").replace(/\(/g, "%28").replace(/\)/g, "%29").replace(/\*/g, "%2A"); }

async function fatSecretRequest(method: string, params: Record<string, string>) {
  const nonce = crypto.randomUUID().replace(/-/g, "");
  const timestamp = Math.floor(Date.now() / 1000).toString();
  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" };
  const sortedParams = Object.entries(allParams).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${percentEncode(k)}=${percentEncode(v)}`).join("&");
  const baseString = `GET&${percentEncode(API_URL)}&${percentEncode(sortedParams)}`;
  const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(`${CONSUMER_SECRET}&`), { name: "HMAC", hash: "SHA-1" }, false, ["sign"]);
  const sig = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(baseString));
  const signature = btoa(String.fromCharCode(...new Uint8Array(sig)));
  const url = `${API_URL}?${sortedParams}&oauth_signature=${percentEncode(signature)}`;
  const res = await fetch(url);
  return res.json();
}

serve(async (req) => {
  if (req.method === "OPTIONS") return new Response(null, { headers: corsHeaders });
  const supabase = createClient(Deno.env.get("SUPABASE_URL") ?? "", Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "");
  try {
    const body = await req.json();
    const { action } = body;

    if (action === "search") {
      const data = await fatSecretRequest("foods.search.v2", { search_expression: body.query, max_results: "20", page_number: "0" });
      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]) : [] }));
      return new Response(JSON.stringify({ foods }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
    }

    if (action === "log-food") {
      const { user_id, date, meal_type, food_id, food_name, serving_size, calories, protein, carbs, fat } = body;
      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() });
      return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
    }

    return new Response(JSON.stringify({ error: "Unknown action" }), { status: 400, headers: corsHeaders });
  } catch (err) {
    return new Response(JSON.stringify({ error: err.message }), { status: 500, headers: { ...corsHeaders, "Content-Type": "application/json" } });
  }
});
```

**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.

### 4. 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.

**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.

## 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.

## 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.

Prompt example:

```
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.
```

### 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.

Prompt example:

```
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.
```

### 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.

Prompt example:

```
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.
```

## 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&params), and the final signature. FatSecret's documentation includes example requests with expected signatures that you can use to verify your implementation.

```
// Debug: log the base string (REMOVE before production)
console.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.

```
const data = await fatSecretRequest("foods.search.v2", {
  search_expression: query,
  max_results: "20",
  page_number: "0",
  // format is already added in fatSecretRequest as format: 'json'
});
```

### 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.

```
const calories = parseFloat(selectedServing.calories ?? '0') * servingMultiplier;
```

## 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.

---

Source: https://www.rapidevelopers.com/lovable-integration/myfitnesspal
© RapidDev — https://www.rapidevelopers.com/lovable-integration/myfitnesspal
