Open Food Facts Product Lookup — Ingredients & Nutri-Score API avatar

Open Food Facts Product Lookup — Ingredients & Nutri-Score API

Pricing

from $2.40 / 1,000 successful lookups

Go to Apify Store
Open Food Facts Product Lookup — Ingredients & Nutri-Score API

Open Food Facts Product Lookup — Ingredients & Nutri-Score API

Look up food products by barcode against Open Food Facts' free, crowdsourced database of 3M+ products. Get name, brand, ingredients, allergens, Nutri-Score, Eco-Score, NOVA group, and per-100g nutrition facts. Pay only for barcodes that resolve.

Pricing

from $2.40 / 1,000 successful lookups

Rating

0.0

(0)

Developer

Adrian Voss

Adrian Voss

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Open Food Facts Product Lookup

Look up any food product by barcode (GTIN/UPC/EAN) against the free, crowdsourced Open Food Facts database — ingredients, allergens, Nutri-Score, NOVA processing group, Eco-Score, and full per-100g nutrition facts. No API key and no scraping: this calls the official public API directly, so you get the same record the Open Food Facts app reads.

Who it's for

Built for anyone who needs real product data behind a barcode without a paid database subscription. Food-app and diet-tracker builders use it to turn a user's barcode scan into Nutri-Score, NOVA group and full nutrition facts on the spot. Import and retail compliance teams screen a supplier's SKU list for undeclared allergens and additives before it ever reaches a shelf. Comparison-shopping and price-tracking tools attach a name, brand and image to a barcode list pulled from POS or supplier data — the boring enrichment step that turns a list of numbers into something a shopper recognizes.

Why this one

  • The official public API, not a scrape. Open Food Facts publishes a free product API and this actor calls it directly — no HTML parsing to break, no key to request.
  • You don't pay for barcodes it doesn't know. A barcode that isn't in the database, or isn't a valid GTIN, comes back found: false and is never billed.
  • Everything on the label in one row. Ingredients, allergens, additives, labels, Nutri-Score, NOVA group, Eco-Score and eight per-100g nutrition figures — one lookup, not five.
  • Separators are stripped for you. 0737628064502, 737628064502 and a barcode pasted with spaces or hyphens all resolve to the same product.
  • Stably-named fields. Column names are frozen between runs, which matters if an AI agent or a Clay column reads the schema once and keeps using it.

What you get

One row per input barcode, with field names frozen between runs — a schema mapped once by an agent or a Clay column keeps working.

FieldType / formatDescription
querytextThe barcode exactly as submitted, before separators are stripped.
foundbooleanWhether the barcode resolved to a product. Gates billing — false rows are never charged.
statustextOK, NOT_FOUND (barcode not in the database), or BAD_FORMAT (not an 8–14 digit GTIN).
barcodetextThe normalized barcode as Open Food Facts stores it.
nametextProduct name, falling back to the generic name when the branded one is blank.
brandstextBrand string as entered by contributors — may list several, comma-separated.
categoriesarrayCategory path, split into separate entries.
quantitytextPack size as printed — e.g. 155 g.
nutriScoretextNutri-Score grade AE, uppercased. null when not computed.
novaGroupnumberNOVA processing group, 1 (unprocessed) to 4 (ultra-processed).
ecoScoretextEco-Score grade, uppercased. Often UNKNOWN outside the EU.
ingredientsTexttextFull ingredients list as printed on the packaging.
allergensarrayDeclared allergens, with the en: language prefix stripped.
additivesarrayAdditive codes present — e.g. e330.
labelsarrayCertifications and claims — Organic, Vegan, No gluten.
countriesarrayMarkets the product is recorded as being sold in.
nutritionobjectPer-100g figures: energyKcal100g, fat100g, saturatedFat100g, carbohydrates100g, sugars100g, fiber100g, proteins100g, salt100g.
imageUrllinkFront-of-pack product photo.
scrapedAtdate (ISO 8601)When the lookup ran.

Price

$4 per 1,000 barcodes, plus a $0.005 start fee. Misses (found:false) are never charged.

You're billed per barcode that resolves to a product. A barcode the database doesn't know, or one that isn't a valid GTIN, costs nothing no matter how many are in the list. Run 1,000 barcodes and, at the live FREE-tier price, that's roughly $4 if every one resolves — cheaper in practice, since misses cost nothing, and cheaper again on paid Apify tiers. No monthly fee runs whether or not you use it that month.

How to use

  1. In the Apify Console. Open the actor page and click Start — the barcodes field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
  2. Via the API. Call it directly with a POST request — no Console needed once you have an API token:
    curl "https://api.apify.com/v2/acts/accountable_eel~openfoodfacts-product-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"barcodes":["0737628064502"]}'
  3. On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.
  1. Paste your barcodes into barcodes — digits only, with or without a leading zero.
  2. Run the actor. Each barcode is looked up against the Open Food Facts product API, in parallel up to maxConcurrency.
  3. Read the dataset. Each row carries the full product record, or found: false if the barcode isn't in the database.
  4. Turn on onlyFound if you want the misses dropped from the output entirely.

Common ways teams use this:

  • Screen a catalogue for allergens or additives before listing or importing it, by filtering rows on allergens and additives.
  • Pull per-100g nutrition in bulk for a private-label range or a comparison app.
  • Enrich a barcode scan with Nutri-Score and NOVA group instantly inside a health or diet product.
  • Attach names, brands and images to a barcode list exported from POS or supplier data.
  • Check which markets a product is sold in using countries before planning a launch.

Input

{
"barcodes": [
"0737628064502"
]
}

One GTIN/UPC/EAN barcode per line, digits only. Accepted formats: 0737628064502, 737628064502.

{
"barcodes": ["0737628064502", "737628064502"],
"testRun": false,
"onlyFound": false,
"maxConcurrency": 5
}

barcodes is your list of GTIN/UPC/EAN codes — separators are stripped automatically, so spaces and hyphens are fine. Turn on testRun to try the list against just the first five barcodes before committing to the full batch. onlyFound drops miss rows from the output, maxResults stops the run early once that many products have been found, includeKeywords and excludeKeywords filter rows by content, and columns picks which fields come back — useful for keeping a Clay table narrow.

Sample output

queryfoundstatusnamebarcodebrandscategoriesquantitynutriScorenovaGroupecoScoreingredientsTextallergensadditiveslabelscountriesnutritionimageUrlscrapedAt
0737628064502trueOKThai peanut noodle kit includes stir-fry rice noodles & thai peanut seasoning0737628064502Simply Asia, Thai Kitchen["Cereals and their products","Noodles","Rice Noodles"]155 gD4UNKNOWNRice 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).["peanuts","sesame seeds","soybeans"]["e330"]["No gluten","Vegan"]["France","United States"]{"energyKcal100g":385,"fat100g":7.69,"saturatedFat100g":1.92,"carbohydrates100g":71.15,"sugars100g":13.46,"fiber100g":1.9,"proteins100g":9.62,"salt100g":0.72}https://images.openfoodfacts.org/images/products/073/762/806/4502/front_en.6.400.jpg2026-08-23T21:04:47.132Z

That table lists every available column. A single row reads like this:

{
"query": "0737628064502",
"found": true,
"status": "OK",
"barcode": "0737628064502",
"name": "Thai peanut noodle kit",
"brands": "Simply Asia, Thai Kitchen",
"categories": ["Cereals and their products", "Noodles", "Rice Noodles"],
"quantity": "155 g",
"nutriScore": "D",
"novaGroup": 4,
"ecoScore": "UNKNOWN",
"allergens": ["peanuts", "sesame seeds", "soybeans"],
"additives": ["e330"],
"labels": ["No gluten", "Vegan"],
"countries": ["France", "United States"],
"nutrition": { "energyKcal100g": 385, "fat100g": 7.69, "sugars100g": 13.46, "salt100g": 0.72 },
"scrapedAt": "2026-08-23T21:04:47.132Z"
}

A barcode the database doesn't know still returns a row, and is never charged:

{
"query": "0000000000000",
"found": false,
"status": "NOT_FOUND",
"message": "No product is registered under this barcode in Open Food Facts.",
"scrapedAt": "2026-08-23T21:04:47.132Z"
}

Failed barcodes stay in the dataset by default rather than disappearing — useful for spotting a batch of transcription errors versus barcodes that genuinely aren't registered. Set onlyFound if you'd rather not see them.

Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

curl "https://api.apify.com/v2/acts/accountable_eel~openfoodfacts-product-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
-X POST \
-H "Content-Type: application/json" \
-d '{"barcodes":["0737628064502"]}'

n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~openfoodfacts-product-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"barcodes":["0737628064502"]} (swap in an expression from an earlier node for a real value).

Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~openfoodfacts-product-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"barcodes":["{{barcode}}"]}, mapping the row's barcode into the barcodes array.

MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Open Food Facts API — Barcode to Nutri-Score & Allergens" — the agent will find and run this actor.

Tips

  • Send the barcode exactly as scanned. Leading zeros are preserved and separators stripped, so you rarely need to normalize a list before running it.
  • Treat ecoScore as EU-centric. It's frequently UNKNOWN for products sold outside Europe — don't build a filter that silently drops those rows.
  • Use columns to keep a Clay table narrow. The full record is wide; picking six fields makes the output far easier to map into a spreadsheet.
  • Check countries before trusting a nutrition figure for your market. The same brand can have a different recipe per country, and the record reflects whichever pack was contributed.
  • Run testRun first on a big list. Five barcodes will tell you whether your codes are the right format before you commit the whole batch.

vs. alternatives

What it costsWhat you getTrade-off
This actor (openfoodfacts-product-lookup)$4 per 1,000 resolved barcodes (less on paid tiers), $0.005 actor start, nothing for a barcode the database doesn't knowThe full Open Food Facts record — ingredients, allergens, additives, labels, Nutri-Score, NOVA, Eco-Score and per-100g nutrition — as one flat rowCoverage is only as good as Open Food Facts itself: crowdsourced, strongest in the EU, thinnest on niche and own-brand products
burbn/barcode-lookup (122 users)$0.02 per result, $0.01 startA general barcode resolver across product types, not just foodFive times the per-row price, and broader rather than deeper — no Nutri-Score, NOVA or per-100g nutrition
Open Food Facts' own APIFreeThe same JSONIt is the same JSON. This handles the barcode normalization, the retries, the concurrency ceiling and the flattening, and hands you a table instead of nested objects.
A commercial GS1 / GDSN feedFour figures a year and upAuthoritative manufacturer-supplied data with guaranteed coverageIf you need contractual accuracy for regulated labelling, buy the commercial feed. This is a free, crowdsourced source and should be treated as such.

(Prices for the tools above are their August 2026 FREE-tier list prices — check their own pages before relying on a straight comparison.)

Coverage: what's in Open Food Facts

Open Food Facts is crowdsourced — anyone with the app can add or edit a product — which cuts both ways. It means millions of products are covered for free, but coverage tracks where the contributor community is strongest, not where products are sold. Packaged goods sold in the EU, and especially France where the project started, have the most complete records: full ingredients, all four scores, per-100g nutrition. Products sold only in smaller markets, store own-brands, and anything niche are more likely to have a thin record or no record at all.

Practically: expect nutriScore and ecoScore to be null more often outside Europe, expect some barcodes not to resolve at all even for real products, and treat a found: false as "not in this crowdsourced database" rather than "doesn't exist." For products where you need guaranteed coverage — a specific retailer's own catalogue, for instance — this free source won't get you there; a commercial GS1 feed will, at commercial prices.

FAQ

Do I need an Open Food Facts API key? No. The product API is free and public — this actor calls it directly, with no credentials required on your end.

How accurate and up to date is the data? Open Food Facts is crowdsourced and community-maintained, covering millions of products worldwide. Coverage and freshness vary by product and region — packaged goods sold in the EU, especially France where the project started, tend to have the most complete records. Treat it as a very good free source, not as a manufacturer-certified one.

What happens if a barcode isn't in the database? You still get a row, with found: false and status: NOT_FOUND, so your output always has one row per input — and you're never charged for it.

Can I run this against thousands of barcodes at once? Yes. Turn on testRun first to sanity-check the list against five barcodes, then run the full batch. maxConcurrency controls how many requests run in parallel.

Does this only work for US products? No — it's a global database. Use countries on each result to see which markets a product is actually recorded as being sold in.

Why is nutriScore or ecoScore empty on a product that clearly has one? Both are computed by Open Food Facts, and only when enough of the underlying nutrition data has been contributed. A sparse record produces a null grade rather than a guess.

Is the nutrition data per 100g or per serving? Per 100g or 100ml, always — that's what the 100g suffix on each field means. Serving-size figures aren't returned, so a per-portion number has to be derived from quantity.

Can I look up a product by name instead of barcode? No — this actor is barcode-keyed by design. Open Food Facts does offer text search, but it returns ranked guesses rather than one definite product, which is the wrong shape for a lookup that promises exactly one row per input.

Why do two barcodes for the same product return different data? Because they're different pack records. A 200g jar and a 400g jar carry separate GTINs and are contributed separately, so the nutrition may match while quantity, imageUrl and even labels differ. Match on barcode, not on name.

Does the actor write anything back to Open Food Facts? No. It only reads. Nothing about your barcode list, your run, or your account is sent to the project — and no data is stored between runs on this side either.

What does novaGroup actually mean? It's the NOVA food-processing classification, 1 to 4: 1 is unprocessed or minimally processed, 4 is ultra-processed. It's a processing measure, not a health score — nutriScore is the one that grades nutritional quality.