How to Scrape Open Food Facts Nutrition & Barcode Data
Extract nutrition facts, Nutri-Score, NOVA group, ingredients and labels from Open Food Facts by category, brand or barcode — keyless JSON API, bulk pagination.
Open Food Facts is the largest open food database on the web — over 3 million products, community-contributed, with barcodes, ingredients, nutrition tables and Nutri-Score grades. It publishes everything through a free, keyless JSON API, which sounds like the hard part is solved. It isn’t. If you want all yogurts sold in France or every ultra-processed breakfast cereal, you’re facing paginated search endpoints, inconsistent field coverage across community entries, and a category taxonomy that expects slugs, not display names. This guide covers how the Open Food Facts API is structured, how to pull data in bulk without tripping over its quirks, and what the extracted records actually look like.
What’s worth extracting
Each product record carries 17 fields, grouped by what you’ll use them for:
- Identity —
code(the EAN/UPC barcode, your stable key),product_name,brands,categories(category tags),quantity(package size like “500 g”). - Health ratings —
nutriscore_grade(a–e),nova_group(1–4 processing level, where 4 is ultra-processed). - Nutriments per 100g —
energy_kcal_100g,fat_100g,sugars_100g,salt_100g,proteins_100g. - Composition —
ingredients_text(the full ingredient list, often in the product’s local language). - Certification & market —
labels(organic, fair-trade, no-palm-oil and other quality tags),countries(where the product is sold). - Media & links —
image_url(front image) andurl(the product’s Open Food Facts page).
For diet analysis you need the barcode, name, nutriscore, nova group and the five nutriments. For catalog enrichment, add the image URL and ingredients.
How the Open Food Facts API works
The actor talks to world.openfoodfacts.org — the official public API — across three endpoints matching its three modes.
Search mode hits /api/v2/search with category, brand and country filters, paginating in batches of 100 until it reaches maxResults. This is the workhorse for building datasets:
{
"mode": "search",
"categories": ["breakfast-cereals", "muesli"],
"brands": ["Kellogg's"],
"countries": ["united-states"],
"maxResults": 1000
}
Category mode uses the dedicated /category/<slug>.json endpoint, which is slightly faster for straight category browsing but returns fewer fields than search.
Product mode fetches individual products by barcode via /api/v2/product/<barcode>.json — the fastest path when you already have a barcode list:
{
"mode": "product",
"barcodes": ["3017620422003", "5449000000996", "7613036020328"]
}
The critical detail is that filters expect slugs, not display names. You pass breakfast-cereals, not “Breakfast Cereals”; united-states, not “USA”. Country filters use English-language slugs regardless of where the product is sold. There is no HTML scraping here — every request returns clean JSON straight from the API.
Choosing a mode
The three modes trade breadth against depth, and picking the right one saves both time and cost:
- Search is the default and the most flexible. Use it whenever you’re filtering by category, brand or country and want the full 17-field record per product. It’s the only mode that combines filters — categories and brands and countries together — which is how you get precise slices like “Kellogg’s breakfast cereals sold in the US.”
- Category is a browse shortcut. It hits the dedicated per-category endpoint, which is marginally faster for pulling a whole category, but returns fewer fields than search. Reach for it when you want everything in one category and don’t need the tightest field set.
- Product is the direct-lookup path. If you already hold a list of barcodes — say, your grocery inventory — this fetches each product individually with no pagination overhead. It’s the fastest per-item mode and the right choice for enrichment pipelines that start from known EANs/UPCs.
Most dataset-building work lives in search mode; category and product are the specialized tools for browsing and enrichment respectively.
▶ Run the Open Food Facts Scraper on Apify — search by category, brand or country, or look up a barcode list, and export nutrition data to CSV or JSON. Keyless, no login.
The access reality
Open Food Facts is a nonprofit and the API is open and generous — there’s no key, no token expiry, and no aggressive rate limiting. That removes the usual scraping friction, but it introduces a different one: data completeness varies wildly because the database is community-contributed.
- Nutrition fields are frequently null. Many products exist in the database with just a barcode and name because no contributor has filled in the nutrition table. Expect empty
energy_kcal_100g,fat_100gand the rest for a meaningful slice of any broad query. Filter these out downstream (energy_kcal_100gis not null) before you compute averages. - Nutri-Score isn’t universal.
nutriscore_gradeis only computed for products where the data supports it and, historically, where the market context makes it relevant. Some products return an empty grade — drop them if you’re comparing grades head to head. - Ingredients are multilingual.
ingredients_textcomes back in whatever language the contributor entered, often the product’s origin country. If you need English, bias your query with acountriesfilter toward English-speaking markets, but don’t expect it to be perfect. - Popular categories are huge. Categories like “yogurts” or “beverages” hold tens of thousands of products. Set
maxResultsdeliberately — an unlimited run on “beverages” is a large job.
Because the API doesn’t rate-limit hard, the actor still keeps concurrency modest (3 requests by default) to be a good citizen of a nonprofit resource. Datacenter proxy is sufficient; you never need residential IPs.
Example output
A single search-mode record for a real product:
{
"code": "3017620422003",
"product_name": "Nutella",
"brands": "Ferrero",
"categories": "Spreads, Sweet spreads, Chocolate spreads",
"quantity": "400 g",
"nutriscore_grade": "e",
"nova_group": 4,
"energy_kcal_100g": 539,
"fat_100g": 30.9,
"sugars_100g": 56.3,
"salt_100g": 0.107,
"proteins_100g": 6.3,
"ingredients_text": "Sugar, palm oil, hazelnuts (13%), skimmed milk powder (8.7%)...",
"labels": "no-gluten",
"countries": "france, germany, united-kingdom, united-states",
"image_url": "https://images.openfoodfacts.org/images/products/301/762/042/2003/front_en.497.400.jpg",
"url": "https://world.openfoodfacts.org/product/3017620422003"
}
Who uses this
- Nutritionists and dietitians building diet-comparison tools or client food-tracking systems on a maintained, free nutrition database.
- Food-tech startups that need a nutrition backend without paying for a commercial data provider or maintaining their own crawler.
- Data scientists and researchers analyzing food composition, ultra-processing prevalence (filter
nova_groupequals 4), or Nutri-Score distribution across brands and countries. - E-commerce and retail teams enriching product catalogs with nutrition facts, front images and ingredient lists keyed on barcode.
- Journalists and public-health advocates studying food labeling, additive use and ultra-processed-food patterns with a reproducible dataset.
- Grocery and delivery apps running a barcode list through product mode to attach nutrition data to their inventory.
Cost and effort: build vs. managed
The API is free and documented, so a one-off script is achievable. What eats time is the shape of the problem: paginating /api/v2/search correctly, normalizing the nested nutriments object into flat columns, mapping display names to the slugs the API actually wants, and handling the pervasive null fields without your pipeline choking. Then you own that code as the community re-tags products and the schema drifts.
The managed actor is pay-per-result — pennies per hundred records, scaling linearly. A 1,000-product category pull runs in roughly four to five minutes and costs a few cents. Because Open Food Facts has no proxy or anti-bot cost, the entire expense is just per-row plus a negligible start fee, which makes bulk category datasets genuinely cheap to assemble.
Common pitfalls
Source-specific things to get right:
- Use slugs everywhere. The single most common mistake is passing “Breakfast Cereals” instead of
breakfast-cereals. Check the Open Food Facts categories page for valid slugs before a big run. - Filter nulls before aggregating. Community data is incomplete. Averaging
sugars_100gacross a category without dropping nulls skews your numbers. - NOVA 4 is your ultra-processed filter. If you’re building an ultra-processed-food dataset, filter
nova_groupequals 4 — it’s the cleanest single signal in the record. - Nutri-Score coverage is partial. Don’t assume every product has a grade; branch your logic for the empty case.
- Barcode mode skips misses silently. In product mode, a barcode that isn’t in the database is logged and skipped — your dataset contains only the barcodes that existed, so reconcile against your input list if completeness matters.
- Brand and country filters are search-mode only. The
brandsandcountriesinputs apply in search mode. Category mode browses a single category endpoint and product mode looks up exact barcodes, so if you need to combine a category with a brand or market, you must use search. - Re-run for freshness. The database updates daily as contributors add products and corrections. A dataset from months ago will be missing new entries; schedule periodic re-runs for production use.
Wrapping up
Open Food Facts hands you a keyless, openly licensed food database — the access is the easy part. The real work is paginating the search endpoint, flattening nutriments, speaking the slug-based taxonomy, and absorbing the null-heavy nature of community data. If you need a quick lookup, hit the API directly. If you need a clean, filtered nutrition dataset by category, brand or barcode, delivered as a spreadsheet, a managed actor handles the plumbing for a fraction of a cent per row.
▶ Open the Open Food Facts Scraper on Apify — one run yields a nutrition dataset of thousands of products with Nutri-Score, NOVA group, ingredients and labels, exportable to CSV, Excel or JSON. No API key, no login. Start on Apify’s free monthly credit.
Related guides
EU Company Registry Data Export — Germany, France, Netherlands
How to extract company-registry records from Handelsregister, INPI, and KvK in a unified schema — for KYC, B2B lead generation, and compliance workflows.
How to Scrape Allabolag.se Sweden Company Leads in 2026
Extract Swedish company data from allabolag.se — org number, revenue, CEO, phone and email — without an API key. A guide to bulk firmographics and B2B leads.
How to Scrape the Australia Business Register (ABN/ABR)
Bulk-export Australian business names, ABNs, status and registration dates from the official data.gov.au CKAN register — no API key, no browser, no captcha.