# UPC Barcode Product Lookup (`automation-lab/upc-barcode-lookup`) Actor

Resolve UPC, EAN, and GTIN batches into source-attributed product identity, brand, title, category, package, image, duplicate count, and match-status records for catalog enrichment and validation.

- **URL**: https://apify.com/automation-lab/upc-barcode-lookup.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## UPC Barcode Product Lookup

Resolve UPC, EAN, and GTIN batches into source-attributed **UPC products** records for catalog enrichment and validation.

The Actor validates each barcode, checks selected public product databases, merges missing product fields in source order, and saves one typed record per unique code. Each row includes product identity, brand, category, package size, image, match status, duplicate count, and source-level evidence.

### What does UPC Barcode Product Lookup do?

Use the Actor to:

- look up UPC-A, EAN-8, EAN-13, and GTIN-14 codes;
- reject malformed codes and incorrect GS1 check digits before lookup;
- enrich supplier or merchant barcode lists with product metadata;
- distinguish a confirmed match from a clean no-match and an upstream error;
- combine fields from multiple public databases without losing attribution;
- deduplicate repeated codes while retaining their occurrence count;
- export normalized rows to JSON, CSV, Excel, or another Apify integration.

This is a barcode-to-product lookup utility. It does not generate barcodes, verify GS1 company ownership, or guarantee that every retail product exists in a public database.

### Who is this Actor for?

#### Ecommerce catalog teams

Map incoming barcode lists to titles, brands, categories, package sizes, and images before adding products to a catalog.

#### Marketplace operations teams

Separate matched products from unmatched codes that need manual research or supplier clarification.

#### Retail analysts

Normalize mixed UPC and EAN files before comparing assortments across suppliers, stores, or time periods.

#### Data engineers

Feed deterministic match-status records into spreadsheets, warehouses, ETL jobs, webhooks, or scheduled Apify Tasks.

#### Quality assurance teams

Validate barcode length and check digits before a bad identifier reaches downstream systems.

### Why use this UPC product lookup?

- **Source attribution:** `fieldSources` identifies which database supplied every merged field.
- **No false empty result:** `not_found` is different from `lookup_error`.
- **Batch-safe validation:** the run fails before charging when any supplied barcode has an invalid shape or check digit.
- **Duplicate awareness:** repeated input codes produce one row with `duplicateCount`.
- **Selectable sources:** use only the databases allowed by your workflow.
- **Lightweight execution:** public JSON APIs avoid browser and proxy overhead.
- **Integration-ready output:** the default dataset contains one stable record type.

### Supported barcode formats

| Format | Digits | Typical use |
| --- | ---: | --- |
| EAN-8 | 8 | Compact retail packages |
| UPC-A | 12 | North American retail products |
| EAN-13 | 13 | International retail products |
| GTIN-14 | 14 | Trade items and packaging levels |

Spaces and hyphens are removed before validation. Submit codes as strings when leading zeroes matter.

The Actor verifies the check digit. It does not infer or repair an incorrect code because that could attach the wrong product to a catalog row.

### Product data sources

| Input value | Public source | Best fit |
| --- | --- | --- |
| `openFoodFacts` | Open Food Facts | Food and beverage products |
| `openBeautyFacts` | Open Beauty Facts | Cosmetics and personal care products |
| `openPetFoodFacts` | Open Pet Food Facts | Pet food products |
| `openProductsFacts` | Open Products Facts | General consumer products |
| `upcItemDb` | UPCitemdb trial API | Broader retail identity fallback |

The default checks Open Food Facts and UPCitemdb. Source availability and coverage vary by product, region, and time.

UPCitemdb's public trial endpoint has a shared rate limit. A rate-limit response is recorded as a source `error`; it is never silently presented as a product no-match.

### What data can you extract?

| Field | Meaning |
| --- | --- |
| `inputCode` | First submitted representation of the barcode |
| `gtin` | Digits-only validated identifier |
| `format` | EAN-8, UPC-A, EAN-13, or GTIN-14 |
| `matchStatus` | `found`, `not_found`, or `lookup_error` |
| `title` | Best available product name |
| `brand` | Best available brand name |
| `category` | Source category or category path |
| `packageSize` | Source-provided quantity or package size |
| `imageUrl` | Best available product image URL |
| `fieldSources` | Source selected for each populated field |
| `lookups` | URL, status, and bounded error text for each queried source |
| `duplicateCount` | Number of occurrences in the submitted batch |
| `lookedUpAt` | UTC lookup timestamp |

Product fields are nullable. A valid barcode can exist even when none of the selected public databases has metadata for it.

### How to look up UPC codes

1. Open the Actor in Apify Console.
2. Add one or more values to **UPC, EAN, or GTIN codes**.
3. Choose the product data sources appropriate for the catalog.
4. Set `maxItems` to cap the number of unique codes saved.
5. Keep concurrency low when using public rate-limited APIs.
6. Click **Start**.
7. Open the default dataset to inspect matches and source evidence.
8. Export the dataset or connect it to the next workflow.

A useful first run is:

```json
{
  "codes": ["737628064502", "3017620422003"],
  "sources": ["openFoodFacts", "upcItemDb"],
  "maxItems": 2,
  "maxConcurrency": 2
}
```

### Input parameters

#### `codes`

Required array of barcode strings. The Actor accepts 1 to 1,000 submitted values and saves up to `maxItems` unique codes.

#### `sources`

Optional ordered array of source identifiers. Earlier sources win when more than one source supplies the same field; later sources can fill missing values.

#### `maxItems`

Maximum unique records saved, from 1 to 500. The default is 100.

#### `maxConcurrency`

Number of barcodes processed at once, from 1 to 10. The default is 5.

Higher concurrency can finish a batch faster, but it can also reach third-party rate limits sooner.

### Output example

A current local lookup for `737628064502` returns a record shaped like this:

```json
{
  "inputCode": "737628064502",
  "gtin": "737628064502",
  "format": "UPC-A",
  "matchStatus": "found",
  "title": "Thai peanut noodle kit includes stir-fry rice noodles & thai peanut seasoning",
  "brand": "Simply Asia, Thai Kitchen",
  "category": "Cereals and their products, Noodles, Rice Noodles",
  "packageSize": "155 g",
  "imageUrl": "https://images.openfoodfacts.org/images/products/073/762/806/4502/front_en.6.400.jpg",
  "fieldSources": {
    "title": "openFoodFacts",
    "brand": "openFoodFacts"
  },
  "lookups": [
    {
      "source": "openFoodFacts",
      "sourceUrl": "https://world.openfoodfacts.org/api/v2/product/737628064502.json",
      "status": "found"
    }
  ],
  "duplicateCount": 1,
  "lookedUpAt": "2026-08-05T06:00:00.000Z"
}
```

Source records can change. Treat the example as a shape demonstration, not a permanent claim about that product.

### Understanding match statuses

#### `found`

At least one selected source returned a product. Some individual fields can still be null.

#### `not_found`

At least one source completed normally, but none returned a product for the validated code.

#### `lookup_error`

Every selected source failed because of a network, rate-limit, timeout, or upstream response problem. Retry later or select another source; do not interpret this status as evidence that the product does not exist.

The `lookups` array makes mixed outcomes visible when one source fails and another finds the product.

### Deduplicating catalog batches

The Actor normalizes spaces and hyphens, then deduplicates by validated digits.

For this input:

```json
{
  "codes": ["737628064502", "737-628-064-502"]
}
```

one result is saved with `duplicateCount: 2`. This keeps billing and downstream datasets predictable without hiding repeated supplier rows.

### Tips for reliable lookups

- Submit codes as strings, especially codes beginning with zero.
- Select the catalog that matches the product type.
- Use `openFoodFacts` alone when you need a reproducible food-database check.
- Use more than one source when field completeness matters more than request count.
- Keep `maxConcurrency` between 1 and 5 for rate-limited public sources.
- Schedule retries for `lookup_error`, not for `not_found`.
- Store previous datasets if you need to compare source changes over time.
- Review source licenses and attribution requirements before redistributing enriched records.

### Limits and failure behavior

Public databases do not provide universal retail coverage. Private-label, regional, discontinued, new, or packaging-level products may be missing.

A title or image can be user-contributed and may differ across sources. The Actor merges only missing fields; it does not assert that one source is authoritative.

Any invalid barcode in the input fails the run before source requests and before the start event. Split uncertain values into a separate validation batch if partial processing is preferred.

Transient network errors, HTTP 429 responses, and temporary 5xx responses receive bounded retries. Stable invalid or unauthorized responses are not retried blindly.

The Actor does not download images. It saves source URLs, which reduces transfer and runtime.

### How much does it cost to look up UPC products?

The Actor uses pay-per-event pricing:

- one `start` event per valid run;
- one `item` event per unique barcode record saved;
- duplicate input occurrences do not create extra item events.

Current measured rates are:

| Plan tier | Item price |
| --- | ---: |
| Free | $0.004715 |
| Bronze | $0.004100 |
| Silver | $0.003198 |
| Gold | $0.002460 |
| Platinum | $0.001640 |
| Diamond | $0.001148 |

The start event is $0.005. At the Free-tier item rate, 10 unique lookups cost $0.05215 and 100 unique lookups cost $0.4765, before any free platform credits. At the Bronze rate, the same batches cost $0.046 and $0.415. Check the live Actor pricing panel for the authoritative active rate.

### Export to spreadsheets and data pipelines

After a run, export the default dataset as JSON, CSV, XML, or Excel.

Common workflow:

1. receive a supplier barcode file;
2. convert the barcode column to strings;
3. run this Actor with the distinct values;
4. join output back to the supplier file on normalized `gtin`;
5. route `not_found` to research;
6. route `lookup_error` to a retry queue;
7. review source attribution before publication.

Apify integrations can send completed datasets to Google Sheets, webhooks, Make, Zapier, or custom services.

### Run with the Apify API

Replace `APIFY_TOKEN` with your token.

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~upc-barcode-lookup/runs?token=APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "codes": ["737628064502", "3017620422003"],
    "sources": ["openFoodFacts", "upcItemDb"],
    "maxItems": 2
  }'
```

To wait for completion and receive dataset items directly:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~upc-barcode-lookup/run-sync-get-dataset-items?token=APIFY_TOKEN&timeout=300" \
  -H "Content-Type: application/json" \
  -d '{"codes":["737628064502"],"sources":["openFoodFacts"]}'
```

### JavaScript integration

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/upc-barcode-lookup').call({
  codes: ['737628064502', '3017620422003'],
  sources: ['openFoodFacts', 'upcItemDb'],
  maxItems: 2,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Python integration

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/upc-barcode-lookup').call(run_input={
    'codes': ['737628064502', '3017620422003'],
    'sources': ['openFoodFacts', 'upcItemDb'],
    'maxItems': 2,
})

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item)
```

### Use with Apify MCP

Add this Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/upc-barcode-lookup"
```

#### Claude Desktop setup

Add this server object to the `mcpServers` section of Claude Desktop's configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/upc-barcode-lookup"
    }
  }
}
```

#### Cursor setup

Open Cursor Settings, choose MCP, add a remote server named `apify`, and use:

```text
https://mcp.apify.com?tools=automation-lab/upc-barcode-lookup
```

#### VS Code setup

Add the same remote HTTP URL to your VS Code MCP server configuration and name the server `apify`.

Example prompts:

- "Look up these UPC codes and return title, brand, and match status: 737628064502, 3017620422003."
- "Validate this supplier barcode batch with Open Food Facts and list unmatched codes."
- "Deduplicate these EAN values and export source-attributed product identities."

### Scheduling and monitoring

Create an Apify Task with a fixed source selection and schedule it for recurring catalog checks.

A schedule reruns the current barcode batch; it does not automatically compare datasets or send change alerts. Use a webhook or downstream workflow to compare `matchStatus`, fields, and `lookedUpAt` with an earlier run.

For stable monitoring:

- preserve the prior dataset ID;
- compare by `gtin`;
- treat null-to-value changes as enrichment;
- retry `lookup_error` before recording a source change;
- keep source selection consistent between runs.

### Legality and responsible use

Barcode numbers identify trade items, but product metadata and images can have separate rights and license terms.

Use the Actor only for lawful purposes. Review each selected database's terms, attribution requirements, and reuse license. Do not assume an image URL grants permission to republish the image.

Avoid using source-contributed data as the sole basis for safety, medical, allergen, ownership, or regulatory decisions. Verify high-impact facts with an authoritative provider.

The Actor sends only submitted barcodes to the selected public endpoints. Do not put secrets, customer personal data, or internal notes in the barcode input.

### Troubleshooting

#### Why did my run fail before returning rows?

Check the log for an invalid length, non-digit character, or incorrect check digit. Correct the source barcode instead of guessing a replacement.

#### Why is `matchStatus` equal to `not_found`?

The code is valid, but none of the selected sources returned a product. Try a catalog suited to the product type or confirm the code with the supplier.

#### Why is `matchStatus` equal to `lookup_error`?

Every selected source failed. Reduce concurrency, wait for a public rate limit to reset, or select another source.

#### Why are some product fields null?

Public database coverage varies by field. Select another compatible source to fill gaps, or retain null as an explicit unknown.

#### Why did two input rows become one result?

They normalized to the same validated barcode. Use `duplicateCount` to see how many times it appeared.

#### Does this Actor tell me who owns a GS1 company prefix?

No. It validates identifier structure and looks up public product metadata; it does not provide proprietary GS1 ownership data.

#### Can it generate a barcode image?

No. Use [Barcode Generator](https://apify.com/automation-lab/barcode-generator) to create barcode images from values you are authorized to encode.

### Related automation-lab Actors

- [Barcode Generator](https://apify.com/automation-lab/barcode-generator) — generate barcode images after preparing identifiers.
- [Open Food Facts Scraper](https://apify.com/automation-lab/openfoodfacts-scraper) — collect broader Open Food Facts product datasets when lookup by a known code is not enough.
- [Dataset Dedup](https://apify.com/automation-lab/dataset-dedup) — remove duplicates from larger downstream Apify datasets.

### FAQ

#### Can I submit UPC and EAN codes together?

Yes. Every code is validated according to its length and returned with its detected format.

#### Are duplicate barcodes charged twice?

No. One item event is emitted per unique saved code; `duplicateCount` preserves the number of submitted occurrences.

#### Does a valid check digit guarantee a real product?

No. It proves structural consistency only. Use `matchStatus` and source evidence to evaluate whether public metadata exists.

#### Is a result guaranteed to be current?

No. The Actor reports what selected public sources return at lookup time and records that time in `lookedUpAt`.

#### Can I choose only one database?

Yes. A single-source run is useful when licensing, reproducibility, or catalog scope matters more than enrichment breadth.

#### Does the Actor use a proxy or browser?

No. It calls credential-free public JSON APIs directly, which keeps runtime and memory low.

# Actor input Schema

## `codes` (type: `array`):

Barcodes to look up. Strings preserve leading zeroes; spaces and hyphens are accepted. Invalid check digits fail the run before any lookup.

## `sources` (type: `array`):

Public product databases to query in order. Select multiple sources to fill missing fields and retain per-source lookup status.

## `maxItems` (type: `integer`):

Maximum number of unique, valid barcode records to save. Duplicate input codes are counted on one output record.

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

Number of barcodes processed concurrently. Keep this low for public API rate limits.

## Actor input object example

```json
{
  "codes": [
    "737628064502",
    "3017620422003"
  ],
  "sources": [
    "openFoodFacts",
    "upcItemDb"
  ],
  "maxItems": 20,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `dataset` (type: `string`):

Validated UPC, EAN, and GTIN product lookup records.

# 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 = {
    "codes": [
        "737628064502",
        "3017620422003"
    ],
    "sources": [
        "openFoodFacts",
        "upcItemDb"
    ],
    "maxItems": 20,
    "maxConcurrency": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/upc-barcode-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 = {
    "codes": [
        "737628064502",
        "3017620422003",
    ],
    "sources": [
        "openFoodFacts",
        "upcItemDb",
    ],
    "maxItems": 20,
    "maxConcurrency": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/upc-barcode-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 '{
  "codes": [
    "737628064502",
    "3017620422003"
  ],
  "sources": [
    "openFoodFacts",
    "upcItemDb"
  ],
  "maxItems": 20,
  "maxConcurrency": 5
}' |
apify call automation-lab/upc-barcode-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/upc-barcode-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/wEGKrX3oXgGpevv1T/builds/TaXtlYVNRhGEq8J75/openapi.json
