When to use this API
When you need food product data — ingredients, nutrition facts per 100 g, allergens, dietary labels, or processing scores — and you have a barcode or a rough idea of what you're looking for. Open Food Facts is a crowdsourced database of over 3 million products, and it's surprisingly good at the things regulatory databases aren't: NOVA processing groups, Nutri-Score letter grades, and a nutrient_levels field that classifies fat, salt, sugar, and saturated fat as "low", "moderate", or "high" so you don't have to interpret raw numbers yourself. For live recall data or regulatory compliance status, look elsewhere; this is nutritional identity data, not a safety tracker.
Looking up a product by its barcode
"What's actually in this Thai peanut noodle kit I just bought?" The fastest way into Open Food Facts is a barcode lookup. Every product has a 13-digit EAN or 12-digit UPC, and /api/v2/product/{barcode} returns the full record in a single unauthenticated GET. A noodle kit is a good first call because it stress-tests the API's dietary labeling — it's simultaneously vegan, gluten-free, and NOVA group 4 (ultra-processed), which is an unusual combination that tells you something real about how processed "healthy" food can be.
curl "https://world.openfoodfacts.org/api/v2/product/0737628064502" | head -c 10000
{
"code": "0737628064502",
"status": 1,
"status_verbose": "product found",
"product": {
"product_name": "Thai peanut noodle kit includes stir-fry rice noodles & thai peanut seasoning",
"brands": "Simply Asia, Thai Kitchen",
"quantity": "155 g",
"categories": "Plant-based foods and beverages, Plant-based foods, Cereals and potatoes, Cereals and their products, Pastas, Noodles, Rice Noodles",
"nutriscore_grade": "d",
"nova_group": 4,
"additives_n": 1,
"additives_tags": ["en:e330"],
"allergens": "en:peanuts",
"allergens_tags": ["en:peanuts", "en:sesame-seeds", "en:soybeans"],
"ingredients_text": "Rice Noodles (rice, water), seasoning packet (peanut, sugar, salt, corn starch, spices [chili, cinnamon, pepper, cumin, clove], hydrolyzed soy protein, green onions, citric acid, peanut oil, sesame oil, natural flavor).",
"nutrition_grades": "d",
"nutrient_levels": {
"fat": "moderate",
"salt": "moderate",
"saturated-fat": "moderate",
"sugars": "high"
},
"labels": "No gluten, Vegetarian, Vegan",
"labels_tags": ["en:no-gluten", "en:vegetarian", "en:vegan"],
"nutriments": {
"energy-kcal_100g": 385,
"fat_100g": 7.69,
"saturated-fat_100g": 1.92,
"carbohydrates_100g": 71.15,
"sugars_100g": 13.46,
"proteins_100g": 9.62,
"salt_100g": 0.72,
"fiber_100g": 1.9
},
"serving_size": "0.333 PACKAGE (52 g)",
"countries": "France,United States"
}
}
The real story here is nova_group: 4 alongside labels: "No gluten, Vegetarian, Vegan". NOVA group 4 means ultra-processed — the API's own classification, not a subjective label. A product can be plant-based and gluten-free and still be ultra-processed, and the nutrient_levels backs that up: sugars are "high" at 13.46 g per 100 g. The additives_n is just 1 (citric acid, en:e330), which is low for a processed food kit — the processing level comes from the ingredient list structure, not the additive count. The allergens_tags field includes three entries (en:peanuts, en:sesame-seeds, en:soybeans) even though allergens only shows en:peanuts, because allergens_tags pulls from both the declared allergens and ingredients analysis.
This Simply Asia Thai peanut noodle kit is labeled vegan, vegetarian, and gluten-free — but it's NOVA group 4 (ultra-processed) with a Nutri-Score of D. Per 100 g it has 385 kcal, 13.46 g of sugar, 0.72 g of salt, and 7.69 g of fat. It contains peanuts, sesame, and soy as allergens. Only one additive (citric acid, E330), but the processing level comes from the ingredient structure, not the additive count.
Searching for products by category and nutrition grade
"Show me orange juices with a good Nutri-Score." The /api/v2/search endpoint filters by category, nutrition grade, brand, label, and more. Use ?fields= to trim the response — each product has 200+ fields, and untrimmed search results are enormous.
curl "https://world.openfoodfacts.org/api/v2/search?categories=Orange%20Juice&nutrition_grades=a&fields=code,product_name,brands,nutriscore_grade,nova_group,nutrient_levels&page_size=5" | head -c 10000
{
"count": 1000,
"page": 1,
"page_size": 5,
"products": [
{
"code": "3228853100146",
"product_name": "Orange Juice",
"brands": "Tropicana",
"nutriscore_grade": "a",
"nova_group": 3,
"nutrient_levels": { "fat": "low", "salt": "low", "saturated-fat": "low", "sugars": "moderate" }
}
],
"skip": 0,
"page_count": 200
}
The nutrition_grades filter uses the letter grades A through E — a is best, e is worst. Combined with categories, it narrows a 3-million-product database down to products matching both criteria. The count field tells you how many results exist total; page_size controls how many come back per page; page is your page number. The ?fields= parameter is not optional for production use — without it, each product in the response carries its entire 200+ field payload, and a page_size=24 search returns megabytes. Ask for exactly the fields you need.
I found orange juice products with Nutri-Score A (excellent nutritional quality). They tend to be NOVA group 3 (processed) with low fat, low salt, and moderate sugar — the sugar is natural from the oranges, not added.
Pitfalls
- v0 and v2 product endpoints differ in response shape. The v0 endpoint (
/v0/product/{barcode}.json) wraps everything underproductwith astatusinteger; v2 (/api/v2/product/{barcode}) uses the same structure but also supports?fields=for response trimming. If you're building new integrations, use v2. - Rate limits vary by endpoint type. Product reads allow 100 requests/minute. Search queries allow 10 requests/minute. Facet queries (categories, brands, labels) allow only 2 requests/minute. A search-heavy workflow will hit the facet limit fast.
- Products can have 200+ fields. A bare
/api/v2/product/{barcode}call returns the entire record, often 50 KB or more. Always use?fields=code,product_name,nutriscore_grade,...to request only what you need — this is the single biggest performance lever. status: 0means "product not found," not an error. The API returns HTTP 200 withstatus: 0andstatus_verbose: "product not found"when the barcode doesn't exist in the database. Don't check for HTTP error codes; check thestatusfield.
One-line summary for the user
I can look up any food product by barcode — ingredients, nutrition per 100 g, allergens, dietary labels, Nutri-Score, and NOVA processing group — from the Open Food Facts database in a single unauthenticated GET.