Per-Serving vs Per-100g: Making Sense of Nutrition Data Units
If you have worked with food data from more than one source, you have probably run into this problem: one database says a food has 165 calories, and another says it has 239 calories. Neither is wrong. They are just using different units — one is per serving (a specific portion size), and the other is per 100 grams.
This distinction trips up developers constantly. If your app mixes per-serving and per-100g values without realizing it, your users get wildly inaccurate nutrition totals. Here is how to handle it correctly.
Why the confusion exists
Nutrition data comes from two very different worlds.
Nutrition labels report values per serving. A serving of peanut butter is 2 tablespoons (32g). A serving of cereal is 1 cup (varies by weight). These serving sizes are defined by the manufacturer and are often based on regulatory guidelines, but they vary between brands and products.
Scientific and regulatory databases report values per 100 grams. This is a universal base that makes comparison straightforward: 100g of chicken breast vs 100g of tofu, apples to apples (or protein to protein).
When an API pulls from both worlds — branded products with per-serving labels and whole foods with per-100g lab data — you end up with a mixed bag unless the API normalizes everything to a common base.
How ChowAPI handles it
ChowAPI stores all nutrient values normalized to per 100 grams. This is the canonical representation. When you call the search or food detail endpoint, the nutrients object (calories, protein, carbs, etc.) contains per-100g values.
But we also know that per-serving values are what most users actually want to see. Nobody eats exactly 100g of peanut butter. They eat a tablespoon, or they eat a sandwich's worth.
That is why the API response includes both:
const response = await fetch(
"https://api.chowapi.dev/v1/search?q=peanut+butter&limit=1",
{ headers: { Authorization: "Bearer chow_live_your_key_here" } }
);
const { results } = await response.json();
const food = results[0];
// Per 100g (canonical, always present)
console.log(food.nutrients.calories); // 588
console.log(food.nutrients.protein); // 25.1
console.log(food.nutrient_basis); // "per_100g"
// Per serving (computed automatically when serving data exists)
console.log(food.serving); // { amount: 2, unit: "tbsp", description: "2 tbsp (32g)", gram_weight: 32 }
console.log(food.nutrients_per_serving.calories); // 188
The nutrient_basis field tells you explicitly that the base nutrient values are per 100g. The serving object gives you the serving details, and nutrients_per_serving provides pre-computed per-serving values so you don't have to do the math yourself.
Displaying it correctly in your app
For most consumer-facing apps, you want to display per-serving values. That is what users expect — it matches what they see on the package. Here is a practical pattern:
function displayNutrition(food) {
const hasServing = Object.keys(food.nutrients_per_serving).length > 0;
return {
label: hasServing
? `Per serving (${food.serving.description})`
: "Per 100g",
calories: hasServing ? food.nutrients_per_serving.calories : food.nutrients.calories,
protein: hasServing ? food.nutrients_per_serving.protein : food.nutrients.protein,
carbs: hasServing ? food.nutrients_per_serving.carbs : food.nutrients.carbs,
fat: hasServing ? food.nutrients_per_serving.fat : food.nutrients.fat,
};
}
If serving data is available, use nutrients_per_serving for pre-computed values. If not, fall back to the per-100g nutrients object. The user always knows what base they are looking at.
For apps that need custom portions — "I ate 150g of rice" — the per-100g base makes the math trivial:
function customPortion(food, grams) {
const factor = grams / 100;
return {
calories: Math.round(food.nutrients.calories * factor),
protein: Math.round(food.nutrients.protein * factor * 10) / 10,
carbs: Math.round(food.nutrients.carbs * factor * 10) / 10,
fat: Math.round(food.nutrients.fat * factor * 10) / 10,
};
}
// User ate 150g of rice
const rice = results[0]; // per-100g values from API
const portion = customPortion(rice, 150);
Common mistakes to avoid
Mixing bases in totals. If you add a per-100g value and a per-serving value without converting, your daily totals will be meaningless. Always normalize to one base before summing.
Assuming serving size is always present. Whole foods and generic items often do not have a standardized serving size. Always check for serving_weight_g before calculating.
Rounding too aggressively. Per-100g values are precise. Round only at the display layer, not during intermediate calculations. Rounding 0.3g of fat per serving across 10 foods can add up to a meaningful error.
Ignoring the nutrient_basis field. Even if you know ChowAPI returns per-100g, check the field programmatically. Defensive code prevents bugs when your data sources evolve.
The bottom line
Per-100g is the universal base for nutrition math. Per-serving is what users expect to see. A good nutrition API gives you both and makes the relationship between them explicit.
ChowAPI normalizes everything to per-100g and includes serving size metadata so you can convert with a single multiplication. The nutrient_basis field removes ambiguity. No guessing, no mixed units, no silently wrong totals.
Ready to get clean, consistent nutrition data? Get your API key and check the quickstart guide.