# Spicelands Scraper - Indian Grocery Products & Prices (`sian.agency/spicelands-product-scraper`) Actor

Produkte von spicelands.de als sauberes JSON: Preise, Grundpreis, Marken, Herkunftsland, Kategorien und Lagerbestand. Ohne Code, ohne Login.

- **URL**: https://apify.com/sian.agency/spicelands-product-scraper.md
- **Developed by:** [SIÁN OÜ](https://apify.com/sian.agency) (community)
- **Categories:** E-commerce, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 catalogue searches

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

## Spicelands Scraper 🌶️ Indian Grocery Products, Prices & Unit Prices

[![SIÁN Agency Store](https://img.shields.io/badge/Store-SI%C3%81N%20Agency-1AE392)](https://apify.com/sian.agency?fpr=sian) [![Google Shopping Price Tracker](https://img.shields.io/badge/Store-Google%20Shopping%20Price%20Tracker-1AE392)](https://apify.com/sian.agency/google-shopping-price-scraper?fpr=sian) [![Tesco Product Scraper](https://img.shields.io/badge/Store-Tesco%20Product%20Scraper-1AE392)](https://apify.com/sian.agency/tesco-product-scraper?fpr=sian) [![Kleinanzeigen Scraper](https://img.shields.io/badge/Store-Kleinanzeigen%20Scraper-1AE392)](https://apify.com/sian.agency/kleinanzeigen-scraper?fpr=sian)

#### 🎉 The whole Spicelands catalogue in one call — with the price per kilo on every row

##### For price monitors, sourcing teams and anyone tracking Indian and South Asian food in Germany

***

### 🔎 What is the Spicelands Scraper — and when should you use it?

The **Spicelands Scraper** turns the public catalogue of spicelands.de, the German online grocer for Indian, South Asian and Sri Lankan food, into clean, structured rows you can filter, export and feed straight into a spreadsheet, database or AI agent. No account, no portal API key, no browser automation to maintain.

**Use it when you need:** German Indian-grocery articles as rows: name, euro price, the crossed-out was-price where a real discount exists, the Grundpreis per kilo or litre, brand, country of origin, category and stock status. Every row also carries the article number, the pack weight, the size variants, the full German ingredients and nutrition text, and every published photo. The shop holds 2,610 articles, 1,514 of them sellable, across 238 brands and 69 categories.

**Use something else when:** you want a different shop or a cross-retailer view. Use [Google Shopping Price Tracker](https://apify.com/sian.agency/google-shopping-price-scraper?fpr=sian) for the same article priced across every German retailer that sells it. Use [Tesco Product Scraper](https://apify.com/sian.agency/tesco-product-scraper?fpr=sian) for UK grocery shelves, with the same price-and-stock row shape. Use [Kleinanzeigen Scraper](https://apify.com/sian.agency/kleinanzeigen-scraper?fpr=sian) for Germany's biggest classifieds site, for second-hand prices on the same goods. This actor covers one shop and nothing else: what Spicelands publishes at spicelands.de. It reads the storefront a visitor sees. There are no ratings and no reviews to return, because the shop has none: every one of its 1,514 in-stock articles carries a review count of zero. Order history and anything behind a login are not published by the shop and are not part of it.

### 🤖 Use with AI agents

Already connected to the [Apify MCP server](https://mcp.apify.com)? Just ask for this Actor by name: sian.agency/spicelands-product-scraper

**Your agent can pay for its own runs.** This Actor is eligible for [agentic payments](https://docs.apify.com/platform/actors/publishing/monetize), so an agent can discover it, run it and settle the bill over [x402](https://www.x402.org/) (USDC on Base) or [Skyfire](https://www.skyfire.xyz/) — without an Apify account or API token of its own. Billing is the same either way: per successful row, never for errors.

Otherwise copy this prompt into Claude, ChatGPT, Cursor or any MCP-enabled assistant:

```text
I want to track what Spicelands sells at spicelands.de and what it costs using the Apify Actor `sian.agency/spicelands-product-scraper`.

Use it when I need: German Indian-grocery articles as rows: name, euro price, the crossed-out was-price where a real discount exists, the Grundpreis per kilo or litre, brand, country of origin, category and stock status. Every row also carries the article number, the pack weight, the size variants, the full German ingredients and nutrition text, and every published photo. The shop holds 2,610 articles, 1,514 of them sellable, across 238 brands and 69 categories.

Don't use it when: you want a different shop or a cross-retailer view — use google-shopping-price-scraper or tesco-product-scraper or kleinanzeigen-scraper instead.

How to call it: there is one operation, `search`, and every filter is applied by the shop itself. `searchTerms` is a list of words matched against the product name, the short description and the article number, combined with OR; an empty list returns everything the other filters allow. `category` picks one of the shop's 29 categories and includes its sub-categories. `brand` picks one of the 22 largest brands. `onSaleOnly` returns only the articles the shop currently discounts, 48 of them. `includeOutOfStock` adds the 1,096 articles the shop hides from its own catalogue, which is off by default because the default is the sellable assortment. `sortBy` decides which products you get when `maxItems` stops the run. `maxItems` caps the run and therefore the spend. To watch named articles instead, put their addresses in `productUrls`: up to 40 are looked up in a single request and the search fields are then ignored.

Start with this input:
{
  "operation": "search",
  "searchTerms": [
    "masala"
  ],
  "category": "gewuerze",
  "includeOutOfStock": false,
  "sortBy": "date",
  "maxItems": 100
}

Ask me what I am looking for, which category or brand it sits under, and how many products I want back, then run the Actor and summarise the results as a table.
```

**Things you can ask your agent for:**

- *List every MDH spice Spicelands has in stock, with the price per kilo.*
- *Pull the whole Hülsenfrüchte category and tell me which lentils are cheapest per kilo.*
- *Check these twenty product links every morning and flag anything whose price moved.*

Machine-readable API, MCP config and OpenAPI definition for this Actor are published at [apify.com/sian.agency/spicelands-product-scraper.md](https://apify.com/sian.agency/spicelands-product-scraper.md).

### 📋 Overview

**Spicelands is a German online grocer for Indian, South Asian and Sri Lankan food**: spices,
lentils, rice, flours, namkeens, ready mixes and pooja goods. This actor turns its catalogue into
structured rows. Counted on 2026-09-10, that is 2,610 articles, 1,514 of them in stock, across
238 brands and 69 categories.

**What you get that a generic shop scraper does not:**

- ✅ **The Grundpreis on 99.5% of rows**: price per kilo or litre, so a 400 g jar and a 1 kg bag finally compare. This is the number a price analyst actually needs.
- 🏭 **The brand, on 93.5% of rows**: 238 of them, from TRS, MDH, Haldirams and MTR to the shop's own Spicelands label.
- 🌍 **The country of origin**: 44 countries, 834 articles from India. It sits in the shop's product attributes, which is why a generic catalogue puller misses it.
- 💰 **$1.50 per 1,000 products**: under every grocery scraper measured on the Store, which run $2.00 to $5.00 per 1,000.
- 🔎 **Filters the shop applies itself**: search, category, brand, reduced-only, sold-out and sort order all travel to the shop. A one-brand run costs a single request rather than a sixteen-page walk.
- ✨ **One operation, one price**: we compared the shop's single-product page against a catalogue row field by field. It carries nothing extra, so there is no second event to bill you for.

***

### ✨ Features

- 🌶️ **Whole-catalogue export**: 1,514 sellable articles in 16 requests, or the full 2,610 with sold-out ones included.
- 🗂️ **29 real categories**: the shop's own shelves. Each one carries the in-stock count we measured, so you know what a pick is worth before you run it.
- 🏭 **22-brand picker**: the largest brands by article count, plus free-text search for the other 216.
- ⚖️ **Unit prices**: €/kg and €/l as a number, not as a string buried in HTML.
- 🔥 **Reduced-only mode**: the 48 articles the shop currently discounts, with the crossed-out price beside the current one.
- 📦 **Sold-out archive**: one switch adds the 1,096 articles the shop hides, which is the restock and discontinuation feed.
- 🔗 **Fixed-basket watching**: paste up to 40 product addresses and they come back in a single request.
- 🧾 **Full German product copy**: the ingredients list, allergen note and nutrition table as plain text, on every article.
- 📸 **Every published image**: the main photo plus the rest of the gallery.
- 📄 **HTML run report**: a shareable summary in the key-value store, with your product links ready to copy.

***

### 🎬 Quick Start

Pick a category or type a search term, press Start, export as JSON, CSV or Excel. That is the whole
flow — no account with the shop, no API key, no login.

```bash
curl -X POST 'https://api.apify.com/v2/acts/sian.agency~spicelands-product-scraper/runs?token=YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"operation": "search", "searchTerms": ["masala"], "maxItems": 100}'
```

***

### 🚀 Getting Started (3 Simple Steps)

#### Step 1: Choose what to take

Type words into **Search terms**, or pick a **Category**, or pick a **Brand** — or leave all three
alone and take the whole shop.

#### Step 2: Narrow it down

Switch on **Reduced articles only** for the current markdowns. Switch on **Include sold-out
articles** if you want the archive too. Set **Max products** to cap the run and the spend.

#### Step 3: Press Start and export

Results land in the dataset. Download JSON, CSV or Excel, or read them straight from the API.

**That's it. In about a minute you'll have:**

- Every matching product with its price, its was-price and its price per kilo
- Brand, country of origin, category, stock status, article number and pack weight
- An HTML report summarising the run, saved beside the data

***

### 📥 Input Configuration

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `operation` | string | No | Always `search`. This actor has one operation. |
| `searchTerms` | array | No | Words matched against product name, short description and article number. Combined with OR. |
| `category` | string | No | One of the shop's 29 categories, or `Any`. |
| `brand` | string | No | One of the 22 largest brands, or `Any`. |
| `productUrls` | array | No | Specific product addresses. Up to 40 per request. Overrides the search fields. |
| `includeOutOfStock` | boolean | No | Add the 1,096 sold-out articles. Default `false`. |
| `onSaleOnly` | boolean | No | Only currently reduced articles. Default `false`. |
| `sortBy` | string | No | `date`, `price`, `popularity`, `title` or `menu_order`. Default `date`. |
| `maxItems` | integer | No | Stop after this many products. Default `100`. |

**A whole category:**

```json
{
  "operation": "search",
  "category": "gewuerze",
  "maxItems": 200
}
```

**One brand, cheapest first:**

```json
{
  "operation": "search",
  "brand": "mdh",
  "sortBy": "price",
  "maxItems": 100
}
```

**A fixed basket, watched daily:**

```json
{
  "operation": "search",
  "productUrls": [
    "https://spicelands.de/produkt/periyar-dry-tapioca-908g/",
    "https://spicelands.de/produkt/ajmi-chakki-atta/"
  ]
}
```

***

### 📤 Output

Each row is one product. The most useful fields:

| Field | Type | Description |
|-------|------|-------------|
| `productName` | string | The article name as the shop publishes it |
| `price` | number | Current price in euros, gross |
| `regularPrice` | number | The crossed-out price, only when genuinely higher |
| `onSale` | boolean | Whether the article is reduced today |
| `discountPercent` | number | How far below the was-price, to one decimal |
| `unitPrice` | number | Grundpreis — price per kilo or litre |
| `unitPriceUnit` | string | The unit that price is per, e.g. `kg` |
| `brand` | string | From the shop's own brand attribute |
| `originCountry` | string | Country of origin, e.g. `Indien` |
| `category` | string | The article's primary category |
| `inStock` | boolean | Whether the shop can ship it today |
| `sku` | string | The shop's article number |
| `weightKg` | number | Pack weight in kilograms |
| `variantCount` | integer | How many sizes the article comes in |
| `imageUrl` | string | Main product photo |
| `productUrl` | string | The article's page on the shop |

Rows also carry `categories`, `tags`, `variants`, `priceMin`, `priceMax`, `packSize`, `storage`,
`descriptionText`, `shortDescription`, `taxInfo`, `images`, `imageCount`, `productId` and `slug`.

**Example:**

```json
{
  "productId": 260921,
  "productName": "MDH Chilli Potato Masala 45g",
  "productUrl": "https://spicelands.de/produkt/mdh-chilli-potato-masala-45g/",
  "brand": "MDH",
  "originCountry": "Indien",
  "category": "Neue Produkte",
  "categories": ["Neue Produkte", "Fertigmischungen"],
  "price": 0.99,
  "onSale": false,
  "unitPrice": 22,
  "unitPriceUnit": "kg",
  "currency": "EUR",
  "inStock": true,
  "sku": "15765-576547",
  "weightKg": 0.045,
  "variantCount": 0,
  "taxInfo": "inkl. 7 % MwSt.",
  "shop": "Spicelands"
}
```

***

### 💼 Use Cases & Examples

#### 1. Price and Markdown Monitoring

**A pricing analyst watching what a competitor charges for Indian pantry staples.**

**Input:** A category, or a fixed list of product addresses, on a daily schedule.
**Output:** Current price, was-price, discount percentage and price per kilo for every article.
**Use:** 48 of 1,514 in-stock articles were reduced on 2026-09-10. Catch the next batch the day it lands.

#### 2. Assortment and Sourcing Research

**A buyer mapping what a German Indian grocer actually stocks.**

**Input:** Leave every filter alone and take the whole shop.
**Output:** 1,514 articles by category, brand and country of origin.
**Use:** 238 brands, 834 articles sourced from India, 138 from Thailand, 55 from Pakistan.

#### 3. Competitive Price Benchmarking

**A retailer comparing basmati, atta and spice blends across shops.**

**Input:** `brand` set to the label you carry, or search terms for the product family.
**Output:** Price, pack weight and the Grundpreis that makes different pack sizes comparable.
**Use:** "garam masala" alone draws 49,500 searches a month in Germany. Know what the market charges.

#### 4. Product Feed for Shops and Marketplaces

**A dropshipper or comparison site building a catalogue.**

**Input:** The whole shop, or one category at a time.
**Output:** Names, German descriptions, images, weights, article numbers and prices as clean JSON.
**Use:** Load it straight into a listing tool, a comparison site or a marketplace feed.

#### 5. Stock and Discontinuation Tracking

**A category manager watching what disappears.**

**Input:** Two runs — one default, one with **Include sold-out articles** switched on.
**Output:** The difference between them is exactly what the shop cannot sell right now.
**Use:** 1,096 articles were in that gap on 2026-09-10. Frozen goods were entirely out of stock.

#### 6. Ingredient and Allergen Research

**A food developer or importer checking formulations.**

**Input:** Search terms for the product family you care about.
**Output:** `descriptionText` carries the full ingredients list, allergen note and nutrition table.
**Use:** Present on all 1,514 articles, as plain text rather than HTML.

***

### 🔗 Integration Examples

#### JavaScript/Node.js

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });

const run = await client.actor('sian.agency/spicelands-product-scraper').call({
  operation: 'search',
  category: 'gewuerze',
  maxItems: 200,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].productName, items[0].price, items[0].unitPrice);
```

#### Python

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')

run = client.actor('sian.agency/spicelands-product-scraper').call(
    run_input={'operation': 'search', 'brand': 'trs', 'maxItems': 200}
)

for item in client.dataset(run['defaultDatasetId']).iterate_items():
    print(item['productName'], item.get('price'), item.get('unitPrice'))
```

#### cURL

```bash
curl -X POST 'https://api.apify.com/v2/acts/sian.agency~spicelands-product-scraper/runs?token=YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"operation": "search", "onSaleOnly": true, "maxItems": 100}'
```

#### Automation Workflows (N8N / Zapier / Make)

1. **Trigger**: Schedule — daily at 07:00, or a webhook from your own system
2. **HTTP Request**: Call the actor API with your saved input
3. **Process**: Compare today's prices against yesterday's rows
4. **Action**: Write to a sheet, push to a database, or alert on a markdown

***

### 📊 Performance & Pricing

#### FREE Tier (Try It Now)

- **25 products** per run — every field, every filter, same quality
- No credit card required
- Enough to check a category before committing to the whole shop

#### PAID Tier (Production Ready)

- **Unlimited** products per run — the whole 2,610-article catalogue if you want it
- Pay per product returned: a run that matches nothing costs nothing
- A whole-shop run is 16 requests and finishes in about two minutes

💰 **$1.50 per 1,000 products.** The German and European grocery scrapers measured on the Store
run $2.00 to $5.00 per 1,000. Generic WooCommerce pullers sit at $0.90 to $1.20, but they return
no brand, no country of origin and no price per kilo.

🔗 [View current pricing](https://apify.com/sian.agency/spicelands-product-scraper?fpr=sian)

***

### ❓ Frequently Asked Questions

**Q: How many products are there?**
A: 2,610 articles in the catalogue on 2026-09-10, of which 1,514 were in stock, across 238 brands and 69 categories. The shop hides sold-out articles from its own catalogue, which is why a default run returns the 1,514.

**Q: Do I need an API key or a login?**
A: No. Pick a category or type a search term and press Start.

**Q: Is there a separate operation for a single product?**
A: No, and deliberately so. The shop's single-product page was compared field by field against a catalogue row and carries nothing extra. Paste addresses into **Specific products** instead — up to 40 are looked up in one request, at the same per-product price.

**Q: Are prices in euros and do they include VAT?**
A: Prices are in euros exactly as the shop publishes them, which is the gross price a German shopper pays. Most food carries 7% VAT and the rest 19%; `taxInfo` says which. Rows also carry the Grundpreis on 1,507 of 1,514 articles.

**Q: Why is there no rating or review column?**
A: Because the shop has none. All 1,514 articles carry a review count of zero, so a rating column would never fill. Sorting by rating is left out for the same reason.

**Q: Can I get one row per pack size?**
A: Rows are one per product, which is what you are charged for. 232 articles have size variants, and every variant travels inside the row. A 1 kg / 2 kg / 5 kg atta is one row and one charge rather than three.

**Q: My run returned no rows. What went wrong?**
A: Probably nothing. The filters combine, so a narrow combination can genuinely have no members: MDH alone returns 29 products, MDH inside Gewürze returns 1, and MDH inside Namkeens returns none. Widen one field at a time. You were not charged for the empty run.

**Q: What output formats are available?**
A: JSON, CSV, Excel and XML — export directly from the Apify dataset, or read them from the API.

***

### 🐛 Troubleshooting

**A run returned zero products**

- Reset **Category** and **Brand** to `Any`, then add one back at a time
- Switch off **Reduced articles only** — only 48 articles are reduced at any time
- Shorten the search term. The shop matches the product name and article number, not the long ingredients text

**A product address came back as "no longer in the shop"**

- The shop has taken that article down. Search for it by name and copy a current address from the results

**Fewer rows than the category count suggests**

- **Max products** stops the run. Raise it, or set it to 3000 to take everything
- On the FREE tier a run stops at 25 rows

**A category looks empty**

- Frozen goods and a couple of other shelves had nothing in stock when the actor was built. Switch on **Include sold-out articles** to see them anyway

**The shop was temporarily unavailable**

- The run already retried five times. Try again in a few minutes; nothing needs changing on your side

***

### ⚖️ Is it legal to scrape data?

Our actors are ethical and do not extract any private user data, such as email addresses, gender, or location. They only extract what the user has chosen to share publicly. We therefore believe that our actors, when used for ethical purposes by Apify users, are safe.

However, you should be aware that your results could contain personal data. Personal data is protected by the **GDPR** in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers.

You can also read Apify's blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

Spicelands and spicelands.de are trademarks of their respective owner. This actor is not affiliated with, endorsed by, or sponsored by Spicelands.

***

### 🤝 Support

[![Telegram Support](https://img.shields.io/badge/Telegram-Support%20Group-0088cc?logo=telegram)](https://t.me/+vyh1sRE08sAxMGRi)

**Join our active support community**

- For issues or questions, open an issue in the actor's repository
- Check [SIÁN Agency Store](https://apify.com/sian.agency?fpr=sian) for more automation tools
- 📧 <apify@sian-agency.online>

***

**Built by [SIÁN Agency](https://www.sian-agency.online)** | **[More Tools](https://apify.com/sian.agency?fpr=sian)**

# Actor input Schema

## `operation` (type: `string`):

One operation. Catalogue Search walks the shop and returns many products per call, with search terms, category, brand, sale and stock all applied by the shop itself rather than filtered afterwards.

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

Words to look for. The shop matches them against the product name, the short description and the article number, so 'masala' catches 'Garam Masala' and 'MDH Chana Masala' alike. Terms are combined with OR. Measured on 2026-09-10: 'masala' matched 107 products, 'curry' 44, 'basmati' 38, 'paneer' 13. The shop does not search the long ingredients text, only the name, the short description and the article number. Leave this empty to take everything in the chosen category.

## `category` (type: `string`):

Take one of the shop's own categories instead of the whole catalogue. The counts in brackets are what each one held in stock on 2026-09-10. A parent category includes its sub-categories, so Gewürze returns 108 products rather than the 38 filed directly under it. Categories under 15 products are left out, and so are the two that had nothing in stock at all (Tiefkühl, Chapatti & Naan): a choice that returns no rows is worse than no choice. Search terms and brand still apply on top.

## `brand` (type: `string`):

Take one brand's whole range. The shop carries 238 brands; the 22 largest are listed here with the number of articles each had in stock on 2026-09-10. Every other brand is reachable by typing its name into Search terms instead. Brand combines with category and search terms — MDH alone returned 29 products, MDH inside Gewürze returned 1, MDH plus the term 'masala' returned 24.

## `productUrls` (type: `array`):

Paste product page addresses copied from the shop, for example https://spicelands.de/produkt/periyar-dry-tapioca-908g/. Only those products come back. Up to 40 addresses are looked up in a single request, so watching 40 prices daily costs one request a day. A bare product slug works too. When this is set, the search, category and brand fields are ignored. An address the shop no longer publishes comes back as 'no longer in the shop', not as an error.

## `includeOutOfStock` (type: `boolean`):

Off by default, and off is what you want for pricing, sourcing or a product feed. The shop hides sold-out articles from its own catalogue, so the default already gives you the sellable assortment: 1,514 articles in stock on 2026-09-10 out of 2,610 in total. Switch this on to get the other 1,096 as well. That is useful for tracking what the shop used to carry and for spotting restocks, though those rows cannot be bought today.

## `onSaleOnly` (type: `boolean`):

Return only articles the shop currently sells below their normal price. Measured on 2026-09-10: 48 of the 1,514 in-stock articles were reduced, and none of the sold-out ones were. The row carries both the current price and the crossed-out one, so you can see the size of every markdown. This combines with category, brand and search terms.

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

The order the shop serves products in, which decides which ones you get when Max products stops the run early. Four orders were checked against real payloads and all four behave. Two the shop offers are deliberately missing: sorting by rating does nothing, because every article in the shop has no rating at all, and 'most expensive first' came back genuinely unsorted when it was tested, so offering it would quietly give you the wrong products.

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

Stop after this many products. The run ends as soon as the number is reached, so this is also your spending ceiling. For scale: the whole shop was 1,514 in-stock articles on 2026-09-10 and 2,610 including sold-out ones, so 3000 takes everything even as the shop grows. The largest category, Namkeens, held 198.

## Actor input object example

```json
{
  "operation": "search",
  "searchTerms": [
    "masala",
    "basmati"
  ],
  "category": "Any",
  "brand": "Any",
  "productUrls": [
    "https://spicelands.de/produkt/periyar-dry-tapioca-908g/"
  ],
  "includeOutOfStock": false,
  "onSaleOnly": false,
  "sortBy": "date",
  "maxItems": 100
}
```

# Actor output Schema

## `spicelandsSpicelandsDeProducts` (type: `string`):

Every product this run returned.

## `scrapingSummary` (type: `string`):

HTML summary showing successful and failed results with key metrics

# 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 = {
    "operation": "search",
    "searchTerms": [
        "masala"
    ],
    "category": "Any",
    "brand": "Any",
    "includeOutOfStock": false,
    "onSaleOnly": false,
    "sortBy": "date",
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("sian.agency/spicelands-product-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 = {
    "operation": "search",
    "searchTerms": ["masala"],
    "category": "Any",
    "brand": "Any",
    "includeOutOfStock": False,
    "onSaleOnly": False,
    "sortBy": "date",
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("sian.agency/spicelands-product-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 '{
  "operation": "search",
  "searchTerms": [
    "masala"
  ],
  "category": "Any",
  "brand": "Any",
  "includeOutOfStock": false,
  "onSaleOnly": false,
  "sortBy": "date",
  "maxItems": 100
}' |
apify call sian.agency/spicelands-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sian.agency/spicelands-product-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/eab1EbjS1ZDRyRe5f/builds/IHV4GNiRHA8AcmkVR/openapi.json
