# IKEA Price & Stock Tracker - 51 Countries (KR, JP, US, EU) (`magenta_courser/ikea-prices-all-countries`) Actor

Enter IKEA article numbers, product URLs, product names or category IDs plus countries; get one row per product and country with local price, EUR/USD price (ECB rates), sale price, online availability, rating and reviews, plus a free cheapest-country summary and price change since your last run.

- **URL**: https://apify.com/magenta_courser/ikea-prices-all-countries.md
- **Developed by:** [SUNGHWAN CHO](https://apify.com/magenta_courser) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 product in one countries

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

## IKEA Price Comparison by Country

Enter IKEA article numbers (or product URLs, product names, category IDs) and a list of countries; get one row per product and country with the local price, the price in EUR and USD, sale price, online availability, rating and review count, plus a free **cheapest-country** summary row per product and the **price change since your last run**.

Covers IKEA **South Korea, Japan and China** (ikea.cn) next to the US, Canada, 25+ European countries, Australia, New Zealand, Southeast Asia, the Gulf states, India, Israel, Egypt, Morocco and Latin America: 51 countries in total.

### What you get

| Field | Example (KR) | Notes |
|---|---|---|
| `country` | `KR` | ISO code |
| `articleNumber` | `00522047` | Local article number in that country |
| `articleNumberGlobal` | `20522046` | IKEA's global number, the same in every country. Used to match products across countries |
| `name`, `productType` | `BILLY 빌리`, `책장` | In the local language (or English, see `language`) |
| `nameEnglish`, `productTypeEnglish` | `BILLY`, `Bookcase` | |
| `color`, `size` | `화이트`, `80x28x202 cm` | |
| `currency`, `price` | `KRW`, `89900` | Current price as a number |
| `regularPrice`, `isDiscounted`, `discountPercent` | `null`, `false`, `null` | Pre-sale price when IKEA shows one |
| `priceEUR`, `priceUSD`, `fxRateDate` | `60.4`, `67.23`, `2026-10-29` | European Central Bank reference rates |
| `offerText`, `offerForMembersOnly` | `In-store only price $65.00`, `true` | IKEA Family / in-store offers as shown by IKEA |
| `onlineSellable` | `true` | Can be bought online in that country |
| `storesChecked`, `storesInStock`, `storeStock` | `1`, `1`, `373 광명점: HIGH_IN_STOCK` | Only when you set `storeIds` |
| `rating`, `reviewCount` | `4.5`, `2117` | |
| `previousPrice`, `priceChange`, `priceChangePercent`, `previousOnlineSellable`, `isNewProduct`, `previousScrapedAt` | | Compared with your last run |
| `url`, `imageUrl`, `category`, `scrapedAt` | | |

Row types (`type` field):

- `productCountry` with `found: true`: one product in one country. **This is the only charged row.**
- `productCountry` with `found: false` (free): an article number you asked for is not sold in that country (`notFoundReason`: `notSoldInCountry` or `countryFailed`). A number that is not found in any selected country gives one row with `country: null` and `notFoundReason` `unknownArticleNumber` or `retired`.
- `cheapestCountry` (free): per product, the cheapest and most expensive country in EUR/USD, `spreadPercent`, all prices in EUR (`pricesEUR`) and the countries where it is not sold (`notFoundIn`).
- `storeStock` (free): one row per product and store when you set `storeIds`.

The dataset has two views: **Prices by country** and **Cheapest country per product**. `RUN_SUMMARY` in the key-value store lists each country's status (`completed`, `partial`, `failed`), requests and errors.

### Input

Only one field is needed: `articleNumbers` (or `searchQueries` / `categoryIds`). Everything else has defaults.

```json
{
  "articleNumbers": ["20522046", "https://www.ikea.com/kr/ko/p/billy-bookcase-white-00522047/"],
  "countries": ["KR", "JP", "CN", "US", "DE", "GB"]
}
```

- **Article numbers from any country work.** Korea, Japan, China and Australia give many products their own local numbers (BILLY 80x28x202 white is `20522046` in the US and France, `00522047` in Korea, Japan and China, `10616564` in Australia). The Actor first looks the number up directly, then matches the rest through `articleNumberGlobal`.
- `searchQueries`: IKEA product names such as `BILLY`, `KALLAX` work in every country. Generic words only work in the local language.
- `categoryIds`: e.g. `10382` (bookcases) or a category URL.
- `maxResultsPerSearch`: products per search or category and country (default 24).
- `storeIds`: `country:storeId`, e.g. `KR:373` (Gwangmyeong), `US:399` (Burbank).
- `language`: `local` (default) or `english`. France, Denmark, Italy, Poland, Slovakia, Hungary, Romania, Croatia, Slovenia, Serbia, Israel, Chile and Colombia have no English IKEA site and stay in the local language.
- `outputMode: changesOnly`: for scheduled monitoring, saves and charges only products whose price, pre-sale price or online availability changed, or that are new.
- `historyStoreName`: named key-value store with the last prices (default `ikea-prices-history`). Use one name per monitoring project.

### Pricing

Pay per event: **`product-country`**, charged once per product row with `found: true`. Not-found rows, cheapest-country rows, store stock rows and failed countries are free. If you set a maximum cost per run, the Actor stops cleanly at that limit and tells you in the status message.

Example: 10 products x 9 countries = up to 90 charged rows.

### How it works and limits

- Data comes from IKEA's public product search service, the same JSON the IKEA website loads in your browser. It needs no login and no keys, and the service's robots.txt allows all paths. No product page HTML is downloaded.
- **Prices are compared as shown.** US and Canadian prices exclude sales tax; European, Korean, Japanese, Chinese and Australian prices include VAT/GST. Delivery and assembly are not included.
- Sizes can differ between countries (inches vs cm, US-specific variants). Products only match when IKEA gives them the same `articleNumberGlobal`. Some countries sell an older or regional version under another number. For example, Germany and the UK sell BILLY 80x28x202 as `00263850`, not `20522046`, so `20522046` is reported as not sold there. Add both numbers if you want both.
- EUR/USD conversion uses the [ECB euro reference rates](https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html) of the latest working day. Currencies without an ECB rate (SAR, AED, KWD, QAR, BHD, OMR, JOD, EGP, CLP, COP, RSD, MAD) have empty `priceEUR`/`priceUSD` and are left out of the cheapest-country comparison. They are listed in `notComparedCountries`.
- `offerText` is IKEA's own text, e.g. IKEA Family member prices. `price` is the regular public price.
- Store stock is IKEA's store-level status (`HIGH_IN_STOCK`, `LOW_IN_STOCK`, `OUT_OF_STOCK`), not a unit count.
- Not available (other IKEA platforms): Taiwan, Hong Kong, Turkey, Greece, Iceland, Cyprus, Indonesia, Peru, Luxembourg. Ukraine currently lists no products.
- For a product family with more than 1,000 items, matching a local article number can miss. Use the local number in that case.

### Tips

- Schedule a weekly run with `outputMode: changesOnly` to get only price drops, price increases and new sales.
- To find where a product is cheapest worldwide, select many countries; the `cheapestCountry` row is free.

# Actor input Schema

## `articleNumbers` (type: `array`):

IKEA article numbers (8 digits, with or without dots, e.g. 205.220.46 or 20522046) or IKEA product page URLs, one per line. Each product is looked up in every selected country. Korea, Japan, China and Australia use their own article numbers for many products; the Actor matches them automatically through IKEA's global article number (articleNumberGlobal), so you can paste a number from any country. Add at least one of: article numbers, search queries or category IDs.

## `countries` (type: `array`):

Countries to compare. Default: KR, JP, CN, US, DE, GB, FR, SE, AU. One charged row per product and country where IKEA sells it. Not available here (other IKEA platforms): Taiwan, Hong Kong, Turkey, Greece, Iceland, Cyprus, Indonesia, Peru, Luxembourg.

## `searchQueries` (type: `array`):

Optional. Search IKEA in every selected country and return the top results, e.g. BILLY, KALLAX, POÄNG. IKEA product names work in every country; generic words only work in the country's language (sofa / 소파 / ソファ / 沙发), so use product names for cross-country comparisons. Results of different countries are matched by articleNumberGlobal.

## `categoryIds` (type: `array`):

Optional. IKEA category ID (the number at the end of a category URL, e.g. 10382 for bookcases, st002 for shelving units) or a category URL such as https://www.ikea.com/us/en/cat/bookcases-10382/. Category IDs are mostly the same in every country.

## `maxResultsPerSearch` (type: `integer`):

Optional. How many products to return for each search query or category in each country. Default 24, maximum 1000. Each product and country is one charged row: 2 queries x 6 countries x 24 = up to 288 rows.

## `storeIds` (type: `array`):

Optional. Physical stores to check stock in, as country:storeId, e.g. KR:373 (IKEA Gwangmyeong), US:399 (IKEA Burbank). The store ID is the 3-digit IKEA store number. Each product row gets storesChecked, storesInStock and storeStock, and every product x store gets a free row of type storeStock. Adds one request per store per 20 products.

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

Language of name, productType, color and category. "english" uses the country's English IKEA site where one exists; France, Denmark, Italy, Poland, Slovakia, Hungary, Romania, Croatia, Slovenia, Serbia, Israel, Chile and Colombia have none and stay in the local language. nameEnglish and productTypeEnglish are filled in either way when IKEA has an English name.

## `currencyConversion` (type: `boolean`):

Add priceEUR and priceUSD using the European Central Bank euro reference rates of the latest working day (free public source, about 30 currencies). Currencies without an ECB rate (e.g. SAR, AED, KWD, QAR, BHD, OMR, JOD, EGP, CLP, COP, RSD, MAD) keep priceEUR/priceUSD empty and are left out of the cheapest-country comparison.

## `includeSummary` (type: `boolean`):

For each product, add one free row of type cheapestCountry: cheapest and most expensive country, price in EUR/USD and the spread between them.

## `includeEnglishNames` (type: `boolean`):

Fill nameEnglish and productTypeEnglish. When no selected country is English-language, this costs one extra (free) request per country per 20 products.

## `compareWithLastRun` (type: `boolean`):

Add previousPrice, priceChange, priceChangePercent, previousOnlineSellable and isNewProduct to each row, compared with the last run in the same country. The last prices are kept in a named key-value store in your account, so scheduled runs line up automatically.

## `outputMode` (type: `string`):

"changesOnly" saves (and charges) only products that are new or whose price, regular (pre-sale) price or online availability changed since the last run. The first run saves everything. Needs "Compare with last run".

## `historyStoreName` (type: `string`):

Named key-value store that keeps the last price per country and article number. Use a different name for each separate monitoring project.

## `proxyConfiguration` (type: `object`):

Keep the default Apify proxy (datacenter). In our tests IKEA's search API answered every datacenter request; switch to RESIDENTIAL only if you see repeated HTTP 403 errors.

## `maxRequests` (type: `integer`):

Optional. Upper limit on HTTP requests for the whole run, retries included. Default: 3x the expected number + 10.

## `maxRunMinutes` (type: `integer`):

Optional. Stop sending new requests after this many minutes (default 30) and save what was collected.

## Actor input object example

```json
{
  "articleNumbers": [
    "20522046",
    "00579755"
  ],
  "countries": [
    "KR",
    "JP",
    "CN",
    "US",
    "DE",
    "GB"
  ],
  "maxResultsPerSearch": 24,
  "language": "local",
  "currencyConversion": true,
  "includeSummary": true,
  "includeEnglishNames": true,
  "compareWithLastRun": true,
  "outputMode": "all",
  "historyStoreName": "ikea-prices-history",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Product-country rows (charged), cheapest-country summary rows, not-found rows and store stock rows (free).

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

Per-country status (completed, partial, failed), requests, products found and errors. Not billed.

# 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 = {
    "articleNumbers": [
        "20522046",
        "00579755"
    ],
    "countries": [
        "KR",
        "JP",
        "CN",
        "US",
        "DE",
        "GB"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("magenta_courser/ikea-prices-all-countries").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 = {
    "articleNumbers": [
        "20522046",
        "00579755",
    ],
    "countries": [
        "KR",
        "JP",
        "CN",
        "US",
        "DE",
        "GB",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("magenta_courser/ikea-prices-all-countries").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 '{
  "articleNumbers": [
    "20522046",
    "00579755"
  ],
  "countries": [
    "KR",
    "JP",
    "CN",
    "US",
    "DE",
    "GB"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call magenta_courser/ikea-prices-all-countries --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,magenta_courser/ikea-prices-all-countries"
        }
    }
}
```

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/HaZBZ1ZOnPMhZEsyK/builds/BYNBea4l4OAzZRJTP/openapi.json
