# EAN / GTIN Product Image Extractor (`khadinakbar/ean-gtin-image-extractor`) Actor

Resolve EAN-8, EAN-13, UPC-A, and GTIN-14 barcodes into product image galleries with title, brand, and provenance. HTTP-first against Open Food/Beauty/Pet/Products Facts plus UPCitemdb free plan. Validates GS1 checksums, batches codes, never fabricates images. MCP-ready.

- **URL**: https://apify.com/khadinakbar/ean-gtin-image-extractor.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** E-commerce, AI, MCP servers
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 product image set founds

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 Product Image Extractor

Catalog, PIM, and marketplace teams paste **EAN-8, UPC-A, EAN-13, or GTIN-14** barcodes and receive **primary plus gallery product image URLs**, with product name and brand when public catalogs expose them. Each row includes source provenance and a collection timestamp so agents can trust what they store. Built for enrichment workflows on Apify with scheduling, API, and MCP access.

The Actor is HTTP-first against free Open Facts catalogs (food, beauty, pet, and general packaged goods) with a bounded UPCitemdb Explorer free-plan fallback. It validates GS1 check digits, deduplicates codes, and only persists real HTTPS image URLs.

### Best fit for this Actor

- Choose this Actor when you already hold retail barcodes and need image URLs plus light identity fields for PIM, listing QA, or agent enrichment.
- It works well for food, beauty, pet, and many packaged-goods codes covered by Open Facts, with UPCitemdb helping on broader retail UPCs.
- For Amazon listing research after you have an ASIN, start with [Amazon Product Intelligence](https://apify.com/khadinakbar/amazon-product-intelligence), then pass confirmed barcodes here for image galleries.
- For supplier pack-shot context from customs filings, pair it with [ImportYeti Scraper](https://apify.com/khadinakbar/importyeti-scraper) when your workflow needs importer/supplier evidence next to barcode images.

### PIM backfill workflow

A catalog manager exports a list of retail EAN-13 codes from their PIM. They paste Nutella (`3017620422003`) and LIFEWTR (`012000161155`) into **Barcode codes**, keep max images at 10, and run. The dataset returns primaryImageUrl, imageUrls, productName, brand, and source for each found code. They export JSON into the PIM image field and schedule the same input weekly so new SKUs pick up fresh public gallery URLs.

### Quick start input

```json
{
  "codes": ["3017620422003", "012000161155"],
  "maxImagesPerProduct": 10,
  "concurrency": 2
}
```

Open the Input tab in Console for every field. Prefill already includes the two codes above so a first run stays cheap.

### Input reference

| Field | What it controls |
| --- | --- |
| `codes` | EAN-8 / UPC-A / EAN-13 / GTIN-14 strings (spaces and dashes stripped). Max 100 unique valid codes. |
| `maxImagesPerProduct` | Gallery URL cap per barcode (1–20). Primary image is always `imageUrls[0]` when present. |
| `maxCodes` | Hard cap after dedupe for quality tests. |
| `concurrency` | Parallel lookups (1–8). Keep 1–3 for free-catalog courtesy. |
| `sources` | Optional filter: `openfoodfacts`, `openbeautyfacts`, `openpetfoodfacts`, `openproductsfacts`, `upcitemdb`. |
| `includeEmptyRows` | When true, write unbilled NOT_FOUND rows for valid codes with zero images. |

### What data you receive

One dataset item is one barcode that resolved to at least one real image URL (unless you enable empty rows).

```json
{
  "ean": "3017620422003",
  "gtin": "3017620422003",
  "normalizedGtin": "03017620422003",
  "format": "EAN-13",
  "productName": "Nutella",
  "brand": "Nutella, Ferrero",
  "imageUrls": [
    "https://images.openfoodfacts.org/images/products/301/762/042/2003/front_en.879.400.jpg"
  ],
  "primaryImageUrl": "https://images.openfoodfacts.org/images/products/301/762/042/2003/front_en.879.400.jpg",
  "imageCount": 1,
  "source": "openfoodfacts",
  "confidence": 0.88,
  "scrapedAt": "ISO-8601 collection time"
}
```

| Field | Description |
| --- | --- |
| `ean` / `gtin` | Validated barcode digits |
| `normalizedGtin` | Zero-padded GTIN-14 for dedupe |
| `productName` / `brand` | From the winning source when present |
| `primaryImageUrl` / `imageUrls` | Real HTTPS image URLs only |
| `source` / `confidence` | Provenance plus heuristic confidence |
| `scrapedAt` | Collection timestamp for the row |

Download the dataset as JSON, CSV, Excel, or HTML from the run Output tab.

### Pricing

#### Startup billing and empty runs

The `apify-actor-start` event costs **$0.00005 per startup unit**. Apify charges one startup unit per GB of allocated memory, with a minimum of one unit, so a 2 GB run incurs two units. This startup charge still applies when input is invalid, no results are found, or an upstream request fails. Statements about free, unbilled, or skipped results refer only to the corresponding result event; they do not waive the startup charge. Apify platform usage is included in the event prices and is not passed through as an additional customer charge. Check the live [Pricing tab](https://apify.com/khadinakbar/ean-gtin-image-extractor/pricing) for current events, tiers, and rates. Result limits cap result events, not the entire run cost.

This Actor uses **Pay per event** with **platform usage included**. Check the live **Pricing** tab for the current schedule.

| Event | Typical price | When charged |
| --- | ---: | --- |
| `apify-actor-start` | $0.00005 | Once per run |
| `image-set-found` | $0.008 | Once per barcode that returns at least one image |

Worked example: two found barcodes in a run allocated at most 1 GB ≈ `$0.00005 + 2 × $0.008` event charge, with Apify platform usage included. Invalid checksums and codes with no images skip the `image-set-found` event.

### Outcomes and agent readback

| Outcome | Meaning |
| --- | --- |
| `COMPLETE` | Every valid code returned images |
| `PARTIAL` | Mix of found and not-found or upstream gaps |
| `VALID_EMPTY` | Valid codes, no images found |
| `INVALID_INPUT` | Empty input or every code missed checksum/format validation |
| `UPSTREAM_FAILED` | Providers returned transport issues with no successful miss responses |

Read `OUTPUT` / `RUN_SUMMARY` for `outcome`, `itemsPushed`, and `chargedImageSets`. Provenance lives on each row in `source` and `scrapedAt`.

### API / MCP example

```bash
curl "https://api.apify.com/v2/acts/khadinakbar~ean-gtin-image-extractor/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"codes":["3017620422003"],"maxImagesPerProduct":5,"concurrency":1}'
```

On Apify MCP this Actor appears as `apify--ean-gtin-image-extractor`. Pass `codes`, then read dataset rows for `primaryImageUrl` and provenance.

#### Agent prompt card

> Resolve these product barcodes to image galleries. Use `ean-gtin-image-extractor` with `codes`. Expect one dataset row per found barcode with `primaryImageUrl`, `imageUrls`, `source`, and collection time. Treat missing codes as `VALID_EMPTY` scope, and confirm cost against the Pricing tab before large batches.

### Best results guidance

- Provide canonical retail barcodes (EAN-13 / UPC-A) rather than internal SKUs.
- Start with Open Facts sources for food, beauty, and pet packs; confirm electronics and general retail with `upcitemdb` when needed.
- Keep concurrency low and validate checksums in your own sheet first so billed rows stay productive.
- Schedule focused batches when catalogs refresh so agents always see current public image URLs.

### Builder's note

I designed this Actor for image-set resolution with provenance rather than nutrition dumps or paid per-file downloads. In my testing, a checksum gate plus a free multi-source waterfall kept MCP payloads flat and honest: found codes charge once, unknown codes finish empty, and every saved URL is a real HTTPS link from the winning catalog.

### Legal / responsible use

Use only for legitimate catalog, research, and enrichment workflows under applicable laws and site terms for the public catalogs you query. Product images remain copyright of their owners; this Actor returns public URLs and grants no redistribution rights.

Open Food Facts and related Open Facts projects are trademarks of their owners. This independent Actor is not affiliated with, associated with, or endorsed by Open Food Facts. UPCitemdb is a trademark of its owner. This independent Actor is not affiliated with, associated with, or endorsed by UPCitemdb. GS1 is a trademark of GS1. This Actor is not affiliated with or endorsed by GS1.

### Support

Open an Issue on the Actor page with the barcode and `RUN_SUMMARY.outcome` when a result needs review.

# Actor input Schema

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

EAN-8, UPC-A (GTIN-12), EAN-13 (GTIN-13), or GTIN-14 codes to resolve. Spaces and dashes are stripped. Each code is checksum-validated; invalid codes are skipped and reported in RUN_SUMMARY. Maximum 100 unique valid codes per run. Do not pass ASINs or SKUs here.

## `maxImagesPerProduct` (type: `integer`):

Cap on gallery URLs returned for one barcode. Primary image is always imageUrls\[0] when present. Range 1-20. Lower this for lean MCP payloads.

## `maxCodes` (type: `integer`):

Hard cap on unique valid codes processed in this run after dedupe. Use a small value for quality tests. Default 100.

## `concurrency` (type: `integer`):

How many barcodes to resolve in parallel. Keep low (1-3) to respect Open Facts and UPCitemdb free-tier rate limits. Default 3.

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

Optional source filter using ids: openfoodfacts, openbeautyfacts, openpetfoodfacts, openproductsfacts, upcitemdb. Leave empty to try Open Facts family first, then UPCitemdb free plan. Restrict only when you know the product category.

## `includeEmptyRows` (type: `boolean`):

When true, write unbilled dataset rows for valid codes with no images. Default false so the dataset stays image-only and billing matches rows.

## Actor input object example

```json
{
  "codes": [
    "3017620422003",
    "012000161155"
  ],
  "maxImagesPerProduct": 10,
  "maxCodes": 10,
  "concurrency": 2,
  "includeEmptyRows": false
}
```

# Actor output Schema

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

Dataset items with barcode, title, brand, primaryImageUrl, imageUrls, source, and confidence.

## `summary` (type: `string`):

OUTPUT record with outcome, itemsPushed, charge counters, and diagnostics.

## `runSummary` (type: `string`):

Machine-readable RUN_SUMMARY mirroring OUTPUT.

# 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": [
        "3017620422003",
        "012000161155"
    ],
    "maxImagesPerProduct": 10,
    "maxCodes": 10,
    "concurrency": 2,
    "includeEmptyRows": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/ean-gtin-image-extractor").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": [
        "3017620422003",
        "012000161155",
    ],
    "maxImagesPerProduct": 10,
    "maxCodes": 10,
    "concurrency": 2,
    "includeEmptyRows": False,
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/ean-gtin-image-extractor").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": [
    "3017620422003",
    "012000161155"
  ],
  "maxImagesPerProduct": 10,
  "maxCodes": 10,
  "concurrency": 2,
  "includeEmptyRows": false
}' |
apify call khadinakbar/ean-gtin-image-extractor --silent --output-dataset

```

## MCP server setup

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

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/jYFsV6ofEveVItpTh/builds/kJXN70ElMAfWwadmI/openapi.json
