# Yandex Market Scraper API | Парсер Яндекс Маркета (`dami_studio/yandex-market-scraper`) Actor

Scrape Yandex Market products by search term or catalogue URL: name, price, crossed-out old price, discount, seller, rating, stock, brand, specs, image and product link. No API key, no browser. $1.70 per 1,000 products, the same flat rate on every plan, with no volume tiers.

- **URL**: https://apify.com/dami\_studio/yandex-market-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** E-commerce, Lead generation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.70 / 1,000 product returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Yandex Market Scraper (Парсер Яндекс Маркета)

Pulls product listings off **Yandex Market** (`market.yandex.ru`), Russia's biggest price-comparison
marketplace. Give it a search term or paste a Market URL and you get back one row per product:
name, current price, crossed-out old price, discount, seller, rating, rating count, stock, delivery
estimate, brand, key specs, image and a clean product link.

No API key, no Yandex account, no browser. It is a plain HTTP scraper, which is why it is cheap.

### What you get

One row per product. A real row from a live run for `фен` (hair dryer):

```json
{
  "productId": "5793004993",
  "offerId": "Ads1fH9EJYoe_frsFnAXzA",
  "sku": "5793004994",
  "name": "WOEX Фен с ионизацией профессиональный 2000Вт IonPro 2010 HD-WX-2010BL",
  "url": "https://market.yandex.ru/product--woex-fen-s-ionizatsiyey-professionalnyy-2000vt-ionpro-2010-hd-wx-2010bl/5793004993",
  "price": 6350,
  "oldPrice": 19490,
  "discountPercent": 67,
  "priceWithoutCard": 17590,
  "currency": "RUB",
  "rating": 4.8,
  "ratingCount": 41,
  "purchasedText": "127 купили",
  "sellerName": "WOEX",
  "sellerId": "90418609",
  "sellerSlug": "woex",
  "sellerUrl": "https://market.yandex.ru/business--woex/90418612",
  "brand": "WOEX",
  "inStock": true,
  "stockNote": null,
  "conditionNote": null,
  "deliveryText": "Завтра, ПВЗ",
  "categoryId": "70053433",
  "categoryName": "Фен",
  "badges": ["SUPER_PRICE", "ПРОМОКОД"],
  "specs": [{ "name": "Мощность фена", "value": "2000 Вт" }],
  "imageUrl": "https://avatars.mds.yandex.net/get-mpic/20419546/2a0000019f6ae4dcf74021662e2581e35b83/orig",
  "images": ["…", "…"],
  "searchQuery": "фен",
  "page": 2,
  "scrapedAt": "2026-08-08T18:20:44.310Z"
}
```

#### About the three price fields

Yandex Market shows up to three numbers for the same offer, and mixing them up is the usual way a
price monitor goes wrong. This scraper keeps them apart:

| Field | What it is |
|---|---|
| `price` | The big number on the result card. This is the price Yandex Market itself publishes in the page's schema.org data — checked across three product pages, 40 of 40 `ld+json` prices matched this field exactly. It assumes payment with a Yandex Pay card. |
| `priceWithoutCard` | What the same offer costs without the Yandex Pay card discount. `null` when there is no difference. |
| `oldPrice` | The crossed-out list price. `discountPercent` is computed from `oldPrice` against `price`. |

### Input

| Field | What it does |
|---|---|
| `searchQueries` | Search terms, one per line. Russian gives the fullest catalogue (`фен`, `ноутбук`, `кроссовки`); Latin brand and model names work too (`iphone 15`, `dyson`). |
| `startUrls` | Yandex Market search pages or catalogue listings, e.g. `https://market.yandex.ru/catalog--noutbuki/54544/list`. Filters already in the URL are preserved. |
| `maxItems` | Hard cap on unique products, 1–5000. Default 50. |
| `sortBy` | `relevance`, `priceAsc`, `priceDesc`, `rating`. |
| `minPrice` / `maxPrice` | Price bounds in roubles. |
| `minRating` | Drop products rated below this (and products with no rating). |

Leaving the input empty returns a single labelled `_sample: true` row and charges nothing.

### Speed and limits, measured

- **~16 products per request.** Page 1 of a search returns 8; pages 2 and deeper return 16. A
  catalogue listing page returns up to 20.
- **~1 second per page** and about 2.5 MB of HTML per page.
- **A search runs dry, it does not get cut off.** `фен` returned products up to page 50 and nothing
  at page 55 — roughly 800 products for a broad term. The scraper stops on its own when two
  consecutive pages bring nothing new.
- **Yandex repeats products between pages.** Twelve pages of `iphone` produced 184 snippets but only
  165 distinct products. Duplicates are removed before your item cap is applied, so `maxItems: 200`
  means 200 different products, and you are never charged twice for the same one.

### What this does NOT do

Being straight about the edges, because they are the things that would otherwise surprise you:

- **No region switching.** Every price is for the Moscow delivery region (Yandex geo id 213). Both
  the `lr=` URL parameter and the `yandex_gid` cookie were tested and Yandex ignored both — the
  delivery point stayed on Moscow in every case. Rather than ship a setting that silently does
  nothing, there isn't one.
- **`maxPrice` is enforced by this scraper, not by Yandex.** Yandex treats an upper price bound as a
  relevance hint: asking for `priceto=1500` returned 12 of 16 rows *above* 1500. The scraper drops
  those rows itself and does not charge you for them. `minPrice` genuinely filters server-side.
- **No sponsored / advertisement flag.** Yandex marks essentially every search offer as sponsored in
  its own data (48 of 48 offers across three unrelated queries), so a flag built on it would say
  "true" for every row. A field that is always the same value is worse than no field.
- **No review text.** Search results carry a star rating and a rating count (`оценок`), not written
  reviews. `ratingCount` is that count, not a count of review bodies.
- **Search results only.** It reads listing and catalogue pages. It does not open each product page
  to collect the full offer list, spec sheet or review feed.
- **One seller per product** — the offer Yandex chose to show in the result list, not every seller
  carrying that product.
- **Prices move.** Yandex Market reshuffles its result order between requests and runs personalised
  promotions, so two runs a minute apart can differ. Store `scrapedAt` with your data.

### FAQ

**Is there an official Yandex Market API?**
Not a public one. `api.partner.market.yandex.ru` is for merchants selling on the platform and needs
OAuth plus a seller account; the old public Content API was retired. For reading the public
catalogue, scraping the site is the route that exists.

**Do I need a proxy or a Yandex account?**
No. The scraper handles its own egress and rotates the exit address when Yandex challenges one. You
can point it at your own proxy if you want to, but you do not need to.

**Does it work for market.yandex.by, .kz or .uz?**
`market.yandex.by` and `market.yandex.kz` redirect to `market.yandex.ru`, so they are the same
storefront. `market.yandex.uz` is a genuinely separate, much smaller catalogue priced in soms and is
not supported here.

**How do I monitor a competitor's prices?**
Paste their seller page or run your product search on a schedule and diff `price` on `productId`
between runs. `offerId`, `sellerId` and `sku` are all stable enough to key on.

**How many products can I get for one term?**
Around 800 for a broad category term — that is where Yandex's own result list ends, not a scraper
limit. To go deeper, use narrower terms or catalogue URLs with filters applied.

**What happens if Yandex blocks a request?**
You get an uncharged diagnostic row saying so (`errorCode: "CAPTCHA"` or `"FETCH_FAILED"`) instead
of a silently empty dataset. Failed and filtered-out rows are never charged.

**Why is `price` sometimes far below `priceWithoutCard`?**
Because Yandex Market's headline price assumes a Yandex Pay card. Both numbers are real; use
`priceWithoutCard` if you are comparing against a shop that does not run that promotion.

### Pricing

**$1.70 per 1,000 products** ($0.0017 each), plus **$0.001 to start a run** (the start fee is billed
once per gigabyte of run memory, and this Actor runs at 1 GB, so that is $0.001 per run). It is a
flat rate: the same price on a free account as on a paid one, with no volume tiers to reach and no
subscription on top.

Pay per product returned. Sample rows, rows dropped by your own filters, and diagnostic rows for
blocked requests are all free.

| Products | Total cost |
|---|---|
| 50 (the default) | $0.086 |
| 1,000 | $1.701 |
| 5,000 (the per-run cap) | $8.501 |

# Actor input Schema

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

What to look for on Yandex Market, one per line. Russian terms return the fullest catalogue ("фен", "ноутбук", "кроссовки"), but Latin brand and model names work too ("iphone 15", "dyson"). Each term is paginated until it runs out of products or hits your item cap.

## `startUrls` (type: `array`):

Optional. Paste Yandex Market search pages (https://market.yandex.ru/search?text=ноутбук) or catalogue listings (https://market.yandex.ru/catalog--noutbuki/54544/list). Filters already in the URL are kept. A few catalogue nodes only list products when the URL carries ?hid=<categoryId>; if one comes back empty you get an uncharged row telling you so.

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

Hard cap on unique products returned across every search (1-5000). Yandex Market repeats products between pages; duplicates are dropped before the cap is applied, so you get the number you asked for. You are charged per product returned.

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

Sorting applied to search terms. Ignored for pasted URLs that already carry their own sort.

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

Only return products at or above this price, in roubles. Leave empty for no floor.

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

Only return products at or below this price, in roubles. Yandex Market ignores this server-side (it returned 12 of 16 rows above the requested cap in testing), so the scraper also filters it locally and does not charge for the rows it drops.

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

Only return products rated at or above this value out of 5. Products with no rating yet are excluded when this is set. Applied locally; dropped products are not charged.

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

Leave as-is. The scraper already routes through the addresses that Yandex Market answers from; only override this if you have your own proxy.

## Actor input object example

```json
{
  "searchQueries": [
    "фен"
  ],
  "startUrls": [],
  "maxItems": 50,
  "sortBy": "relevance",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One row per product in the default dataset: name, price, old price and discount, seller, rating and rating count, stock, delivery, brand, specs, image and the product URL. Empty or blocked runs return a single uncharged row instead.

# 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 = {
    "searchQueries": [
        "фен"
    ],
    "startUrls": [],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/yandex-market-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 = {
    "searchQueries": ["фен"],
    "startUrls": [],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/yandex-market-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 '{
  "searchQueries": [
    "фен"
  ],
  "startUrls": [],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call dami_studio/yandex-market-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/yandex-market-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/01c8QSA7LAFhVVA8T/builds/ZShVd3rHkFkNBagNt/openapi.json
