Skip to content
Get the app

Free nutrition API

A free, read-only JSON API over the same food data as the CalorTracker food database: calories, protein, carbs, fat, 31 nutrients in all per 100 g, and the household portions USDA weighs, for every food that has a page. There is no key to request and no account to create. The one condition is a visible credit wherever you show the data; the terms say exactly what.

Endpoints

The base URL is https://calortracker.com/api/v1. Every endpoint answers GET (and HEAD) with JSON, and every successful body carries an attribution and a license object next to the data.

RequestWhat it returns
/foods/<slug>One food in full. The slug is the last part of the food's page URL: banana for /nutrition/banana.
/foods?q=<words>&limit=<n>A search, best match first, the same ranking as the search box on the food database. limit is 1 to 50, 10 if left out.
/foods?limit=<n>&offset=<n>Every food, A to Z by name, a page at a time: limit 1 to 50 (20 if left out), offset 0 to 10,000. meta.next is the URL of the next page, and is absent on the last.

Search words are matched against food names and other names people use (prawns, courgette, porridge), at most 64 characters of letters, digits, spaces and common punctuation. A search returns only the short form of each food; follow its apiUrl for the rest. Parameters other than these are refused rather than ignored, and each may appear once.

Example: one food

curl https://calortracker.com/api/v1/foods/banana
{
  "data": {
    "slug": "banana",
    "name": "Banana",
    "category": "fruits",
    "url": "https://calortracker.com/nutrition/banana",
    "per100g": {
      "energyKcal": 89,
      "proteinG": 1.09,
      "fatG": 0.33,
      "saturatedFatG": 0.112,
      "monounsaturatedFatG": 0.032,
      "polyunsaturatedFatG": 0.073,
      "cholesterolMg": 0,
      "carbsG": 22.84,
      "fiberG": 2.6,
      "sugarsG": 12.23,
      "sodiumMg": 1,
      "potassiumMg": 358,
      "calciumMg": 5,
      "ironMg": 0.26,
      "magnesiumMg": 27,
      "phosphorusMg": 22,
      "zincMg": 0.15,
      "vitaminARaeUg": 3,
      "vitaminCMg": 8.7,
      "vitaminDUg": 0,
      "vitaminEMg": 0.1,
      "vitaminKUg": 0.5,
      "vitaminB6Mg": 0.367,
      "vitaminB12Ug": 0,
      "folateDfeUg": 20,
      "thiaminMg": 0.031,
      "riboflavinMg": 0.073,
      "niacinMg": 0.665,
      "caffeineMg": 0,
      "alcoholG": 0,
      "waterG": 74.91
    },
    "portions": [
      {
        "label": "1 cup, mashed",
        "grams": 225
      },
      {
        "label": "1 cup, sliced",
        "grams": 150
      },
      {
        "label": "1 extra small (less than 6\" long)",
        "grams": 81
      },
      {
        "label": "1 small (6\" to 6-7/8\" long)",
        "grams": 101
      },
      {
        "label": "1 medium (7\" to 7-7/8\" long)",
        "grams": 118
      },
      {
        "label": "1 large (8\" to 8-7/8\" long)",
        "grams": 136
      },
      {
        "label": "1 extra large (9\" or longer)",
        "grams": 152
      },
      {
        "label": "1 NLEA serving",
        "grams": 126
      }
    ],
    "source": {
      "name": "USDA FoodData Central",
      "fdcId": 173944,
      "dataType": "sr_legacy_food",
      "description": "Bananas, raw",
      "release": "FoodData Central SR Legacy 2018-04",
      "retrievedOn": "2026-10-20",
      "energySource": "energy",
      "url": "https://fdc.nal.usda.gov/fdc-app.html#/food-details/173944/nutrients"
    },
    "license": "CC0-1.0"
  },
  "units": {
    "energyKcal": "kcal",
    "proteinG": "g",
    "fatG": "g",
    "saturatedFatG": "g",
    "monounsaturatedFatG": "g",
    "polyunsaturatedFatG": "g",
    "cholesterolMg": "mg",
    "carbsG": "g",
    "fiberG": "g",
    "sugarsG": "g",
    "sodiumMg": "mg",
    "potassiumMg": "mg",
    "calciumMg": "mg",
    "ironMg": "mg",
    "magnesiumMg": "mg",
    "phosphorusMg": "mg",
    "zincMg": "mg",
    "vitaminARaeUg": "µg",
    "vitaminCMg": "mg",
    "vitaminDUg": "µg",
    "vitaminEMg": "mg",
    "vitaminKUg": "µg",
    "vitaminB6Mg": "mg",
    "vitaminB12Ug": "µg",
    "folateDfeUg": "µg",
    "thiaminMg": "mg",
    "riboflavinMg": "mg",
    "niacinMg": "mg",
    "caffeineMg": "mg",
    "alcoholG": "g",
    "waterG": "g"
  },
  "attribution": {
    "text": "Data: USDA FoodData Central via CalorTracker",
    "url": "https://calortracker.com/developers",
    "required": true,
    "terms": "https://calortracker.com/developers#terms"
  },
  "license": {
    "data": "CC0-1.0",
    "name": "CC0 1.0 Universal (Public Domain Dedication)",
    "url": "https://creativecommons.org/publicdomain/zero/1.0/",
    "source": {
      "name": "USDA FoodData Central",
      "url": "https://fdc.nal.usda.gov/"
    }
  }
}

per100g holds every nutrient per 100 grams of the food as USDA describes it (source.description says raw or cooked). Each key ends in its unit, and units spells them out. A nutrient USDA did not report is sent as an empty value, not a number, and never as 0: check for a number before you use one. portions are USDA's household measures with their weight in grams, so the nutrients in one portion are the per-100 g value times grams / 100. source.fdcId and source.url lead to the FoodData Central record every figure was read from.

curl "https://calortracker.com/api/v1/foods?q=prawns&limit=2"
{
  "data": [
    {
      "slug": "shrimp",
      "name": "Shrimp",
      "category": "fish-seafood",
      "per100g": {
        "energyKcal": 85,
        "proteinG": 20.1,
        "carbsG": 0,
        "fatG": 0.51
      },
      "fdcId": 175179,
      "url": "https://calortracker.com/nutrition/shrimp",
      "apiUrl": "https://calortracker.com/api/v1/foods/shrimp",
      "matchedAlias": "prawns"
    },
    {
      "slug": "cooked-shrimp",
      "name": "Shrimp (Cooked)",
      "category": "fish-seafood",
      "per100g": {
        "energyKcal": 119,
        "proteinG": 22.78,
        "carbsG": 1.52,
        "fatG": 1.7
      },
      "fdcId": 171971,
      "url": "https://calortracker.com/nutrition/cooked-shrimp",
      "apiUrl": "https://calortracker.com/api/v1/foods/cooked-shrimp",
      "matchedAlias": "prawns"
    }
  ],
  "meta": {
    "query": "prawns",
    "limit": 2,
    "count": 2
  },
  "attribution": {
    "text": "Data: USDA FoodData Central via CalorTracker",
    "url": "https://calortracker.com/developers",
    "required": true,
    "terms": "https://calortracker.com/developers#terms"
  },
  "license": {
    "data": "CC0-1.0",
    "name": "CC0 1.0 Universal (Public Domain Dedication)",
    "url": "https://creativecommons.org/publicdomain/zero/1.0/",
    "source": {
      "name": "USDA FoodData Central",
      "url": "https://fdc.nal.usda.gov/"
    }
  }
}

matchedAlias appears when a food was found by another name than its own, as here. The list looks the same, with meta.total and meta.next:

curl "https://calortracker.com/api/v1/foods?limit=2&offset=0"
{
  "data": [
    {
      "slug": "two-percent-milk",
      "name": "2% Milk",
      "category": "eggs-dairy",
      "per100g": {
        "energyKcal": 50,
        "proteinG": 3.3,
        "carbsG": 4.8,
        "fatG": 1.98
      },
      "fdcId": 171267,
      "url": "https://calortracker.com/nutrition/two-percent-milk",
      "apiUrl": "https://calortracker.com/api/v1/foods/two-percent-milk"
    },
    {
      "slug": "acorn-squash",
      "name": "Acorn Squash",
      "category": "vegetables",
      "per100g": {
        "energyKcal": 56,
        "proteinG": 1.12,
        "carbsG": 14.58,
        "fatG": 0.14
      },
      "fdcId": 169293,
      "url": "https://calortracker.com/nutrition/acorn-squash",
      "apiUrl": "https://calortracker.com/api/v1/foods/acorn-squash"
    }
  ],
  "meta": {
    "total": 461,
    "limit": 2,
    "offset": 0,
    "next": "https://calortracker.com/api/v1/foods?limit=2&offset=2"
  },
  "attribution": {
    "text": "Data: USDA FoodData Central via CalorTracker",
    "url": "https://calortracker.com/developers",
    "required": true,
    "terms": "https://calortracker.com/developers#terms"
  },
  "license": {
    "data": "CC0-1.0",
    "name": "CC0 1.0 Universal (Public Domain Dedication)",
    "url": "https://creativecommons.org/publicdomain/zero/1.0/",
    "source": {
      "name": "USDA FoodData Central",
      "url": "https://fdc.nal.usda.gov/"
    }
  }
}

From a web page

Responses allow any origin (Access-Control-Allow-Origin: *), so a page can call the API directly. Send no credentials; none are needed.

const res = await fetch("https://calortracker.com/api/v1/foods?q=greek%20yogurt&limit=5");
const { data, attribution } = await res.json();
// Show attribution.text, linked to attribution.url, wherever data appears.

Limits and caching

  • Each IP address may make 60 requests a minute and 1,000 requests an hour; an IPv6 address counts with the rest of its /64 network. Over that, the answer is 429 with a Retry-After header giving the seconds to wait. Waiting it out restores the full allowance.
  • Responses carry Cache-Control and an ETag. Keep what you fetch and send If-None-Match when you ask again; an unchanged answer is a short 304. Foods change rarely: when a batch of new foods goes live or a value is corrected, listed on the food database changelog.
  • To copy every food at once, read the list a page of 50 at a time, slowly, or use the open dataset, the same data as CSV and JSON files, once it is published.

Errors

An error is a JSON body { "error": { "code", "message", "docs" } } with the matching status: 400 for a bad slug or parameter (codes invalid_slug, invalid_parameter, unknown_parameter, duplicate_parameter, query_too_long), 404 for a food or path that does not exist (not_found), 405 for any method but GET, HEAD and OPTIONS, and 429 for the rate limit (rate_limited). A food that is scheduled but not yet published is a 404 until the day its page opens.

Terms of use

  1. Attribution is required. Wherever you show or publish data from the API, show this line, with CalorTracker linked to https://calortracker.com/developers:
    Data: USDA FoodData Central via CalorTracker
    In an app, put it on the screen that shows the data or on an about screen it links to. Every response repeats the line and the link in its attribution object.
  2. Free and read-only. There is no charge, no key and no paid tier. The API serves the published food data and nothing else: no accounts, no user data, nothing written.
  3. No service level. The API is provided as is, without warranty, uptime commitment or support obligation. We may change the limits, add fields, or pause or end the API. Breaking changes go to a new version path rather than into /api/v1, and we will say so on this page first.
  4. Fair use. Stay within the limits and do not work around them by spreading requests over many addresses. Do not present the data as CalorTracker's or USDA's endorsement of your product. We may block traffic that harms the service for others.
  5. Not medical advice. These are reference values for foods in general; a brand, a recipe or a ripeness will differ. Nothing the API returns is dietary or medical advice.

Licence and source

The numbers come from USDA FoodData Central (U.S. Department of Agriculture, Agricultural Research Service), which USDA places in the public domain under CC0 1.0 Universal (Public Domain Dedication), and the API passes them on under the same dedication. CalorTracker adds the slug, the name, the category and the page link, and changes no value. The attribution in the terms is the condition for using this service, not a claim on the data: the same figures are free from USDA directly. The page text around the numbers on our site, such as food notes, is not part of the API. How the values are chosen and checked is on how we calculate and sources.

What we keep

The API needs no account and sets no cookie. Requests reach us through Cloudflare, which protects the site and handles them under its own privacy policy. Our own servers keep no access log of API requests and do not store the addresses they come from: the rate limit counts requests in memory, never on disk, under a key that cannot be turned back into an address, and the API otherwise keeps only a count of answers by status. The one exception is the site's general security checks. A request shaped like an attack, or one from an address already blocked for abuse, is refused and recorded with its address, as anywhere else on the site.

Questions, a missing food or a wrong value: write to support@calortracker.com.