Plain-language guide · no code required
NUTRI-SCORE

How nutritious is this food?

Nutri-Score is the nutrition-quality grade — an A to E letter (and a 0–100 number) based purely on the nutrition facts: calories, sugar, saturated fat, salt, fiber, protein, and fruit/veg content. It answers "is this nutritionally good?" — a different question from how processed it is or what additives it contains.

The A–E scale

A
Excellent · 85–100
B
Good · 65–84
C
Average · 40–64
D
Poor · 15–39
E
Bad · 0–14

The core idea: bad points minus good points

It's a tug-of-war. Each food earns negative points for things to limit and positive points for things to encourage. Subtract one from the other and you get a raw score — lower is better — which maps to a letter and a 0–100 number.

Negative points (0–10 each)

Calories · Sugar · Saturated fat · Salt (sodium). The more a food has, the more points it racks up.

Positive points

Fiber (0–5) · Protein (0–5) · Fruit/veg/nuts (0, 1, 2 or 5). These pull the score back down toward "good."

Raw score = negatives − positives. A fresh vegetable lands deep in the negatives (a great A); a sugary, salty snack piles up positives-can't-save-it points (an E).

The point ladders — the actual lookup tables

A nutrient earns one more point for each threshold it crosses. These are per serving (see "what makes ours different" below).

Negative — points for what to limit
Points →135710
Energy (kcal)60180300420600
Sugars (g)3.410172334
Sat fat (g)0.61.83.04.27.0
Sodium (mg)70210345505805
Positive — points for what to encourage
Points →12345
Fiber (g)0.71.42.12.83.5
Protein (g)1.22.43.64.86.0
Fruit/veg/nuts40%60%80%

Energy/sugar/sat-fat/sodium ladders have 10 rungs; abbreviated here for readability.

What makes Baseline's version different

Standard EU Nutri-Score is a blunt, population-level tool. We keep its trusted backbone but fix the places it misleads an individual shopper:

  • 1
    Per serving, not per 100g. We score what actually enters your body. The standard version judges 100g of everything — which makes a tiny sprinkle of parmesan look like a health food and over-penalizes large healthy portions. We recalibrated every threshold to real serving sizes.
  • 2
    Source-quality overlays. The standard score counts grams of sat fat, sugar, and salt blindly. We adjust the points by where the nutrient comes from — sat fat from yogurt isn't treated like sat fat from a hot dog; sugar from whole fruit isn't treated like added syrup. The adjustment is dampened by half, so it nudges the grade rather than hijacks it.
  • 3
    Fairer with missing data. If a label doesn't list fiber or protein, we give a neutral median credit instead of silently scoring it zero — a missing number shouldn't tank a product.
  • 4
    Smart beverage & water handling. "Chocolate Milk" is scored as a drink, "Milk Chocolate" as a solid — we read the last word of the name. Plain water is always an A.
  • 5
    A "disagreement" flag. When the blunt grade and the source-quality view diverge (e.g. an A-grade product whose fat comes from processed meat), we surface it instead of hiding it.

The five adjustment modules

This is the heart of what makes our score ours. Plain Nutri-Score counts grams. Each adjustment module asks a better question — where did this nutrient come from? — and scales that nutrient's points up or down by a source-quality multiplier.

Two important rules apply to all five:

  • Multiplier meaning: for the bad-point modules (fat, sugar, sodium), >1.0 means a worse source (more penalty), <1.0 means a better source (less penalty). For the good-point modules (protein, fiber), <1.0 shrinks the credit when the source is low-quality.
  • Dampened by half: every multiplier is softened — 1.0 + (multiplier − 1.0) × 0.5 — so an adjustment nudges the grade rather than dominating it. It's an opinion, held lightly.
adjusts SAT-FAT points Saturated Fat module

Sat fat from yogurt isn't the same as sat fat from a hot dog. Rates the source across food matrix, fatty-acid profile and processing (T1 best → T6 worst).

Source tier×Examples
T1 Fermented dairy0.12yogurt, kefir, skyr
T2 Cheese0.20cheddar, mozzarella
T3 Whole milk0.39milk, cream-top
T4 Unprocessed meat0.89–0.92beef, pork, poultry
T5 Isolated fats1.17–1.46butter, coconut, palm
T6 Processed / hydrogenated1.80–1.88bacon, sausage, trans fat
adjusts SUGAR points Sugar module

Sugar locked inside whole fruit is metabolically different from added syrup or a soft drink. Rated by delivery matrix × sugar origin.

Source×Examples
Whole fruit / vegetable0.00intrinsic, intact matrix
Dairy / whole grain / dried fruit0.30lactose, concentrated intrinsic
Juice / honey / purée0.60freed but with co-nutrients
Added sugar1.00the reference point
Sugar-sweetened beverage1.40soda — liquid, no matrix
adjusts SODIUM points Sodium module

Salt in kimchi (fermentation, probiotics) isn't salt in a nitrite-cured hot dog. Recent evidence says food context matters more than total grams.

Context tier×Examples
T1 Whole / fermented0.20–0.30miso, kimchi, sauerkraut
T2 Preserved nutrient-dense0.40–0.55sardines, smoked salmon, aged cheese
T3 Standard added salt0.70–0.85bread, sauces, baking soda
T4 Unknown1.00conservative fallback
T5 Ultra-processed additives1.20–1.40nitrites, phosphates, MSG-heavy
adjusts PROTEIN credit Protein module

Stops a "protein cookie" earning the same credit as a chicken breast. The same whey isolate gets different credit depending on the product it's in.

Tier×Examples
T1 Whole-food complete protein1.00eggs, fish, meat, dairy, tofu
T2 Quality isolate, clean product0.85whey/pea in a protein shake
T3 Added protein (gaming)0.50whey in cookies, candy, bars
T4 Protein claim, <5g0.00label claim, no substance
adjusts FIBER credit Fiber module

12g of fiber from lentils isn't 12g of chicory-root inulin dusted onto a protein bar. Rated by how whole the fiber source is.

Tier×Examples
T1 Whole-food intrinsic1.00legumes, veg, fruit, whole grains
T2 Minimally processed0.80oat fiber, psyllium, bran, chia
T3 Added functional fiber0.50inulin, chicory, soluble corn fiber
T4 Synthetic / negligible0.25MCC, modified cellulose

Look up any ingredient or food

Every term the five modules classify — not just examples.

All classified terms across the five adjustment modules. Search a food or pick a module to audit exactly which tier and multiplier it lands in. Value is the source multiplier before the ×0.5 dampening.

Known limitation: most matches are on the product category, not the ingredients

A term tagged category is matched against the product's name/category — so "lemonade" is assumed to be a sugar-sweetened beverage even if it's a diet version. A term tagged ingredient is matched against the actual ingredient list and is far more reliable. Today ~87% of terms are category-based (sat-fat, sugar & sodium are 100% category; fiber is mostly ingredient). Use the filter below to inspect the category-based assumptions.

Input:
TermModuleInputTier×Classified as

Plurals and label variants are normalized when we scan a product. If a food you'd expect is missing or mis-tiered, that's exactly the kind of gap to flag.

Show the actual math — for anyone who wants the real mechanics ▼ expand
1 · Tally the points

Count how many thresholds each nutrient crosses (from the ladders above). N = energy + sugar + sat fat + sodium points. P = fiber + protein + fruit/veg points.

2 · Apply source overlays (Baseline)

Before subtracting, the sat-fat / sugar / sodium points are scaled by their source quality, dampened by half:

dampened_multiplier = 1.0 + (source_penalty − 1.0) × 0.5
3 · The Nutri-Score formula

Subtract — with one classic rule: for junk-heavy foods, protein can't rescue the score (only fiber & fruit/veg can).

if N < 8:   raw = N − P
else:       raw = N − (fiber + fruit_veg)   # protein excluded
            unless fruit_veg already scores 5
4 · Grade & 0–100 (per serving)
Solid food:   A ≤ −1   B ≤ 2   C ≤ 8   D ≤ 14   E ≥ 15
Beverage:     B ≤ 1    C ≤ 4   D ≤ 7   E ≥ 8     (water = A)
raw score → piecewise map → 0–100 (higher = better)
Worked example — Greek yogurt (one 170g pot)

~100 kcal · 0g sat fat · 6g sugar · 60mg sodium · 0g fiber · 17g protein

Negatives:  energy 1 + sugar 1 + sat fat 0 + sodium 0   = 2
Positives:  fiber 0 + protein 5 (>6g) + fruit/veg 0       = 5
N = 2 (under 8) → raw = 2 − 5 = −3
−3 ≤ −1  →  Grade A  →  top of the 0–100 scale (A band)

Source of truth: food_scoring/nutriscore.py (v7, per-serving) + the overlays/ package.

How it fits with the other modules

Nutri-Score answers one question well, but not all of them. That's why it's one module among several:

Nutri-Score
Is it nutritionally good? (macros & nutrients)
Processing Score
How industrial is it? (additives & transformation)
Seed Oils
A preference filter, not a penalty

A food can be a Nutri-Score A but heavily processed (e.g. a diet soda), or a C that's totally whole (e.g. cheese). Showing them separately is more honest than mashing them into one opaque number.

Where it's still rough (we'd rather you hear it from us)

  • It only sees the nutrition panel. It can't tell whole from ultra-processed on its own — a diet soda can score well. Processing + additives are deliberately separate modules.
  • Garbage in, garbage out. If the label is missing or wrong (no serving size, no fiber), the grade leans on estimates. We credit missing data rather than punish it, but it's still a guess.
  • Per-serving can be gamed. Scoring real servings is fairer, but a deceptively small "serving size" on the label can flatter a product. We removed the old size floor and recalibrated boundaries to fight this, but it's not bulletproof.
  • The overlays are our judgment. Adjusting points by nutrient source is Baseline's addition, not part of official Nutri-Score. We dampen it by half on purpose — it's an opinion, held lightly.

Questions or disagreements? → tell Stefan and this page gets better.