# EAN / GTIN / UPC Validator – Bulk Barcode Check & Lookup (`fast_data_asap/ean-gtin-lookup`) Actor

Bulk-validate EAN-13, EAN-8, UPC, GTIN-14 and ISBN: check digit, type, GS1 country prefix. Optional food product data from Open Food Facts.

- **URL**: https://apify.com/fast_data_asap/ean-gtin-lookup.md
- **Developed by:** [Fast Data](https://apify.com/fast_data_asap) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.20 / 1,000 valid barcode processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## EAN / GTIN / UPC Barcode Validator & Product Lookup

Paste a list of barcodes and get one clean, flat row per code back:

- **Validation**: normalises the code (spaces/hyphens removed), checks the GS1 mod-10 check digit and shows the expected digit when it is wrong.
- **Type detection**: EAN-13, EAN-8, UPC-A, UPC-E (expanded to UPC-A), GTIN-14 (with indicator digit and contained GTIN-13), ISBN-13, ISBN-10 (converted to ISBN-13), ISMN and ISSN barcodes (977, ISSN derived).
- **GS1 prefix → country / region** from the embedded public GS1 prefix table (e.g. 300-379 France, 400-440 Germany, 500-509 UK, 000-139 GS1 US).
- **Restricted / in-store codes** (020-029, 040-049, 200-299 variable-weight and store-internal codes, coupons 050-059 / 981-984 / 990-999, refund receipts 980) are flagged.
- **Normalised GTIN-13 and GTIN-14** for every valid code, ready for joining with your ERP, PIM or marketplace feeds.
- **Open product data** from the free Open Food Facts, Open Beauty Facts, Open Pet Food Facts and Open Products Facts databases: product name, brand, categories, quantity, front image URL, Nutri-Score, NOVA group, Green-Score/Eco-Score, labels, packaging, stores, allergens, countries sold and an optional ingredient list.

No API key, no login, no proxies. Runs in seconds.

### Who it is for

- **E-commerce and marketplace sellers** cleaning product feeds before uploading to Amazon, Google Merchant Center, bol.com or Shopify (wrong check digits are the #1 cause of rejected listings).
- **Data teams and PIM/ERP owners** normalising mixed UPC/EAN/GTIN-14 columns to one GTIN-14 key.
- **Food, nutrition and health apps** enriching barcodes with names, images and Nutri-Score.
- **AI agents** that need a reliable "what is this barcode?" tool via MCP.

### Why this actor

- Validation, type detection, GS1 country and product lookup in **one row**, not four tools.
- Handles the awkward cases others skip: UPC-E expansion, ISBN-10 to ISBN-13, GTIN-14 indicator digits, 12-digit vs 13-digit UPC storage in Open Food Facts.
- **Invalid codes are free.** You only pay for valid codes.
- Flat, consistent JSON (every row has the same keys) that drops straight into spreadsheets, databases and LLM prompts.
- Polite to the open databases: descriptive User-Agent, low concurrency, retries with back-off, and per-run caching.

### Input

```json
{
  "barcodes": ["3017620422003", "5449000000996", "737628064502", "9780141036144", "3017620422004"],
  "lookupProducts": true,
  "databases": ["openfoodfacts", "openbeautyfacts", "openproductsfacts"],
  "language": "en",
  "includeIngredients": false
}
```

| Field | Description |
|---|---|
| `barcodes` | Codes to check. Spaces and hyphens are ignored; several codes per line separated by commas also work. |
| `lookupProducts` | Turn off for pure offline validation (fastest). |
| `databases` | Which Open \*Facts databases to search, in order. |
| `language` | Preferred language for product names (falls back to the main language). |
| `includeIngredients` | Add the ingredients text for food products. |
| `lookupRestrictedCodes` | Also look up in-store / restricted prefixes (off by default). |
| `deduplicate` | Process identical codes once (default on). |

### Output

One row per input code, in input order. Real example from a test run (Nutella, shortened):

```json
{
  "position": 1,
  "input": "3017620422003",
  "status": "found",
  "valid": true,
  "type": "EAN-13",
  "found": true,
  "checkDigit": "3",
  "expectedCheckDigit": "3",
  "normalizedGtin13": "3017620422003",
  "normalizedGtin14": "03017620422003",
  "gs1Prefix": "301",
  "gs1PrefixCountry": "France & Monaco",
  "prefixKind": "gs1",
  "isRestricted": false,
  "isbn13": null,
  "productName": "Nutella",
  "brand": "Nutella, Ferrero",
  "quantity": "400 g e",
  "imageUrl": "https://images.openfoodfacts.org/images/products/301/762/042/2003/front_en.879.400.jpg",
  "novaGroup": 3,
  "ecoscoreGrade": "F",
  "genericName": "Hazelnut And Cocoa Spread",
  "countriesSold": "Belgium, France, Germany, Luxembourg",
  "labels": "Vegetarian, No gluten, Triman",
  "allergens": "milk, nuts, soybeans",
  "productUrl": "https://world.openfoodfacts.org/product/3017620422003",
  "source": "Open Food Facts"
}
```

Other rows from the same run:

| input | status | type | GS1 prefix country | product | Nutri-Score |
|---|---|---|---|---|---|
| 5449000000996 | found | EAN-13 | Belgium & Luxembourg | Coca-Cola, 330 ml | E |
| 737628064502 | found | UPC-A | GS1 US (USA & Canada) | Thai Kitchen Thai peanut noodle kit, 155 g | D |
| 9780141036144 | not_found | ISBN-13 (isbn10 `0141036141`) | Bookland (ISBN) | – | – |
| 3017620422004 | invalid (`expectedCheckDigit` 3) | EAN-13 | – | – | – |

`status` is one of `found`, `not_found`, `valid` (lookup off), `valid_not_looked_up` (restricted code), `invalid`, `lookup_error`.

Note: the GS1 prefix shows which national GS1 organisation issued the company prefix. It is a strong hint, but not a guarantee of the country of manufacture.

### Pricing

Pay per event: **$0.0002 per valid barcode** ($0.20 per 1,000). Invalid codes and lookup errors are free. A 10,000-code feed check costs about $2.

### Use via API, n8n, Make or MCP

**API (sync, returns the rows directly):**

```bash
curl -X POST "https://api.apify.com/v2/acts/fast_data_asap~ean-gtin-lookup/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"barcodes": ["3017620422003", "737628064502"]}'
```

**Python:**

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("fast_data_asap/ean-gtin-lookup").call(run_input={"barcodes": ["3017620422003"]})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["valid"], row["type"], row["gs1PrefixCountry"], row["productName"])
```

**n8n / Make / Zapier:** use the Apify node, action "Run actor and get dataset items", actor `fast_data_asap/ean-gtin-lookup`.

**MCP (Claude, Cursor, other AI agents):** add `https://mcp.apify.com?tools=fast_data_asap/ean-gtin-lookup` as an MCP server and ask "check these barcodes and tell me what the products are".

### Data sources and limits

- Product data comes from the open, community-maintained [Open Food Facts](https://world.openfoodfacts.org) family of databases (ODbL licence). Coverage is excellent for food and drinks in Europe and good in North America; non-food coverage is smaller. Codes not in these databases are still fully validated and returned with `found: false`.
- Books (ISBN) are detected and converted, but usually not present in the Open \*Facts databases.
- No personal data is processed.

# Actor input Schema

## `barcodes` (type: `array`):

EAN-13, EAN-8, UPC-A (12 digits), UPC-E (8 digits), GTIN-14, ISBN-13, ISBN-10 or ISSN-EAN codes. Spaces and hyphens are ignored. You can also paste several codes per line separated by commas.

## `lookupProducts` (type: `boolean`):

Look up name, brand, categories, quantity, image and Nutri-Score in the free Open Food Facts family of databases. Turn off for pure validation (much faster).

## `databases` (type: `array`):

Searched in this order until the product is found.

## `language` (type: `string`):

Two-letter language code (e.g. en, de, fr). Falls back to the product's main language.

## `includeIngredients` (type: `boolean`):

Adds the ingredients list (food products) to each row.

## `lookupRestrictedCodes` (type: `boolean`):

Codes with restricted prefixes (020-029, 040-049, 200-299, coupons) are store-internal and rarely in open databases. They are validated but not looked up unless this is on.

## `deduplicate` (type: `boolean`):

Process each identical input code only once.

## `maxConcurrency` (type: `integer`):

Parallel requests to the open databases. Keep it low to respect their fair-use limits.

## Actor input object example

```json
{
  "barcodes": [
    "3017620422003",
    "5449000000996",
    "737628064502",
    "9780141036144",
    "3017620422004"
  ],
  "lookupProducts": true,
  "databases": [
    "openfoodfacts",
    "openbeautyfacts",
    "openproductsfacts"
  ],
  "language": "en",
  "includeIngredients": false,
  "lookupRestrictedCodes": false,
  "deduplicate": true,
  "maxConcurrency": 4
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "barcodes": [
        "3017620422003",
        "5449000000996",
        "737628064502",
        "9780141036144",
        "3017620422004"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("fast_data_asap/ean-gtin-lookup").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "barcodes": [
        "3017620422003",
        "5449000000996",
        "737628064502",
        "9780141036144",
        "3017620422004",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("fast_data_asap/ean-gtin-lookup").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "barcodes": [
    "3017620422003",
    "5449000000996",
    "737628064502",
    "9780141036144",
    "3017620422004"
  ]
}' |
apify call fast_data_asap/ean-gtin-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fast_data_asap/ean-gtin-lookup"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/7dVvYzHCtkqbHfLze/builds/oNpsR6sd2Pygr1cvv/openapi.json
