Skip to content

Nutrition data

Noms stores one number per nutrient, per 100 of the food: per 100 grams for a solid, per 100 millilitres for a drink. Separately, it tells you the sizes people measure that food in. Every figure you put on screen is those two multiplied together.

This page is that multiplication, start to finish.

The idea, in plain words

Say you fetch a snack bar. Three things come back with it:

basis_unit   grams              → every value below is per 100 g
PROTEIN      10 g               → 10 g of protein in every 100 g
one serving  1 bar, 50 g        → a portion is 50 g

Read it as a single sentence:

There are 10 g of protein in every 100 g, and one bar is 50 g.

A bar is half of 100 g, so it holds half the protein: 5 g. Two bars, 10 g. Three, 15 g. Half a bar, 2.5 g.

There is no "protein per bar" field to look up, and there does not need to be one. You scale the per-100 figure by the portion you care about, and that same multiplication gives you every nutrient at every portion size. It is how a handful of stored numbers rebuilds any nutrition label you want to print.

The formula

basis_unit is doing two jobs at once, and it is the one field worth slowing down for. It tells you what the values are per (grams or milliliters), and it names the serving field to divide by:

basis_unitValues are perDivide by the serving's
"grams"100 ggrams
"milliliters"100 mlmilliliters

The field it names is never null, so that lookup always resolves.

A solid, in JSON

The same snack bar, as the API returns it, trimmed here to the three fields this page is about:

{
  "basis_unit": "grams",        // every value below is per 100 g
  "nutrients": [
    { "id": "ENERGY", "name": "Energy", "value": "400", "unit": "kcal" },
    { "id": "PROTEIN", "name": "Protein", "value": "10", "unit": "g" }
  ],
  "serving_sizes": [
    {
      "unit": "each",
      "descriptor": "bar",
      "quantity": "1",            // one bar...
      "grams": "50",              // ...and one bar weighs 50 g
      "milliliters": null,        // no volume; we don't guess one
      "is_default": true
    }
  ]
}

basis_unit is "grams", so divide by the serving's grams, which is 50:

protein per bar = 10  × 50 / 100 =   5 g
energy  per bar = 400 × 50 / 100 = 200 kcal

A drink, the same shape

Nothing about the method changes for something measured by volume. Only which field you read does:

{
  "basis_unit": "milliliters",  // every value below is per 100 ml
  "nutrients": [
    { "id": "ENERGY", "name": "Energy", "value": "60", "unit": "kcal" },
    { "id": "PROTEIN", "name": "Protein", "value": "3", "unit": "g" }
  ],
  "serving_sizes": [
    {
      "unit": "ml",
      "descriptor": null,
      "quantity": "250",          // 250 ml...
      "grams": null,              // ...of unstated weight; density is not ours to guess
      "milliliters": "250",       // ...which is, of course, 250 ml
      "is_default": true
    }
  ]
}

basis_unit is "milliliters", so divide by the serving's milliliters:

protein per bottle = 3  × 250 / 100 =   7.5 g
energy  per bottle = 60 × 250 / 100 = 150 kcal

Notice grams is null on that serving. Turning a volume into a weight needs the food's density, which we will not guess, so the dimension a food is not anchored on is best-effort and may be missing. The one basis_unit names never is.

One function, both cases

Because the unit names the field, you never branch on it:

function amountPerServing(food, nutrient, serving) {
  const basis = Number(serving[food.basis_unit]); // "grams" or "milliliters"
  return (Number(nutrient.value) * basis) / 100;
}

const serving = food.serving_sizes.find((s) => s.is_default);
const protein = food.nutrients.find((n) => n.id === "PROTEIN");
amountPerServing(food, protein, serving); // 5

Reading a serving

serving_sizes is a list. Each entry is one way people measure that food: a weight, a volume, or a countable piece:

FieldWhat it is
unitThe measure: g, ml, cup, tbsp, tsp, L, oz, fl_oz or each
quantityHow many units make this serving: 1 bar, 250 ml
descriptorNames the portion when the unit alone is not enough (bar, slice, chopped); null otherwise
gramsWhat this serving weighs, when known
millilitersWhat this serving measures by volume, when known
is_defaultThe food's primary serving. Exactly one per food

Read the portion off these fields, never off the food's name. If you show a single figure, show the serving with is_default: true. That is the reference portion the source itself treats as one serving.

Two things to watch

Each nutrient also carries its own unit (g, mg, kcal, ...), and that is independent of the food's basis_unit. basis_unit says what the value is per; nutrient.unit says what the value is measured in. Protein at "10" with unit: "g" on a grams-basis food reads: 10 grams of protein per 100 grams of food.

See a whole response

Everything above, on a real catalog row: Blue Diamond's roasted salted almonds, with the nutrient array as long as it actually is:

GET
curl -G https://api.noms.sh/v1/foods/TIgbNPnzCIjX \
  --data-urlencode "include=nutrients,serving_sizes" \
  -H "Authorization: Bearer $NOMS_KEY"
Response
200 OK
{
"data": {
"id": "TIgbNPnzCIjX",
"barcode": "00041570110645",
"name": "Roasted salted almonds",
"description": null,
"scientific_name": null,
"country_of_origin": null,
"ingredients_text": "Almonds, sunflower oil, sea salt.",
"is_foundational": false,
"basis_unit": "grams",per 100 grams → divide by serving.grams
"brand_id": "XoluRyOx9o3C",
"food_group_id": "NUTS_AND_SEEDS",
"nutrients": [
{
"id": "ADDED_SUGARS",
"name": "Sugars, added",
"value": "0.0",
"unit": "g"
},
{
"id": "ALPHA_TOCOPHEROL",
"name": "Vitamin E (alpha-tocopherol)",
"value": "25.1625",
"unit": "mg"
},
{
"id": "BIOTIN",
"name": "Biotin",
"value": "43.214286",
"unit": "mcg"
},
{
"id": "CALCIUM",
"name": "Calcium, Ca",
"value": "285.714286",
"unit": "mg"
},
{
"id": "CARBOHYDRATE",
"name": "Carbohydrate, by difference",
"value": "17.857143",
"unit": "g"
},
{
"id": "CHOLESTEROL",
"name": "Cholesterol",
"value": "0.0",
"unit": "mg"
},
],
"serving_sizes": [
{
"unit": "g",
"descriptor": null,
"quantity": "28.0",
"grams": "28.0",one serving weighs 28 g
"milliliters": null,
"is_default": true
},
{
"unit": "each",
"descriptor": "nuts",
"quantity": "28.0",
"grams": "28.0",
"milliliters": null,
"is_default": false
}
]
}
}

Same three fields, same one multiplication. 21.428571 × 28 / 100, rounded for display, is the 6 g of protein printed on the can. So is every other figure on its panel.

Next steps