# IKEA Products Scraper - Prices, Ratings & Images (`scrapyx/ikea-products-scraper`) Actor

Scrapes IKEA products from the search endpoint ikea.com itself calls: price with currency, rating and review count, images, colours, measurements and category path. Reads the price from where it actually lives, and states the 1,000-product reachability ceiling.

- **URL**: https://apify.com/scrapyx/ikea-products-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.05 / 1,000 results

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?

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

## IKEA Products Scraper — Prices, Ratings & Images

Reads IKEA products from the JSON endpoint **ikea.com's own search calls**. No
key, no auth, no HTML parsing.

### What you get

| `recordType` | One per | Carries |
| --- | --- | --- |
| `PRODUCT` | product | range name, product type and a joined full name, price with currency, rating and review count, measurements, main and contextual images, colours, category path, business structure, availability, and the product-page URL |
| `SEARCH_SUMMARY` | search term | IKEA's own match count, **how much of it is actually reachable**, and IKEA's related searches |
| `ERROR` | failed input | a named reason |

### There is no pagination, and the match count is a false promise

`offset` is not an optional extra — **every value returns HTTP 400**. The only
lever is `size`, and it is capped:

```
size=1000  ->  1000 products  (7.5 MB of JSON)
size=2000  ->  HTTP 400
```

So a term whose count reads 9,231 will yield **1,000 products, ever**. The
honest total and the unreachable remainder sit in the same object, and nothing
marks the difference.

Every summary reports `totalMatching`, `estimatedReachable`,
`estimatedUnreachable` and `hitReachabilityCeiling`. Because narrowing the
query is the *only* route to the rest, IKEA's own **related searches** are
returned on the summary row — that's what they're for here.

### The price is not where it looks like it is

The product object carries `priceNumeral` and `currencyCode` at its top
level — exactly where a reader would go — and **both are `null` on every row**.
The real values live under `salesPrice`:

```
product.priceNumeral           null      <- decoy
product.currencyCode           null      <- decoy
product.salesPrice.numeral     99.99     <- the price
product.salesPrice.currencyCode "USD"    <- the currency
```

A scraper reading the obvious fields produces a dataset where every price is
null and nothing errors. This actor reads the real ones and **also emits the
decoys** as `priceNumeralDecoy` / `currencyCodeDecoy`, so you can see for
yourself they're empty rather than wonder whether something was dropped.

### `name` is the range, not the product

IKEA names *ranges*, not products: `name` is `"MICKE"` and `typeName` is
`"Desk"`. Neither alone is a usable title — "MICKE" means nothing to a reader.
Both are emitted, plus `fullName` ("MICKE Desk") for the common case.

### The market selects a catalogue, not a translation

Same query, same day:

```
/us/en/  ->  196 products, USD
/gb/en/  ->  259 products, GBP
/de/de/  ->  528 products, EUR
```

So a run against another market is a **different product set**, not the same
one relabelled. Market and language are recorded on every row, and product URLs
come back market-correct. A market or language that doesn't exist is an honest
HTTP 404 — `/us/zz/` fails rather than silently falling back to English.

### Honest, for the record

- a nonsense term → zero products with a count of 0, not an unfiltered baseline
- an empty term → a genuine browse-everything result (9,231 matches), not an
  error, exposed as the **Browse the whole catalogue** toggle
- an unknown `types` value → HTTP 400

### Notes

- One request per search term. A `size=1000` response is roughly 7.5 MB, so
  concurrency defaults to 2.
- `sik.search.blue.cdtapps.com/robots.txt` names no AI bot and carries no rule
  matching this path; `www.ikea.com` allows `/search/`. No WAF observed.

# Actor input Schema

## `queries` (type: `array`):

What to search for, e.g. 'desk', 'billy bookcase', 'lamp'. Each term is ONE request — this endpoint has no pagination at all, so more products means more (narrower) terms. IKEA's own related searches are returned on the summary row to help with exactly that.

## `browseAll` (type: `boolean`):

Adds an empty query, which IKEA treats as browse-everything rather than an error. Still subject to the 1,000-product ceiling.

## `market` (type: `string`):

Two-letter country code: us, gb, de, se, au... This selects a DIFFERENT catalogue and currency, not a translation — the same query returned 196 products in US, 259 in GB and 528 in DE. An unknown market is refused with HTTP 404.

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

Two-letter code, and it must be one the market actually serves — /us/zz/ is a 404. Common pairs: us/en, gb/en, de/de, se/sv.

## `maxProductsPerQuery` (type: `integer`):

1,000 is IKEA's hard cap and there is no way past it: any `offset` value returns HTTP 400 and `size=2000` is refused. A 1,000-product response is about 7.5 MB of JSON. If a term reports more matches than this, the summary says how many are unreachable.

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

Kept low: a large size makes each response several megabytes.

## `minRequestInterval` (type: `integer`):

Politeness pacing shared across all workers.

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

Optional and OFF by default. No WAF was observed on this endpoint.

## Actor input object example

```json
{
  "queries": [
    "desk",
    "office chair"
  ],
  "browseAll": false,
  "market": "us",
  "language": "en",
  "maxProductsPerQuery": 200,
  "maxConcurrency": 2,
  "minRequestInterval": 1,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {
    "queries": [
        "desk"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/ikea-products-scraper").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 = { "queries": ["desk"] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/ikea-products-scraper").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 '{
  "queries": [
    "desk"
  ]
}' |
apify call scrapyx/ikea-products-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/ikea-products-scraper"
        }
    }
}

```

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/RCef1WBdNd3Gdkjf9/builds/IcguhA7Ti8KVyssEe/openapi.json
