Stop Letting Ingredient Parsers Rewrite the Evidence
Two fresh Open Food Facts parser changes reveal why recipe and food-data APIs should preserve quantities, footnotes, modifiers, and source spans as intermediate claims before resolving ingredients or calculating nutrition.
Two parser fixes expose one architectural boundary
On August 13, 2026, Open Food Facts merged two ingredient-parser changes that look unrelated. One expanded quantity recognition for recipe-like phrases such as “one pinch of salt,” “one kilo of flour,” and “5 cups of flour.” It moved unit matching onto the project's multilingual units taxonomy, converted words such as “one” into numeric values, and added normalized volume and mass outputs where supporting data existed.
The other change taught the parser that */ or **/ can introduce a footnote explanation on a Swedish ingredient label. In the supplied product fixture, symbols distinguish organically grown herbs from a description of low-sodium unrefined sea salt. Without recognizing the separator, explanatory text can be mistaken for another ingredient or attached to the wrong one.
This blog has already covered multilingual label grammar, ingredient normalization, form states, density conversions, and extraction evaluation. Repeating “parsers need localized rules” would add little. The stronger combined signal is about architecture: parsing should not jump directly from source text to canonical ingredients. It should first produce an evidence-preserving layer of typed claims, because quantity phrases and footnotes modify different scopes and support different downstream decisions.
The practical thesis is that recipe and food-data APIs should treat parsing as compilation: preserve tokens and relationships in an intermediate representation, then resolve identities, conversions, nutrition, and product behavior in separate, versioned passes.
A cleaned ingredient string is a lossy output
Many pipelines effectively do this:
source text -> cleaned string -> ingredient ID
That is attractive because the final object appears simple. It is also where information disappears.
Consider one pinch of salt. The parser may identify salt, turn one into 1, map pinch to a unit, and convert that unit into a volume. Open Food Facts' fresh taxonomy change models a pinch as 1 ml for salt and spices while explicitly noting that no universal definition exists. A later density step may turn volume into mass. Each step is a distinct assertion:
- the source contains the textual quantity “one”;
- “one” was interpreted as the number 1 under an English rule;
- “pinch” matched a unit concept;
- this implementation uses a 1 ml conventional value;
- a food-specific density may support a gram conversion.
Flattening those assertions into quantity_g: 1 makes the result look measured when it is actually derived through conventions. The same problem appears with cups. The fresh Open Food Facts unit entry defaults a cup to the 240 ml US legal cup and documents that this differs from the roughly 237 ml US customary cup and the 250 ml metric cup used in several markets.
The footnote case loses a different kind of evidence. A symbol can link one or several ingredients to a qualifier such as organic status, while another symbol links salt to a low-sodium description. Removing punctuation before recording those links can turn scoped claims into global labels—or turn explanatory text into ingredients.
Parse into claims before resolving entities
A more durable pipeline has explicit stages:
source text
-> lexical spans
-> typed parse claims
-> canonical entities and relationships
-> derived quantities and analyses
-> product decisions
The intermediate claims should remain close to what the source actually says. They can be rule-produced or model-produced, but they should preserve spans, locale, scope, and confidence.
{
"source": {
"text": "one pinch of salt",
"locale": "en",
"field": "recipeIngredient"
},
"claims": [
{
"id": "claim:q1",
"type": "quantity_expression",
"span": { "start": 0, "end": 9, "text": "one pinch" },
"amount": { "raw": "one", "normalized": 1 },
"unit": {
"raw": "pinch",
"conceptId": "unit:pinch"
},
"appliesTo": "claim:i1",
"ruleId": "en-text-number-plus-unit",
"ruleVersion": "2026-08-13"
},
{
"id": "claim:i1",
"type": "ingredient_mention",
"span": { "start": 13, "end": 17, "text": "salt" },
"entityCandidate": "ingredient:salt"
}
]
}
A conversion service can then add a derived claim rather than overwriting the source quantity:
{
"type": "normalized_quantity",
"value": 1,
"unit": "ml",
"derivedFrom": "claim:q1",
"method": "conventional_unit_mapping",
"assumptions": ["pinch=1ml"],
"conversionVersion": "2026-08-13"
}
This shape is more verbose internally, but the public API can still provide a compact view. The detailed representation exists for audit responses, reprocessing, disputed nutrition totals, editor tools, and safety-sensitive clients.
Quantity, identity, and qualifiers have different scope
The two fresh changes matter together because they show that adjacency is not enough to determine meaning. A parser must represent relationships.
| Parsed element | Likely scope | Safe downstream use | Common failure if flattened |
|---|---|---|---|
5 cups |
One ingredient mention | Scaling; conversion after locale and ingredient checks | Wrong cup standard or density |
one pinch |
One ingredient mention | Display; approximate conversion with disclosed convention | Approximation presented as measured mass |
93% |
One ingredient or composition claim | Composition validation and ranking | Treated as recipe quantity |
* after several herbs |
Referenced set of ingredients | Attach a shared production qualifier | Label applied to every ingredient |
**/ low-sodium… |
Referenced ingredient or phrase | Preserve a scoped product description | Description parsed as a new ingredient |
| text after a separator | Depends on grammar and locale | Resolve only after relation parsing | Silently discarded as “noise” |
That distinction is useful beyond package labels. Recipe lines contain the same classes of ambiguity:
2 x 400 g cans tomatoeshas count, package size, and ingredient quantity;salt, to tastehas an unbounded instruction-like modifier, not a numeric zero;1 cup flour, plus more for dustinghas a measured portion and an additional purpose-scoped portion;1 bunch parsley, dividedsignals later allocation across steps;3 eggs, separatedchanges component structure without changing ingredient identity.
A canonical ingredient ID cannot express those relationships by itself. Nor should an LLM be asked to hide them inside one polished JSON field.
Keep conversions reversible and policy-aware
Once the intermediate layer exists, conversion policy becomes an explicit product decision instead of a parser side effect.
For a cup, the service may need locale, author convention, source market, and recipe corpus policy. If none is known, the API can retain 1 cup while returning a bounded or policy-selected milliliter estimate. For a pinch, it should distinguish an author-entered approximation from a laboratory measurement. For flour or oil, volume-to-mass conversion needs the resolved ingredient form and a density record with provenance.
A useful derived quantity therefore carries:
- original amount and unit;
- normalized amount and unit;
- conversion method;
- convention or locale policy;
- density source when used;
- uncertainty or range;
- conversion version;
- links to the source claims.
This prevents three operational failures. First, a policy update can selectively recompute affected records. Second, clients can avoid displaying false precision. Third, nutrition and grocery systems can choose different tolerance levels: a shopping list may accept “one pinch,” while sodium calculations should surface that the amount is approximate.
Design reprocessing around impact, not parser success
Parser tests usually ask whether an example now parses. API operators also need to ask what changed downstream.
When deploying a new quantity or footnote rule, compare old and new claim graphs and classify the impact:
- Tokenization only: spans changed, but resolved facts did not.
- Relationship change: a qualifier now attaches to a different ingredient set.
- Identity change: text previously treated as an ingredient is now a footnote, or vice versa.
- Quantity change: a unit is newly recognized or mapped under a different convention.
- Derived-data change: nutrition, cost, sustainability, allergen, or dietary analyses changed.
- Product change: search eligibility, warnings, grocery totals, or meal-plan ranking changed.
The last three deserve targeted review even when parser tests are green. A newly recognized 25 fl oz can fix an ingredient identity and alter percentage estimates. A footnote fix can add an organic qualifier or remove a false ingredient. Those are data migrations from a client's perspective.
Failure modes worth putting in fixtures
A serious ingredient parser should test more than happy-path extraction:
- number words that overlap ordinary ingredient text;
- singular and plural localized units;
- decimals written with comma or point separators;
- ranges such as
10–12 g; - count-plus-package expressions;
- cups with unknown regional convention;
- imprecise units such as pinch, handful, dash, and “to taste”;
- footnote symbols repeated across multiple ingredients;
- symbol explanations separated by
:,=,/, or localized punctuation; - literal asterisks or slashes that are not footnotes;
- nested sub-ingredients and percentages;
- OCR that inserts or removes punctuation;
- mixed-language ingredient lines;
- qualifiers whose scope is ambiguous.
For each fixture, assert the source spans and claim relationships, not only the final ingredient array. Otherwise a parser can produce the expected IDs while silently losing the evidence needed to explain them.
A decision checklist for API teams
Before accepting a new parser output into a recipe, nutrition, or grocery API, ask:
- Can every normalized fact point back to exact source text?
- Are quantity recognition and unit conversion separate operations?
- Does the model preserve the original unit even after normalization?
- Are locale and unit convention explicit when cups or similar measures are used?
- Can qualifiers attach to one ingredient, a referenced set, a sub-list, or the whole source?
- Are approximate culinary units distinguishable from measured values?
- Can a rule update trigger selective reprocessing by locale, unit, or grammar feature?
- Do diffs report changes to relationships and derived product behavior?
- Can compact API responses be expanded into evidence-rich audit responses?
- Do AI-generated and rule-parsed ingredients enter the same claim-validation pipeline?
This is where a structured Recipe API earns its value. The goal is not to expose parser internals in every response. It is to ensure that recipe quantities, ingredient identities, nutrition calculations, grocery merges, and AI outputs are backed by recoverable evidence rather than irreversible cleanup.
Sources
- Open Food Facts pull request, merged August 13, 2026: Improve units support for ingredient parsing of recipes such as “one pinch of salt”.
- Open Food Facts merge commit, August 13, 2026: feat: improve units support for ingredients parsing of recipes.
- Open Food Facts pull request, merged August 13, 2026: Handle
*/in ingredient lists. - Open Food Facts merge commit, August 13, 2026: feat: handle
*/in ingredient lists. - Background reference: Schema.org
recipeIngredient.
Start Building
One consistent schema on every response. Get a free key and ship in minutes.