# Product ID Mapper — EAN to ASIN, Google, idealo & Bol IDs (`anyprice/product-id-mapper`) Actor

Map EAN/GTIN barcodes to marketplace product IDs: Amazon ASIN, Google Shopping catalog ID, idealo product ID and Bol product ID, with product URLs. 8 European countries, up to 50 EANs per run.

- **URL**: https://apify.com/anyprice/product-id-mapper.md
- **Developed by:** [Anyprice](https://apify.com/anyprice) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 marketplace lookups

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/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

## Product ID Mapper — EAN to ASIN, Google, idealo & Bol IDs

Map EAN, GTIN and UPC barcodes to marketplace product IDs: EAN to ASIN for Amazon, plus the Google Shopping catalog ID, the idealo product ID and the Bol product ID, each with its product URL. One GTIN lookup or UPC lookup covers all four marketplaces at once.

It works in 8 European countries, with up to 50 barcodes per run.

### What it does

Most product data starts with a barcode, but each marketplace has its own product ID: Amazon uses the ASIN, idealo and Bol have numeric product IDs, Google Shopping has a catalog ID. This Actor looks up every barcode on the marketplaces you pick and returns one row per barcode with:

- the product ID on each marketplace
- the product URL and the product name as that marketplace shows it
- `matches`: on how many marketplaces an ID was found

All marketplaces are queried at the same time, one job per marketplace, so a list of 50 barcodes on four marketplaces is still one run.

### Who it is for

- Sellers expanding to a new marketplace who need the ASIN or Bol ID for each EAN in their catalogue before they can list or match products.
- Price monitoring and repricing tools that track products by marketplace ID and need a reliable starting mapping.
- Data teams joining sales or ad data from Amazon, Google Shopping, idealo and Bol on one common key, the EAN.
- Anyone cleaning a product feed who wants to know which barcodes are not listed anywhere.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `eans` | array of strings | (required) | 1 to 50 EAN-13, EAN-8, UPC-12 or GTIN-14 barcodes |
| `country` | string | `de` | `de`, `at`, `fr`, `it`, `es`, `uk`, `nl` or `be` |
| `platforms` | array of strings | all four | Any of `idealo`, `google_shopping`, `amazon`, `bol` |

Barcodes are trimmed and de-duplicated. Each one is checked for length and check digit; an invalid barcode gets its own free `invalid` row and is never sent to a marketplace.

Which marketplaces cover which country:

| Country | idealo | Google Shopping | Amazon | Bol |
|---|---|---|---|---|
| `de`, `fr`, `it`, `es`, `uk` | yes | yes | yes | no |
| `at` | yes | yes | no | no |
| `nl`, `be` | no | yes | yes | yes |

A selected marketplace that does not cover the country is marked `unsupported` and not charged. If none of the selected marketplaces covers it (for example only `bol` with `de`), the run stops with an input error.

#### Input example

```json
{
  "eans": ["4009803341163", "4006381333931"],
  "country": "nl",
  "platforms": ["idealo", "google_shopping", "amazon", "bol"]
}
```

### Output

One row per barcode, in input order.

| Field | Meaning |
|---|---|
| `ean`, `country` | The barcode and country |
| `status` | `found` if at least one marketplace found the product, `not_found` if none did, `error` if no marketplace could be checked, `invalid` for a bad barcode |
| `matches` | Number of marketplaces that returned a product ID |
| `platforms.amazon.product_id` | The ASIN |
| `platforms.google_shopping.product_id` | The Google Shopping catalog ID |
| `platforms.idealo.product_id` | The idealo product ID |
| `platforms.bol.product_id` | The Bol product ID |
| `platforms.<name>.url`, `.name` | Product URL and product name on that marketplace |
| `platforms.<name>.status` | `found`, `not_found`, `error` or `unsupported` |
| `platforms.<name>.errorCode` | Why that marketplace failed, if it did |
| `errorCode`, `error` | Why the row failed (`invalid_input` or `internal_error`) |

Example row for the Netherlands, where idealo is not available (IDs and names are illustrative):

```json
{
  "query": "4009803341163",
  "ean": "4009803341163",
  "country": "nl",
  "status": "found",
  "matches": 3,
  "platforms": {
    "idealo": { "status": "unsupported", "product_id": null, "url": null, "name": null },
    "google_shopping": { "status": "found", "product_id": "6029184473615502", "url": "https://www.google.com/shopping/product/6029184473615502?gl=nl", "name": "Example kitchen scale" },
    "amazon": { "status": "found", "product_id": "B0EXAMPL42", "url": "https://www.amazon.nl/dp/B0EXAMPL42", "name": "Example kitchen scale, stainless steel" },
    "bol": { "status": "found", "product_id": "9300000123456789", "url": "https://www.bol.com/nl/nl/p/example-kitchen-scale/9300000123456789/", "name": "Example kitchen scale" }
  }
}
```

`matches` is 3: Google Shopping, Amazon and Bol returned an ID, and idealo was skipped because it does not cover the Netherlands.

### Billing

Pay per event. The **Pricing** tab shows the current rates.

One `platform-lookup` event is charged for each marketplace that answers `found` or `not_found` for a barcode. A `not_found` answer is a completed lookup, so it is charged as well. In the example above, the row costs three events. Free of charge:

- invalid barcodes
- marketplaces marked `unsupported` for the country
- marketplace lookups that end in an error or timeout

Rows are written before charging. If your maximum cost per run is reached, you still get every row.

### Limits and errors

- 50 barcodes per run, one country per run.
- All marketplaces share an 890-second budget. A marketplace that has not answered by then gives a free `timeout` error for the barcodes still open. Set the run timeout to at least 960 seconds.
- Each marketplace has its own limit on lookups in progress for your account (idealo 50, Amazon 100, Google Shopping and Bol 1,000). Avoid starting several full runs at the same time.
- One marketplace failing does not affect the others.
- The run always ends as **Succeeded**. Check `status` on each row and on each marketplace.

| `errorCode` | Meaning |
|---|---|
| `invalid_input` | Not a valid barcode: wrong length, wrong check digit, or one digit repeated |
| `timeout` | The marketplace did not answer in time |
| `blocked` | The marketplace blocked this lookup |
| `free_limit_reached` | Your free Apify plan's allowance for that marketplace is used up |
| `concurrency_limit_reached` | Your other runs held all lookup capacity for that marketplace |
| `internal_error` | Any other failure |

### FAQ

**How does the EAN to ASIN match work?**
Amazon is searched for the barcode and the first search result is taken as the match. That is usually the right product, but not always. Compare `platforms.amazon.name` with your own product name before you rely on the ASIN.

**Why is a marketplace `found` but its `product_id` null?**
Google Shopping sometimes lists offers for a barcode without a catalog page. The lookup counts as found, but there is no catalog ID to return, so it does not add to `matches`.

**Does it return prices?**
No, only IDs, URLs and names. For prices by EAN across marketplaces, use a price comparison Actor.

**Can I convert ASINs back to EANs?**
No. The input must be barcodes.

Questions or higher limits: support@anyprice.dev

# Actor input Schema

## `eans` (type: `array`):

Up to 50 EAN-13, EAN-8, UPC-12 or GTIN-14 barcodes per run. Invalid barcodes get a free error row and are never sent to a marketplace.

## `country` (type: `string`):

Marketplace country. Bol covers NL and BE only; marketplaces that do not cover the country are marked unsupported and not charged.

## `platforms` (type: `array`):

Marketplaces to map. Each marketplace checked for an EAN is one charged lookup.

## Actor input object example

```json
{
  "eans": [
    "4006381333931",
    "4009803341163"
  ],
  "country": "de",
  "platforms": [
    "idealo",
    "google_shopping",
    "amazon",
    "bol"
  ]
}
```

# Actor output Schema

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

URL of the default dataset items. Check each row's status.

# 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 = {
    "eans": [
        "4006381333931",
        "4009803341163"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("anyprice/product-id-mapper").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 = { "eans": [
        "4006381333931",
        "4009803341163",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("anyprice/product-id-mapper").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 '{
  "eans": [
    "4006381333931",
    "4009803341163"
  ]
}' |
apify call anyprice/product-id-mapper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,anyprice/product-id-mapper"
        }
    }
}
```

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/mDPsFaaCUji89gVGd/builds/onKLHr28stR7zat8f/openapi.json
