# IKEA Products & Reviews Scraper (`abotapi/ikea-scraper`) Actor

Scrape IKEA products across 50+ markets. Extract names, prices, currencies, ratings, full reviews, colours, dimensions, images, categories, variants, badges and store availability. Supports search, category, item-number and URL inputs with filters and sorting.

- **URL**: https://apify.com/abotapi/ikea-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 product 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 Scraper

Extract products, prices, availability and reviews from **ikea.com** across 50+
country markets. Search by keyword, list a category, look up exact item numbers,
or paste product / category / search links. Every product comes back as one flat
record with pricing, ratings, colours, measurements, images, category path,
variants, and (optionally) the full marketing description, individual customer
reviews, and per-store stock.

### What you get

- **Product identity** - name, product type, item number(s), product URL, market
- **Pricing** - current price, formatted price, currency, discount, on-sale flag
- **Specials** - was/original price, savings amount, discount %, IKEA's own
  specials label (e.g. "IKEA Family price"), and the price's valid-from/to dates,
  whenever the product actually carries a markdown
- **Ratings & reviews** - average rating and review count on every product, plus
  each individual review's title, text, author, date and rating when detail
  enrichment is on
- **Attributes** - colours (name + hex), width / depth / height, material,
  category path, business area, quick facts, badges (e.g. best seller)
- **Media** - main image and the full product image gallery
- **Variants** - sibling colour/finish options with their own price, image, rating
- **Availability** (optional) - national and per-store stock: quantity, click &
  collect, home delivery, and stock status

### Markets

Pick your market from the **Market and language** dropdown, e.g. United States
(`us/en`), United Kingdom (`gb/en`), Germany (`de/de`), Switzerland – French
(`ch/fr`), Sweden (`se/sv`). Prices, currency, product range and site language
follow the chosen market. In URL mode the market is read straight from each link.

### Modes

- **Search** - keywords + sort + filters
- **Category** - category listing links (`.../cat/<slug>-<id>/`) or bare ids
- **Product item numbers** - exact IKEA item numbers, one full record each
- **Paste URLs** - product, category or search links, walked forward

#### Pasting a "room" or department link

A collection page such as `.../rooms/living-room/` is not itself a category, so
the actor reads the category list that page publishes (for US living room that
is 12 categories: sofas, armchairs, rugs, lighting and so on) and scrapes each
one. The run log names every category it walked, so you can see exactly what was
covered. Products that a room page only merchandises without listing a category
for are not included, so this is a broad sweep of the room rather than a
pixel-perfect copy of the page.

Some links are not product listings at all: `.../offers/`, `.../new/`,
`.../campaigns/` and the bare `.../rooms/` index publish no category. Those are
reported in the log and skipped rather than turned into a keyword guess, so you
get an empty run with an explanation instead of unrelated products. Paste a
`.../cat/<name>-<id>/` link or a search link to scrape products from those
areas.

### Example input

```json
{
  "mode": "search",
  "market": "us/en",
  "searchTerms": ["bookcase"],
  "sortBy": "PRICE_LOW_TO_HIGH",
  "maxItems": 50,
  "fetchDetails": true,
  "maxReviews": 20,
  "includeAvailability": true
}
```

### Example output

> The record below is illustrative sample data.

```json
{
  "kind": "product",
  "id": "00000000",
  "itemNo": "00000000",
  "itemType": "ART",
  "name": "SAMPLE",
  "typeName": "Bookcase",
  "description": "A simple sample bookcase with adjustable shelves.",
  "url": "https://www.ikea.com/us/en/p/sample-bookcase-white-00000000/",
  "price": 79.0,
  "currency": "USD",
  "priceFormatted": "$79.00",
  "onSale": false,
  "isOnSpecial": false,
  "wasPrice": null,
  "wasPriceFormatted": null,
  "savingsAmount": null,
  "discountPercent": null,
  "specialsLabel": null,
  "ratingValue": 4.6,
  "ratingCount": 3091,
  "averageRating": 4.6,
  "reviewCount": 3091,
  "color": "white",
  "colors": [{ "name": "white", "id": "10156", "hex": "ffffff" }],
  "measurementText": "31 1/2x11x79 1/2 \"",
  "width": 31.5,
  "depth": 11.0,
  "height": 79.5,
  "measurementUnit": "in",
  "material": "Particleboard, Paper foil",
  "categoryPath": ["Storage & organization", "Bookshelves & bookcases"],
  "badge": "Best seller",
  "isBestseller": true,
  "onlineSellable": true,
  "mainImage": "https://www.ikea.com/us/en/images/products/sample__0000001.jpg",
  "images": ["https://www.ikea.com/us/en/images/products/sample__0000001.jpg"],
  "numberOfVariants": 4,
  "variants": [
    { "id": "11111111", "name": "SAMPLE", "color": "black", "price": 89.0, "currency": "USD" }
  ],
  "market": "us",
  "language": "en",
  "reviewsCollected": 1,
  "reviews": [
    {
      "author": "Sample Reviewer",
      "date": "2026-06-30",
      "title": "Great shelf for the money",
      "body": "Easy to assemble and very sturdy.",
      "rating": 5
    }
  ],
  "availability": {
    "national": { "country": "US", "homeDelivery": true, "clickCollect": true, "stockStatus": "HIGH_IN_STOCK" },
    "storesWithStock": 42,
    "stores": [
      { "code": "445", "cashCarry": true, "quantity": 62, "stockStatus": "HIGH_IN_STOCK" }
    ]
  }
}
```

### Ratings & reviews

Every product carries its **average rating** and **review count**. Turn on
**Fetch full details and reviews** to also attach the full description and each
individual customer review (title, text, author, date, rating). Products with no
reviews leave the review list empty - nothing is faked. Review photos are not
included.

### Filters & sorting

- **Sort:** relevance, price (low→high / high→low), newest, rating, most reviewed,
  name A-Z, width, height, depth
- **Filters:** min price, max price, min rating, in-stock only, contains keyword,
  specials

Sort and every filter apply in **search mode, category mode and URL mode** alike:
a search or category link pasted in URL mode is narrowed by exactly the same
settings as a search term. They are not applied in **Product item-number** mode
or to a **single product link** - those always return that exact item.

### Specials

Every product already carries its markdown info (if any) straight from the
search/category card, at no extra request cost: `isOnSpecial`, `wasPrice` /
`wasPriceFormatted`, `savingsAmount`, `discountPercent`, `specialsLabel`,
`isBreathTaking` (IKEA's own "hot deal" flag), and `priceValidFrom` /
`priceValidTo`. Full-price products simply carry `isOnSpecial: false` and
`null` for the rest.

The **Specials** input narrows any listing run to one of IKEA's real browse
facets - search terms, category listings, and search or category links pasted in
URL mode alike. It adds a facet to the same listing request already being made,
so it never costs an extra fetch:

- **IKEA Family price** - the loyalty-program markdown IKEA shows as
  "IKEA Family price"
- **Last chance** - clearance / limited-stock items (IKEA's own `lastChance`
  flag)

These are the only two specials categories IKEA itself offers as a browse
filter. Off by default.

### Connection

Runs on Apify Proxy - keep it enabled for reliable results across products,
prices, ratings and stock. Attaching the full description and individual review
texts works best on a residential connection and may be skipped on limited
plans; a residential connection is recommended for full coverage.

### Export to your apps (optional)

Pipe results straight into Notion, Linear, Airtable, or Apify via Model Context
Protocol (MCP) connectors. Authorize a connector under **Settings → API &
Integrations**, then select it in the input. This is a side-channel; it never
changes the dataset.

### Notes

- One dataset row per product; reviews and availability are nested under it.
- Prices and currency follow the selected market.
- Use **Max products** to bound a run; leave **Max pages** empty for no page limit.

# Actor input Schema

## `mode` (type: `string`):

search = keywords + filters. category = category listing links or ids. productIds = exact item numbers. url = paste product, category or search links and walk them.

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

The IKEA market (and its language) to scrape. Sets prices, currency, product range and the site language. In URL mode the market is taken from each link instead.

## `searchTerms` (type: `array`):

One or more keywords to search, e.g. sofa, bookcase, desk lamp.

## `sortBy` (type: `string`):

Order of results within each search or category listing, including a search or category link pasted in URL mode. Ignored for productIds and single product links.

## `categories` (type: `array`):

Category listing URLs (e.g. ikea.com/us/en/cat/bookcases-10382/) or bare category ids. Ids come in two shapes and both work: plain numbers (10382) and letter-prefixed ones (fu003 sofas, tl001 rugs and home textiles, bm003 beds). An id IKEA does not recognise is reported in the log and skipped.

## `productIds` (type: `array`):

Exact IKEA item numbers, e.g. 20522046. Each is resolved to a full product record.

## `urls` (type: `array`):

Paste product, category or search links from ikea.com. The market is read from each link. A room or department collection link (for example ikea.com/us/en/rooms/living-room/) is expanded into the categories that page itself lists, and each one is scraped; a link that lists no category (offers, new, campaigns) is reported in the log and skipped rather than guessed as a keyword. Every field in the Filters section below still applies here, to each search or category link you paste; a single product link returns that exact item and is not filtered.

## `minPrice` (type: `integer`):

Only keep products at or above this price (market currency). Applies in search mode, category mode AND URL mode (to each search or category link you paste). Not applied to productIds or a single product link.

## `maxPrice` (type: `integer`):

Only keep products at or below this price (market currency). Applies in search mode, category mode AND URL mode (to each search or category link you paste). Not applied to productIds or a single product link.

## `minRating` (type: `integer`):

Only keep products with an average rating at or above this value (1-5). Applies in search mode, category mode AND URL mode (to each search or category link you paste). Not applied to productIds or a single product link.

## `inStockOnly` (type: `boolean`):

Keep only products currently sellable online. Applies in search mode, category mode AND URL mode (to each search or category link you paste). Not applied to productIds or a single product link.

## `containsKeyword` (type: `string`):

Keep only products whose name, type or description contains this text. Applies in search mode, category mode AND URL mode (to each search or category link you paste). Not applied to productIds or a single product link.

## `specialsCategory` (type: `string`):

Show only products in one of IKEA's specials categories: IKEA Family price (loyalty-program markdown) or Last chance (clearance / limited-stock items). Off by default. Added as a facet to the same listing request, so it applies in search mode, category mode AND URL mode (to each search or category link you paste). Not applied to productIds or a single product link.

## `fetchDetails` (type: `boolean`):

Attach the full description and individual customer reviews (title, text, author, date, rating) to each product. Uses a residential connection.

## `maxReviews` (type: `integer`):

Cap on individual reviews captured per product. 0 disables review text (ratings are still attached).

## `includeAvailability` (type: `boolean`):

Attach national and per-store stock (quantity, click & collect, home delivery) to each product.

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

Total products to return across all inputs. This is the run cap.

## `maxPages` (type: `integer`):

Optional safety cap on result pages walked per search or category. Leave empty or 0 for no page limit - the run stops at Max products.

## `proxy` (type: `object`):

Apify Proxy configuration. Keeping Apify Proxy enabled is recommended for reliable results. Attaching the full description and individual review texts works best on a residential connection and may be skipped on limited plans.

## `mcpConnectors` (type: `array`):

Optionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify then Settings then API & Integrations, then select it here. Notion gets a page-per-item export; other connectors get a best-effort write. Leave empty to skip. Supported: Notion, Linear, Airtable, Apify.

## `notionParentPageUrl` (type: `string`):

URL or id of the Notion page under which item pages are created. Required only for the Notion export.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large crawl of products without returning or charging for products already collected there. Use this after an interrupted run, or when continuing a product catalogue pull in another run. For recurring monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns all matching products as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED products. Turn on "Emit unchanged" or "Emit expired" only when you also want those products returned (and billed). State is kept separately per market, mode (search/category/productIds/url), and filter setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the market, mode, search/category/productIds/urls and filter settings — different setups then never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return products that have not changed since the last run, marked UNCHANGED. This returns — and bills — extra rows you already have, so leave it off unless you specifically want the full snapshot every run.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return products that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search/category/URLs — not when Max products capped it or when Resume was used. This returns — and bills — extra synthetic rows, so leave it off unless you need expiry tracking.

## Actor input object example

```json
{
  "mode": "search",
  "market": "us/en",
  "searchTerms": [
    "bookcase"
  ],
  "sortBy": "RELEVANCE",
  "categories": [
    "https://www.ikea.com/us/en/cat/bookcases-10382/"
  ],
  "productIds": [
    "20522046"
  ],
  "urls": [
    "https://www.ikea.com/us/en/search/products/?q=bookcase"
  ],
  "inStockOnly": false,
  "specialsCategory": "none",
  "fetchDetails": true,
  "maxReviews": 20,
  "includeAvailability": false,
  "maxItems": 20,
  "maxPages": 0,
  "proxy": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 50,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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 = {
    "mode": "search",
    "searchTerms": [
        "bookcase"
    ],
    "categories": [
        "https://www.ikea.com/us/en/cat/bookcases-10382/"
    ],
    "productIds": [
        "20522046"
    ],
    "urls": [
        "https://www.ikea.com/us/en/search/products/?q=bookcase"
    ],
    "proxy": {
        "useApifyProxy": true
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/ikea-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 = {
    "mode": "search",
    "searchTerms": ["bookcase"],
    "categories": ["https://www.ikea.com/us/en/cat/bookcases-10382/"],
    "productIds": ["20522046"],
    "urls": ["https://www.ikea.com/us/en/search/products/?q=bookcase"],
    "proxy": { "useApifyProxy": True },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/ikea-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 '{
  "mode": "search",
  "searchTerms": [
    "bookcase"
  ],
  "categories": [
    "https://www.ikea.com/us/en/cat/bookcases-10382/"
  ],
  "productIds": [
    "20522046"
  ],
  "urls": [
    "https://www.ikea.com/us/en/search/products/?q=bookcase"
  ],
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false
}' |
apify call abotapi/ikea-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/ikea-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/A6fk97zAqncCslvP3/builds/XjItUB4KUcLhE5Vtj/openapi.json
