DEV Community

Dietly
Dietly

Posted on • Originally published at getdietly.com

How to Handle Missing Nutrition Data Without Lying to Users

How to handle missing nutrition data without lying to users

In nutrition data, null and zero are different facts. Zero sugar means a source reported no sugar. A missing sugar field means the source did not provide a usable value. Turning both into 0 creates confident-looking totals that may be wrong.

Make unknown values explicit in the schema

Every optional nutrient should be nullable from the database through the API client and into the UI. Do not coerce missing values during JSON serialization.

type Food = {
  calories_kcal: number | null;
  protein_g: number | null;
  sugar_g: number | null;
  serving_size_g: number | null;
  serving_desc: string | null;
};
Enter fullscreen mode Exit fullscreen mode

This forces application code to decide what “unknown” means instead of accidentally treating it as arithmetic zero.

Use three states in the interface

Stored value Display Meaning
0 0 g Reported zero
null Not listed Unknown or absent
Positive number 12.4 g Reported numeric value
function nutrient(value, unit = "g") {
  return value === null ? "Not listed" : `${value} ${unit}`;
}
Enter fullscreen mode Exit fullscreen mode

Avoid replacing null with a dash when the dash is unexplained. “Not listed” is slightly longer and much clearer.

Do not total incomplete meals silently

There are two honest strategies. A strict tracker can decline to show a nutrient total when any item is unknown. A pragmatic tracker can show the sum of known values with an “incomplete” badge. What it should not do is display a complete-looking total of 0 g sugar when half the foods had no sugar field.

const known = items.filter(x => x.sugar_g !== null);
const sugar = known.reduce((sum, x) => sum + x.sugar_g, 0);
const complete = known.length === items.length;
Enter fullscreen mode Exit fullscreen mode

Normalize servings only when the denominator is known

Dietly exposes common nutrient values per 100 g. A portion calculation is simple when the consumed mass is known:

portionValue = per100gValue * gramsConsumed / 100
Enter fullscreen mode Exit fullscreen mode

But labels may provide “one bowl,” “one slice” or “one package” without a trustworthy gram weight. Do not invent a conversion. Preserve both serving_size_g and the original serving_desc, and fall back to per-100 g values when grams are unavailable.

Confidence is context, not permission to fabricate

A confidence score can help rank competing records and warn about sparse data. It should never fill missing nutrients or be presented as a probability that a label is correct. Keep the source field next to it. A community-contributed record with complete macros can still contain a typo; a sparse official label can still be accurately sparse.

Design useful empty states

  • For a missing nutrient, say “not listed by the source.”

  • For a barcode miss, offer text search or manual entry.

  • For an incomplete record, let the user choose another result.

  • For medical or allergy decisions, direct users to the physical label and qualified guidance.

Logging missingness also improves the product. Track which fields and searches most often fail without storing unnecessary personal data. That tells you whether to improve ingestion, ranking or the UI.

Preserve provenance through every transformation

Missingness becomes impossible to explain when an ingestion job drops the original unit, source and raw field. Keep the normalized value alongside enough provenance to audit it: source system, source record ID, last refresh time and, where practical, the raw serving declaration. This does not mean exposing your internal ingestion schema to every client. It means being able to answer why a value is absent or how a serving conversion was produced.

Do not merge records by filling each blank field from whichever duplicate has a number. That can create a synthetic product assembled from different package sizes, countries or reformulations. If records are combined, require evidence that they describe the same trade item and retain field-level provenance. Otherwise rank one record above another and let the client choose.

Validate units before validating ranges

A sodium value of 400 may mean 400 milligrams, 400 grams, or 400 milligrams per serving. Range checks alone cannot repair the denominator. Normalize energy, mass and serving bases explicitly, and reject conversions when required inputs are absent. Kilojoules and kilocalories also need named fields rather than a generic energy number. A mathematically plausible value in the wrong unit is more dangerous than a visible null.

Use decimal arithmetic or a documented rounding policy for repeated portion calculations. The physical label is already an estimate, so displaying six decimal places adds false precision. Keep adequate precision internally, then round only for presentation and totals. Test boundary cases such as water with zero calories, a missing serving weight and a package containing multiple servings.

API clients need an explicit missing-data policy

Document which fields are required, nullable or derived. Generated SDK types should match the runtime contract. If a client language cannot express nullability comfortably, provide helper methods that return an optional value instead of silently substituting zero. Add examples for sparse records to the documentation; a perfect yogurt response teaches developers nothing about the failure path they will eventually encounter.

When evolving the API, adding a new nullable nutrient is usually compatible. Changing an existing field from nullable to required is not automatically safe, because old cached records may still contain null. Likewise, removing null values from JSON changes object shape and can break code that enumerates keys. Contract tests should include both complete and intentionally incomplete fixtures.

Design manual correction without corrupting source truth

If users can enter a missing value, store it as a separate user or community assertion until it is reviewed. Do not overwrite the imported source row without an audit trail. Show whether a number came from the package label, a community correction or an estimate. Corrections should capture the basis, unit and serving context, not only the final number.

For a personal food diary, a user-specific override can be useful even when it should not become global catalog data. Separating personal corrections from shared records prevents one person's local package from changing results for everyone. The interface can still make the honest option convenient: scan, see the missing field, enter the label value and continue logging.

API rule: DietlyAPI keeps optional nutrients nullable and returns source and confidence metadata. Inspect the exact schema in the OpenAPI specification.


Originally published at getdietly.com. Data from the Dietly Nutrition API — 4.7M+ indexed foods, free tier available.

Top comments (0)