MyFitnessPal shut down its public API in 2019 — there is no supported key to request. In FlutterFlow, the honest path is either importing a user's CSV export into Firestore or Supabase and reading it with FlutterFlow's native backend, or integrating the active Nutritionix nutrition API via a FlutterFlow API Group pointed at a Cloud Function proxy that holds your Nutritionix app ID and key.
| Fact | Value |
|---|---|
| Tool | MyFitnessPal |
| Category | Health & Fitness |
| Method | FlutterFlow API Call |
| Difficulty | Intermediate |
| Time required | 45 minutes |
| Last updated | July 2026 |
The Honest Truth About FlutterFlow + MyFitnessPal
If you searched for 'FlutterFlow MyFitnessPal integration', you probably found tutorials suggesting an API Call setup. Here's the problem: MyFitnessPal deprecated and shut down its public API in 2019. There is no official key to request, no developer portal to sign up on, and no supported endpoint to call. Competitors who claim otherwise are pointing at unofficial scraping approaches that break silently and violate MyFitnessPal's terms of service.
For FlutterFlow builders, this means you have two honest paths. The first is a CSV import: MyFitnessPal lets users export their diary as a CSV file from the website's settings. You can guide your users through that export, upload it to Firestore or Supabase, and read the historical data in your FlutterFlow app using the native Firebase or Supabase backend integration — no API key needed. The catch is that CSV data is a point-in-time snapshot, not a live sync, so users have to re-export manually when they want fresh data.
The second and more powerful path is to integrate Nutritionix, an active nutrition API with a free developer tier, covering over 1.5 million food items including branded products, restaurant items, and USDA data. Nutritionix uses an `x-app-id` and `x-app-key` header for auth — both are secrets and must never be hardcoded in your FlutterFlow Dart code. Instead, you proxy through a Firebase Cloud Function or Supabase Edge Function that injects those credentials server-side, then build a FlutterFlow API Group pointed at your proxy for food search and logging calls. This gives your app live, real-time nutrition lookup that your users can interact with directly.
Integration method
Because MyFitnessPal discontinued its public API in 2019, there is no direct integration path. You have two practical options: (1) import the user's MyFitnessPal CSV export into Firestore or Supabase and read it through FlutterFlow's native backend integration, or (2) connect to the Nutritionix nutrition API as an active alternative for live food search and macro logging. The Nutritionix path uses a FlutterFlow API Group pointed at a Cloud Function proxy that holds your Nutritionix app ID and key — those credentials are secrets and must never live in Dart or the client build.
Prerequisites
- A FlutterFlow project on a paid plan (Starter or above) with Firebase or Supabase configured
- A Nutritionix developer account at developer.nutritionix.com — free tier available
- Your Nutritionix app ID and app key from the developer dashboard
- A Firebase project (for Cloud Functions) or Supabase project (for Edge Functions) set up
- Node.js installed locally only if you are writing and deploying a Firebase Cloud Function
Step-by-step guide
Understand the limitation and choose your path
Before building anything, confirm that MyFitnessPal has no public API available. Go to myfitnesspal.com/api — you'll find either a closed sign-up page or a statement that the program is discontinued. Do not use unofficial endpoints or scrapers; they violate MFP's terms and break without warning. Now choose between the two supported paths: **Path A — CSV import:** Your users export their diary from MyFitnessPal → Settings → Diary Settings → Export Diary as CSV. You provide a UI in your FlutterFlow app where they can upload that file. This is a one-time historical snapshot — not a live sync. It works well for wellness coach apps that periodically review client history. **Path B — Nutritionix live integration:** You build a food-search and meal-logging UI powered by the Nutritionix API, giving users real-time nutrition lookups without needing a MyFitnessPal account at all. This is the better choice for any app targeting ongoing daily tracking. For most product scenarios, Path B delivers more value. The steps below cover Path B (Nutritionix) as the primary flow, with notes on the Firestore CSV approach where relevant. If you are on Path A, skip directly to Step 3 and configure a Firestore collection to receive the uploaded CSV data.
Pro tip: If your users already rely on MyFitnessPal and don't want to switch, the CSV export path is a good bridge: guide them through the export in an onboarding screen and let them re-upload monthly.
Expected result: You have a clear plan: either CSV import into Firestore/Supabase or Nutritionix API Group via proxy. You've registered at developer.nutritionix.com and have your app ID and app key.
Deploy a Cloud Function proxy for Nutritionix credentials
Your Nutritionix app ID and app key are secrets. If you put them in a FlutterFlow API Call header, they will be compiled into your app's binary and can be extracted from the APK or web bundle by anyone who downloads your app. Even if they're short strings, exposing them lets third parties burn through your API quota and potentially your billing. To fix this, deploy a Firebase Cloud Function (or Supabase Edge Function) that holds the credentials server-side and proxies requests to Nutritionix on behalf of your app. Here is a minimal Firebase Cloud Function in Node.js. Deploy it from the Firebase console or Firebase CLI, and set the two secrets as environment variables in the Cloud Function's configuration rather than hardcoding them: ```javascript const functions = require('firebase-functions'); const axios = require('axios'); exports.nutritionixSearch = functions.https.onRequest(async (req, res) => { res.set('Access-Control-Allow-Origin', '*'); if (req.method === 'OPTIONS') { res.set('Access-Control-Allow-Methods', 'POST'); res.set('Access-Control-Allow-Headers', 'Content-Type'); return res.status(204).send(''); } const { query } = req.body; if (!query) return res.status(400).json({ error: 'query is required' }); try { const response = await axios.post( 'https://trackapi.nutritionix.com/v2/natural/nutrients', { query }, { headers: { 'x-app-id': process.env.NUTRITIONIX_APP_ID, 'x-app-key': process.env.NUTRITIONIX_APP_KEY, 'Content-Type': 'application/json' } } ); return res.json(response.data); } catch (err) { return res.status(err.response?.status || 500).json({ error: err.message }); } }); ``` Set your environment variables in the Firebase console under Cloud Functions → your function → Edit → Environment variables, adding `NUTRITIONIX_APP_ID` and `NUTRITIONIX_APP_KEY`. Copy the deployed function URL — you'll use it in the next step.
1const functions = require('firebase-functions');2const axios = require('axios');34exports.nutritionixSearch = functions.https.onRequest(async (req, res) => {5 res.set('Access-Control-Allow-Origin', '*');6 if (req.method === 'OPTIONS') {7 res.set('Access-Control-Allow-Methods', 'POST');8 res.set('Access-Control-Allow-Headers', 'Content-Type');9 return res.status(204).send('');10 }11 const { query } = req.body;12 if (!query) return res.status(400).json({ error: 'query is required' });13 try {14 const response = await axios.post(15 'https://trackapi.nutritionix.com/v2/natural/nutrients',16 { query },17 {18 headers: {19 'x-app-id': process.env.NUTRITIONIX_APP_ID,20 'x-app-key': process.env.NUTRITIONIX_APP_KEY,21 'Content-Type': 'application/json'22 }23 }24 );25 return res.json(response.data);26 } catch (err) {27 return res.status(err.response?.status || 500).json({ error: err.message });28 }29});Pro tip: Use Firebase environment configuration or Secret Manager for the credentials — never paste them directly into the function source code that you might commit to GitHub.
Expected result: Your Cloud Function is deployed and you have its HTTPS URL (e.g. https://us-central1-YOUR_PROJECT.cloudfunctions.net/nutritionixSearch). Test it with a POST request in your browser's network tools or Postman to confirm it returns Nutritionix food data.
Create the Nutritionix API Group in FlutterFlow
With the proxy deployed, you're ready to build the API Group in FlutterFlow that your app will call. Open your FlutterFlow project, click API Calls in the left navigation panel, then click + Add and select Create API Group. Name it 'Nutritionix' (or similar). In the Base URL field, paste your Cloud Function URL — for example, `https://us-central1-YOUR_PROJECT.cloudfunctions.net`. You do NOT paste the Nutritionix base URL here; the Cloud Function is your backend. With the API Group created, click + Add API Call inside that group to add the food-search call. Name it 'searchFood'. Set the method to POST and the endpoint to `/nutritionixSearch` (matching the function name). Under the Body tab, set the content type to JSON and add a body with the variable `{{ query }}`. To create the variable, go to the Variables tab, click + Add, name it `query`, set the type to String. Your full API Call config should look like this: ```json { "method": "POST", "endpoint": "/nutritionixSearch", "body": { "query": "{{ query }}" } } ``` Switch to the Response & Test tab. In the Body input, paste a sample Nutritionix response (search for 'chicken breast' in your deployed function using Postman and copy the JSON output). Click Generate JSON Paths and FlutterFlow will auto-detect paths like `$.foods[0].food_name`, `$.foods[0].nf_calories`, `$.foods[0].nf_protein`, `$.foods[0].nf_total_carbohydrate`, `$.foods[0].nf_total_fat`. Name each one clearly — `foodName`, `calories`, `protein`, `carbs`, `fat`.
1{2 "method": "POST",3 "endpoint": "/nutritionixSearch",4 "headers": {},5 "body": {6 "query": "{{ query }}"7 },8 "json_paths": {9 "foodName": "$.foods[0].food_name",10 "calories": "$.foods[0].nf_calories",11 "protein": "$.foods[0].nf_protein",12 "carbs": "$.foods[0].nf_total_carbohydrate",13 "fat": "$.foods[0].nf_total_fat",14 "servingQty": "$.foods[0].serving_qty",15 "servingUnit": "$.foods[0].serving_unit"16 }17}Pro tip: Nutritionix's Natural Language endpoint (`/v2/natural/nutrients`) accepts plain-English food descriptions like '2 eggs scrambled' or 'large banana' and returns accurate macros — no need to search by barcode or ID for most cases.
Expected result: You can see the API Call in FlutterFlow's test panel returning real nutrition data. JSON paths are parsed and named. The API Group shows no authentication headers (all credentials stay in the Cloud Function).
Create a custom Data Type and build the food search UI
Now create a custom Data Type in FlutterFlow to store nutrition results cleanly. Go to the Data panel in the left nav, click Custom Data Types → + Add, and name it `NutritionItem`. Add fields: `foodName` (String), `calories` (Double), `protein` (Double), `carbs` (Double), `fat` (Double), `servingQty` (Double), `servingUnit` (String). Next, add an App State variable: go to App State → + Add, name it `searchResults`, set it to a List of `NutritionItem`, and check Persisted if you want results to survive navigation. Now build the search screen. Add a TextField widget for the food query — name it `foodQueryField`. Add a Button below it labelled 'Search'. On the Button's Actions panel, + Add Action → Backend/API Calls → API Call → select your Nutritionix / searchFood call. Set the `query` variable to the `foodQueryField`'s value. After the API Call action, add an Update App State action that updates `searchResults` by mapping the API response: `foodName` → `searchResults[0].foodName`, and so on for each field. Then add a ListView widget bound to `searchResults` — each list tile displays `foodName`, `calories` kcal, and macros as Text widgets. Include a 'Log Meal' button on each tile that writes the item to a Firestore `meals` collection with the user's UID and today's date. For the CSV path: if you're on Path A, add a File Upload widget and an action that reads the uploaded CSV, parses rows, and writes each row as a Firestore document. FlutterFlow's Firestore integration handles the writes without an API key.
Pro tip: For a cleaner UX, show the first result card immediately rather than a list — most natural-language queries return one dominant match. Show the full list only if the user taps 'See more options'.
Expected result: Typing a food name and tapping Search populates a list of NutritionItem results with calories and macros. Tapping Log Meal writes an entry to Firestore. The search results update each time without page refresh.
Add a daily macro summary and chart
The most useful screen after search-and-log is a daily summary that aggregates the user's logged meals for today. In FlutterFlow, add a new screen called 'Dashboard' or 'Today's Nutrition'. Add a Firestore Query as the data source on that page: filter the `meals` collection where `userId == currentUser.uid` AND `date == today's date` (store date as a string in YYYY-MM-DD format so querying is straightforward). Bind Text widgets to show total calories, total protein, total carbs, and total fat — you'll need to sum these in FlutterFlow using a custom function or by reading aggregated values. For a simpler approach, write aggregated totals back to a separate Firestore document (`dailySummary/{userId}/{date}`) whenever a meal is logged, and bind the summary screen to that document. For a chart, add a Bar Chart or Line Chart widget. FlutterFlow's chart widgets accept a list of data points — you can bind the last 7 days of daily calorie totals from a `weeklyCalories` list in App State (populated by querying Firestore for the past 7 days on page load). Label the x-axis with day names and the y-axis with calories. If you'd rather skip building the nutrition proxy and dashboard yourself, RapidDev's team builds FlutterFlow integrations like this weekly — including the Cloud Function setup, Data Types, and chart binding. Book a free scoping call at rapidevelopers.com/contact.
Pro tip: Store date values as YYYY-MM-DD strings in Firestore rather than Timestamps for daily grouping — they're simpler to filter and display without timezone edge cases.
Expected result: The Dashboard screen shows today's total calories, protein, carbs, and fat from logged meals. A 7-day bar chart displays calorie trends. All data reads from Firestore without any MyFitnessPal API call.
Common use cases
Nutrition history viewer from exported MFP data
A wellness coach app that imports a client's MyFitnessPal CSV export into Firestore, displays a 30-day macro history, and charts calorie trends using FlutterFlow's built-in chart widgets. The coach can annotate dates and compare intake against fitness goals stored in the same Firestore collection.
Build a FlutterFlow screen that reads a user's uploaded nutrition history from Firestore and displays daily calorie and macro totals in a line chart grouped by week.
Copy this prompt to try it in FlutterFlow
Live food search and meal logger with Nutritionix
A diet-tracking app where users type a food name, call the Nutritionix API (via a Cloud Function proxy) to get macros and calories, and log the result to a personal Firestore meals collection. A daily summary page totals calories, protein, carbs, and fat from the logged entries.
Build a FlutterFlow food-search screen that calls a Cloud Function to query Nutritionix by food name, shows a list of results with calories, and lets the user tap to log the item to their daily diary in Firestore.
Copy this prompt to try it in FlutterFlow
Restaurant calorie estimator
A quick-lookup tool that lets users search branded restaurant items (McDonald's, Chipotle, etc.) by name via the Nutritionix branded food endpoint, see serving-size breakdowns, and save favourite meals to their Firestore profile for fast re-logging on repeat visits.
Build a FlutterFlow screen that searches Nutritionix for restaurant branded items, shows a result card with name, serving size, and calorie count, and includes a Save to Favourites button that writes to Firestore.
Copy this prompt to try it in FlutterFlow
Troubleshooting
The API Call to the Cloud Function returns a 403 or 401 error
Cause: The Cloud Function may require authentication by default (Firebase functions can be set to require an auth token), or the Nutritionix credentials stored in environment variables haven't been saved correctly.
Solution: In the Firebase console, go to Cloud Functions → your function → Permissions and ensure the function is invocable by allUsers (for unauthenticated calls from your app) or configure FlutterFlow to pass a Firebase auth token in the request header. Also double-check that the environment variables NUTRITIONIX_APP_ID and NUTRITIONIX_APP_KEY are set and that you re-deployed the function after adding them.
XMLHttpRequest error on web publish but the call works in FlutterFlow Test Mode
Cause: FlutterFlow's Test Mode proxies all API calls through FlutterFlow's own servers, masking CORS issues. Once your app is published to web, browser CORS rules apply. If you accidentally pointed the API Group at Nutritionix directly (instead of your Cloud Function), the browser blocks the request.
Solution: Confirm that your API Group's Base URL points at your Cloud Function URL, not at trackapi.nutritionix.com. The Cloud Function must also return the CORS headers (Access-Control-Allow-Origin: *) for cross-origin requests — the example code in Step 2 already includes this.
The food search returns empty results or a 400 error from Nutritionix
Cause: The natural-language endpoint requires a valid text query. An empty string, a very short query (like a single letter), or a query in a language not supported well by Nutritionix may return an error or an empty `foods` array.
Solution: Add a minimum-length check in FlutterFlow before calling the API: add a Condition action before the API Call action that checks `foodQueryField.value.length >= 3`. Show an inline warning message if the field is too short. Also confirm the body is sent as JSON (Content-Type: application/json) and the `query` field name matches exactly what the proxy expects.
CSV data imported to Firestore shows wrong macro values or garbled characters
Cause: MyFitnessPal CSV exports use specific column names and may include UTF-8 characters for special food names. If the CSV parser or Firestore write logic maps the wrong columns, numeric fields can appear as empty strings or NaN.
Solution: Open the exported CSV in a spreadsheet first to confirm the column order: Date, Meal, Calories, Carbohydrates, Fat, Protein, Sodium, Sugar. Ensure your parser reads columns by name rather than index number, and cast numeric strings to Double before storing in Firestore. Filter out the header row and any Totals summary rows that MFP includes at the bottom.
Best practices
- Never scrape MyFitnessPal or use unofficial undocumented endpoints — they violate terms of service and break without notice
- Always proxy Nutritionix credentials through a Cloud Function or Edge Function; never put app ID or app key in Dart or API Call headers
- Set the Access-Control-Allow-Origin header in your Cloud Function so the integration works on web builds as well as mobile
- Cache Nutritionix results in Firestore for commonly searched foods to reduce API calls and improve response time on repeat queries
- Communicate clearly to users that CSV-imported data is a point-in-time snapshot — add the import date as metadata so they know when it was last refreshed
- Use YYYY-MM-DD date strings for daily meal logs in Firestore to keep querying and grouping simple across timezones
- Add a minimum character count check before firing the Nutritionix search to avoid empty-query API errors
- Design around the user's own Firestore data as the source of truth — this gives you full control over data structure and offline access regardless of whether Nutritionix or MFP changes their terms
Alternatives
Fitbit offers a live self-serve OAuth 2.0 API for activity, sleep, and heart-rate data — a better choice if your users wear a Fitbit device and you need real-time synced fitness data rather than nutrition logging.
HealthKit on iOS stores nutrition data that users log from any app (including MyFitnessPal), so a Custom Action reading HealthKit nutrition types gives you aggregated food data on iPhone without needing any third-party API.
On Android, Health Connect (the modern Google Fit replacement) can aggregate nutrition data logged by other apps, giving you device-level nutrition history via a Custom Action without calling any REST API.
Frequently asked questions
Can I still use the old MyFitnessPal API endpoints I found in a 2018 blog post?
No. MyFitnessPal deprecated and shut down its public API in 2019. Any old endpoints you find in tutorials are either completely broken or point to unofficial scraping targets that violate the platform's terms of service. Building on these will result in silent failures and potential account bans. Use Nutritionix or another active nutrition API instead.
Is Nutritionix free to use?
Nutritionix has a free developer tier that allows a limited number of API calls per day — check developer.nutritionix.com for current limits. For production apps with many users, you'll likely need a paid plan. Because credits are metered, caching results in Firestore for common food searches is strongly recommended to stay within your quota.
Will the CSV import path keep syncing automatically?
No. The CSV export from MyFitnessPal is a one-time snapshot of the user's diary up to the export date. Users would need to export again and re-upload to get fresh data. If real-time nutrition tracking is important to your app, the Nutritionix live integration (Path B) is a better fit.
Why do I need a Cloud Function if Nutritionix has a free tier — can I just put the key in the app?
FlutterFlow compiles to a Flutter app that runs on the user's device. Any key you put in an API Call header or in Dart code ships inside the compiled APK or web bundle, where it can be extracted with standard tools in minutes. A Cloud Function proxy keeps the key on a server you control, so even if someone decompiles your app, they find nothing useful. This is especially important with metered APIs where a leaked key can quickly accumulate charges.
Can I build a barcode scanner to look up food instead of typing?
Yes. Nutritionix also has a barcode lookup endpoint (`/v2/search/item?upc={barcode}`). In FlutterFlow, you can add a barcode scanning Custom Action using the `mobile_scanner` pub.dev package, then pass the scanned UPC to your Cloud Function proxy to look up the product's nutrition data — a much faster UX than typing for packaged food.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation