# Yandex SERP Scraper — Rank Tracking, Ads & Regions (`cheapapi/yandex-serp-scraper`) Actor

Yandex search results scraper: organic rankings, ads and result blocks for yandex.ru, .com.tr, .com, .kz, .by, .uz in any region. Bulk, no captchas.

- **URL**: https://apify.com/cheapapi/yandex-serp-scraper.md
- **Developed by:** [CheapAPI](https://apify.com/cheapapi) (community)
- **Categories:** SEO tools, Marketing, Developer tools
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event + usage

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Yandex SERP Scraper — Rank Tracking, Ads & Regions

Scrape Yandex search results in bulk as clean JSON: **organic rankings** with title, URL, snippet and page date, or the **full results page with ads and result blocks** in on-page order. Works for **yandex.ru, yandex.com.tr, yandex.com, yandex.kz, yandex.by and yandex.uz**, with **about 640 cities and regions in Russia and 80 in Turkey** (1,100+ worldwide) selectable on yandex.ru and yandex.com.tr (Moscow, Saint Petersburg, Kazan, Istanbul …) and IP-based location on the other domains. Optional **AI answers** written by Yandex search, with sources. No proxies, browser or Yandex account needed.

**90–95% cheaper for 1,000 search terms than the two most-used Yandex Actors, which charge per single-term run (Store prices, October 2026).**

| Quick facts | |
|---|---|
| Price | $6 per 1,000 searches of up to 20 results (Free plan), $4 on Gold+; no start fee |
| Depth | up to 250 results per search term, Yandex's exact positions |
| Where | yandex.ru, .com.tr, .com, .kz, .by, .uz; ~640 Russian and ~80 Turkish regions |
| Volume | up to 10,000 searches per run, about 6 minutes per 1,000 |
| Extras | full page with ads and AI overview, rank changes, monitoring, AI answers |

Jump to [Pricing](#pricing) · [FAQ](#faq) · [Limitations](#limitations)

**Why this Actor**

- **$6 per 1,000 searches of up to 20 results** on the Free plan and **$4 on Gold and above** plus Apify platform usage (about $0.05–$0.08 per 1,000 terms) — no start or setup fee; the only other charges are the Full results page rate ($0.008 Free / $0.005 Gold per 10 results), the $0.0012 no-results fee and the optional $0.06 AI answer.
- **Bulk in one run:** paste hundreds or thousands of search terms; each usually finishes in **2–10 seconds** (rare queue delays of up to about 95 s are covered by an automatic backup request).
- **Up to 250 results per search term** with Yandex's exact positions (100 results come from a single results page).
- **City-level rankings:** pick a region by name ("Moscow", "Kazan", "Istanbul") or Yandex region ID — or one per search term (`купить диван | Kazan`); desktop or mobile.
- **AI answers (optional, $0.06 per search term):** the answer Yandex search writes for a term (Russian, Kazakh, Uzbek), with its cited sources.
- **One Actor for the whole job:** city regions, the full results page (ads, AI overview, knowledge panel), rank-change tracking and monitoring. The only cheaper listing is a very new per-call Actor (~2 users) for plain pages.
- **Monitoring:** **Only new results** delivers just the URLs that appeared since your last run — you pay for those, plus $0.0012 per processed request when a term has nothing new.
- **Rank tracking built in:** list your domains and get `isTracked` on every result, or one row per search term with each domain's position — and, with **Compare with the previous run**, the position change of every result since your last run (free).
- **Full results page with AI overview:** ads, the Alice AI quick answer with its sources, the knowledge panel, image/video/product blocks and related searches — in page order.
- **Fair billing:** charged per started group of 20 delivered organic results (10 on the full results page); search terms Yandex rejects are free, and a search that finds nothing costs only a $0.0012 no-results fee.

### Compared with alternatives

Typical run: **1,000 search terms × 10 organic results** (10,000 result rows; AI answers not included). Actor fees of public Apify Store listings (Free plan / Gold plan), checked October 2026.

| Option | 1,000 search terms × 10 results | Search terms per run | Notes |
|---|---|---|---|
| Most-used Yandex Store Actor (~2,200 users) | $130 / $74 | 1 (setup fee $0.08 / $0.05 on every run) | $0.05 / $0.024 per results page |
| Second most-used (~270 users) | $70 / $40 | 1 | $0.007 / $0.004 per result |
| Same developer's per-result listing (~85 users) | $130 / $74 | 1 | same fees as the first row |
| Per-item Actor (~60 users) | $50 / $10 | many | $0.005 / $0.001 per result row + $0.005 per run |
| Flat per-result Actor (~40 users) | $34 / $34 | many | $0.0034 per result |
| Per-result Actor (~23 users) | $40 / $32 | many | $0.004 / $0.0032 per result |
| Budget per-result Actor (~13 users) | $20 / $14 | many | $0.002 / $0.0014 per result + the same per run |
| Per-call Actor (~2 users) | **$2 / $1.60** | many | $0.002 / $0.0016 per results page ("standard call") |
| **This Actor** | **$6 / $4** | **many (up to 10,000)** | no start fee |

Plainly: against the two most-used Yandex Actors we are **95% / 95% cheaper** (Free / Gold) than the first and **91% / 90%** than the second, and cheaper than every listed alternative except one very new per-call listing (~2 users), which costs about a third (Free) to 40% (Gold) of our price for plain results pages; you get regions, exact positions up to 250, the full page with ads, rank changes and AI answers here. Small per-row or per-run fees of other Actors ($0.00001 per row up to $0.005 per run) are left out of the table — negligible when 1,000 terms run in one run. Apify platform usage is billed separately for this Actor (see Pricing); the table compares Actor fees only. Competitor prices are a snapshot from their public listings (October 2026) and may change. Our price stays the same with **20 results per term**, while per-result Actors double (the second one: $140 / $80).

**Per plan, 1,000 search terms × 10 results (most-used Actor, one run per search term, vs. this Actor).** Apify lets us set Free, Bronze, Silver and Gold prices; Platinum and Diamond pay our Gold price.

| Apify plan | Most-used Actor | This Actor | Difference |
|---|---|---|---|
| Free | $130 | $6.00 | 95% cheaper |
| Bronze | $105 | $5.50 | 95% cheaper |
| Silver | $85 | $5.00 | 94% cheaper |
| Gold, Platinum, Diamond | $74 | $4.00 | 95% cheaper |

### Not included

- **Search volume / Wordstat keyword frequencies, keyword ideas** — not provided.
- **Yandex Maps places and reviews, Yandex Market products, Yandex Images and News verticals** — this Actor covers Yandex web search.
- **Ad landing URLs** — ads (and their sitelinks) link through Yandex's ad redirect, so ads come with the advertiser's displayed domain, title, text, rating and sitelink titles, but `url` is `null`.
- **Content of the ranking pages** — only what the results page shows.
- **Other Yandex domains and interface languages** — the six Yandex searches in this Actor (yandex.ru, .com.tr, .com, .kz, .by, .uz) and six interface languages (plus automatic) are what Yandex offers for automated search; some scrapers list more domains or languages.

### What data you get

**Result type "Organic results"** (default) — one row per organic result:

| Field | Type | Example |
|---|---|---|
| `searchQuery` | string | `купить ноутбук` |
| `searchDomain` | string | `yandex.ru` |
| `type` | string | `organic` (`ai-answer` and `related-searches` for the extra rows) |
| `region`, `regionId` | string, number | `Moscow`, `213` |
| `position` | number | `1` (Yandex's exact position, 1–250) |
| `title` | string | `Ноутбуки для работы купить по низкой цене…` |
| `url` | string | `https://www.mvideo.ru/noutbuki-…` |
| `domain` | string | `mvideo.ru` |
| `snippet` | string | snippet passages joined (or the page description) |
| `passages` | array | the snippet's separate text passages |
| `headline` | string / null | page description shown by Yandex |
| `modifiedDate` | string / null | `2018-05-21` — page date reported by Yandex (not always the last edit) |
| `documentLanguage` | string / null | `ru` |
| `mimeType` | string / null | `text/html`, `application/pdf` … |
| `savedCopyUrl` | string / null | Yandex's cached copy of the page |
| `isTracked` | boolean | `true` when the domain is in **Track domains** |
| `totalResults` | number / null | `37812154` (Yandex's estimate) |
| `correctedQuery` | string / null | the spelling Yandex searched instead |
| `domainGroupPosition` | number | only with **Results per website** 2–3 |
| `previousPosition`, `positionChange`, `isNew`, `previousRunAt` | number / null, number / null, boolean, string | with **Compare with the previous run**: `7`, `3` (moved up 3 places), `false` |
| `id` | string | `e714ca1d5650c2f4` — same search, position and URL give the same id (not unique per run) |
| `runId`, `scrapedAt`, `language`, `device` | string | the run that collected the row, collection time, interface-language setting (`auto` = domain default; the page language is `documentLanguage`) and device (`desktop` in Organic results mode; the Device option applies to the full results page only) |

**Result type "Full results page"** — one row per block of the results page, in order:

| Field | Type | Example |
|---|---|---|
| `type` | string | `organic`, `ad` or `block` |
| `position` | number | place on the page among all blocks (1, 2, 3 …) |
| `organicPosition` / `adPosition` | number / null | position among organic results / among ads |
| `title`, `url`, `domain`, `snippet` | | as above (`url` is `null` for ads) |
| `breadcrumbs` | array | `["Ноутбуки, планшеты, компьютеры", "Ноутбуки"]` |
| `rating` | number / null | `4.6` — shop rating shown next to the result |
| `sitelinks` | array | links under a result: `[{"title": "Менеджер", "url": "https://spb.hh.ru/vacancies/menedzher"}]` |
| `blockType`, `blockSubtype`, `blockText` | | `ai-overview` (Alice AI quick answer, full text), `knowledge-panel`, `images`, `videos`, `products`, `ads-block` … |
| `blockLinks` | array | links of a block — the AI overview's sources, a knowledge panel's links, image/video items: `[{"title": "ru.wikipedia.org", "url": "https://ru.wikipedia.org/wiki/…"}]` |
| `relatedSearches` | array | on a `related-searches` row: `["эйфелева башня в париже", "эйфелева башня высота", …]` |
| `page` | number | results page the block came from |
| `htmlUrl` | string | link to the saved page HTML (when **Save the page HTML** is on) |

`totalResults`, `correctedQuery`, `modifiedDate`, `passages` and `domainGroupPosition` exist only in **Organic results** mode (the full results page does not contain them).

**AI answer** (option) — one extra row per search term with `type: "ai-answer"`:

| Field | Type | Example |
|---|---|---|
| `answerText` | string / null | `Выбор ноутбука для учёбы зависит от того, что именно предстоит делать. [1] …` (Markdown; `[1]` = first source) |
| `answerSources` | array | `[{"url": "https://hi-tech.mail.ru/…", "title": "25 лучших ноутбуков для учебы 2026…", "used": true}]` |
| `answerRejected` | boolean | `true` when Yandex declined to answer |

The row also carries the common fields (`id`, `runId`, `searchQuery`, `searchDomain`, `scrapedAt`). `region`, `regionId`, `device` and `position` are `null`, because the answer is not region-specific and is requested once per search term even with **Several regions**.

Example AI answer row (real output, shortened):

```json
{
    "id": "5a9d3af82cdb697c",
    "runId": "Hs4ujkV031SOo3a9H",
    "searchQuery": "python",
    "searchDomain": "yandex.ru",
    "region": null,
    "regionId": null,
    "language": "auto",
    "device": null,
    "scrapedAt": "2026-10-01T19:36:02.717Z",
    "type": "ai-answer",
    "position": null,
    "answerText": "**Python** — **высокоуровневый язык программирования общего назначения** с динамической типизацией и автоматическим управлением памятью. [1][5] Создан нидерландским программистом Гвидо ван Россумом в 1991 году. [5] \n\n**Н …",
    "answerSources": [
        {
            "url": "https://ru.wikipedia.org/wiki/Python",
            "title": "Python — Википедия",
            "used": true
        },
        {
            "url": "https://skillbox.ru/media/code/dlya_chego_nuzhen_python/",
            "title": "Python: что это за язык, для чего нужен и где используется / Skillbox Media",
            "used": true
        }
    ],
    "answerRejected": false
}
```

With **Compare with the previous run**, organic results look like this (illustrative values; the fields are real):

```json
{ "searchQuery": "купить ноутбук", "region": "Moscow", "type": "organic", "position": 4, "url": "https://www.citilink.ru/catalog/noutbuki/", "domain": "citilink.ru", "previousPosition": 7, "positionChange": 3, "isNew": false, "previousRunAt": "2026-10-01T16:16:08.854Z" }
```

and a "One row per search term" row (shortened, illustrative values):

```json
{
    "searchQuery": "купить ноутбук", "region": "Moscow", "organicCount": 20, "previousRunAt": "2026-10-01T16:16:08.854Z",
    "trackedDomains": [
        { "domain": "citilink.ru", "position": 4, "url": "https://www.citilink.ru/catalog/noutbuki/", "previousPosition": 7, "positionChange": 3 },
        { "domain": "dns-shop.ru", "position": 6, "url": "https://www.dns-shop.ru/catalog/17a892f816404e77/noutbuki/", "previousPosition": 6, "positionChange": 0 }
    ]
}
```

With **Only results that moved at least** N places, a daily run stores only the results whose position changed by N or more, plus new ones.

With **Output format "One row per search term"**, one row holds all results of a search term: `organicResults`, `ads`, `blocks`, `aiAnswer`, `organicCount`, `adsCount`, `totalResults`, `totalResultsText`, `correctedQuery`, `trackedDomains` (each tracked domain with its `position` or `null`, plus `previousPosition` and `positionChange` when comparing with the previous run), `noNewResults` (true when “Only new results” found nothing new for the term; the row then has `organicCount` 0) and `htmlUrls` (links to the saved page HTML with “Save the page HTML”).

**Related searches** come as one extra row per search term with `type: "related-searches"` and `relatedSearches` (full results page; in "One row per search term" output they are the `relatedSearches` field).

**Run summary** — the `RUN_SUMMARY` record of the run's key-value store (also linked in the Output tab):

- **Counts:** `searchTermsRequested`, `searchTermsCompleted`, `searchTermsWithoutResults`, `searchTermsWithoutNewResults`, `searchTermsFailed`, `searchTermsPartial` (a later results page failed: only the delivered part is charged), `searchTermsSkippedByLimit`, `searchTermsInvalid`, `searchTermsDuplicate`, `pagesCharged`, `rowsDelivered` (result rows stored, not counting AI-answer and related-searches rows; 1 per term with One row per search term), `organicResultsChecked`, `organicResultsDelivered` (stored, after filters), `adsDelivered`, `aiOverviewsFound`, `relatedSearchesFound`, `aiAnswersDelivered`, `trackedDomainHits`, `backupRequests`, `historyReadFailures`, `historyWriteFailures`.
- **State:** `searchDomain`, `region`, `resultType`, `stoppedAtSpendingLimit`, `runError` (only when the run stopped early), `finishedAt`, `problems` (the first 100 search terms that had a problem, with the reason in plain words) and `termsWithoutNewResults` (the first 100 terms with nothing new in **Only new results**, kept apart from real problems).

Example `RUN_SUMMARY` excerpt (shape of a real run with a no-results term and a declined AI answer):

```json
{
    "searchTermsRequested": 3, "searchTermsCompleted": 2, "searchTermsWithoutResults": 1, "searchTermsFailed": 0,
    "pagesCharged": 2, "organicResultsDelivered": 20, "aiAnswersDelivered": 1, "stoppedAtSpendingLimit": false,
    "problems": [
        { "searchQuery": "zxqv wlkj", "reason": "Yandex returned no results for this search term (charged the no-results fee, $0.0012)." },
        { "searchQuery": "declined", "reason": "Yandex declined to write an AI answer for this search term (the AI answer request is still charged)." }
    ]
}
```

**Dataset views** (Output tab, or `…/datasets/<id>/items?view=<name>` in the API): `overview` (Results — every row type, including ads and blocks of the full results page), `rankTracking` (positions, changes and tracked flags), `searches` (one row per search term), `ads` (full page: ads and blocks), `aiAnswers` and `changes` (position changes and new results, with Compare with the previous run).

### How to use

**First run:** paste a few search terms and press **Start** — Region is prefilled with Moscow, and everything else has working defaults. Change **Region** to your city, or clear it when you switch to yandex.com, .kz, .by or .uz.

| Main field | Default | What it does |
|---|---|---|
| Search terms | – | One per line; Yandex operators, `term \| City` and pasted Yandex result URLs work; duplicates are removed (counted in `RUN_SUMMARY.searchTermsDuplicate`) |
| Yandex domain | yandex.ru | yandex.ru, .com.tr, .com, .kz, .by or .uz |
| Region | Moscow (prefilled) | City or country name / region ID (yandex.ru and .com.tr) |
| Results per search term | 20 | 1–250 organic results; one charged page covers 20 |

Optional: **Result type** and **Output format** (full results page with ads and blocks; one row per search term) in the next section, and **Several regions** under Advanced search options.

1. Open the Actor and paste your **Search terms**, one per line. You can also paste Yandex results-page URLs (`https://yandex.ru/search/?text=…&lr=213`): the search term, Yandex domain and region are taken from the URL.
2. Pick the **Yandex domain** and a **Region** (city or country name, or a region ID).
3. Set **Results per search term** (20 by default, up to 250; you pay per started 20).
4. Optional: add **Track domains**, turn on **Compare with the previous run** or **AI answer**, choose **Full results page** for ads and result blocks, or give a term its own region with `term | City`.
5. Press **Start**. Results appear in the **Output** tab; export them as JSON, CSV, Excel or HTML.

Input JSON:

```json
{
    "queries": ["купить ноутбук", "погода москва", "site:habr.com python"],
    "searchDomain": "yandex.ru",
    "region": "Moscow",
    "maxResults": 20,
    "trackDomains": ["citilink.ru", "dns-shop.ru"]
}
```

Input for daily rank tracking with everything turned on (full results page $0.008 / $0.005 per 10 results, AI answer +$0.06 per term; comparison, tracking and the change filter are free):

```json
{
    "queries": ["купить ноутбук", "купить диван | Kazan"],
    "region": "Moscow",
    "maxResults": 20,
    "resultType": "fullPage",
    "trackDomains": ["citilink.ru", "dns-shop.ru"],
    "compareWithPreviousRun": true,
    "outputFormat": "searches",
    "aiAnswer": true
}
```

Monitoring inputs (schedule them daily):

```json
{ "queries": ["купить ноутбук"], "region": "Moscow", "maxResults": 50, "onlyNewResults": true }
```

```json
{ "queries": ["купить ноутбук"], "region": "Moscow", "maxResults": 50, "compareWithPreviousRun": true, "minPositionChange": 3, "trackDomains": ["citilink.ru"] }
```

API (replace `<YOUR_TOKEN>`):

```bash
curl -X POST "https://api.apify.com/v2/acts/cheapapi~yandex-serp-scraper/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"queries": ["купить ноутбук"], "region": "Moscow", "maxResults": 20}'
```

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_TOKEN>' });
const run = await client.actor('cheapapi/yandex-serp-scraper').call({
    queries: ['kahve makinesi'],
    searchDomain: 'yandex.com.tr',
    region: 'Istanbul',
    maxResults: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_TOKEN>")
run = client.actor("cheapapi/yandex-serp-scraper").call(run_input={
    "queries": ["погода алматы"],
    "searchDomain": "yandex.kz",
    "maxResults": 20,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["position"], item["url"])
```

### Use cases

- **Rank tracking for Russian, Turkish and CIS markets:** schedule daily runs with **Compare with the previous run** and get `positionChange` for every result and tracked domain, per city.
- **Local SEO:** see how rankings differ between Moscow, Saint Petersburg, Kazan or Novosibirsk — list them in **Several regions** to compare all cities in one run.
- **Competitor and ad research:** with **Full results page**, see which advertisers bid on your keywords and where product carousels appear.
- **Content gap analysis:** collect the top 100–250 results for a topic and analyse titles, snippets and domains.
- **Brand monitoring and reputation:** track which pages rank for your brand name, including `site:` and exact-phrase searches.
- **Datasets for AI and research:** clean, deduplicated SERP data with consistent `id`s.

### Advanced options

| Option | Default | What it does |
|---|---|---|
| Result type | Organic results | **Full results page** returns organic results, ads, the AI overview, knowledge panel, image/video/product blocks and related searches in page order ($0.008 / $0.005 per 10 organic results). |
| Output format | One row per result | **One row per search term** nests the results and adds tracked-domain positions. |
| Track domains | – | Marks results from your domains (and their subdomains) or from a site section such as `example.com/blog`; free. |
| Deliver only tracked-domain results | off | With Track domains (One row per result output only): stores only your domains' results; all positions are still checked and charged as usual. |
| Exclude domains | – | Leaves rows of these domains (or site sections) out of the dataset, in both output formats; positions are still checked, charged and numbered as usual. |
| Compare with the previous run | off | Adds `previousPosition`, `positionChange` and `isNew` against the last run with the same search term and settings (history kept in the key-value store named in **History store name**, default `yandex-serp-rank-history`, in your account); free. |
| Only results that moved at least | 0 | With Compare (One row per result output only): store only results that moved N+ places or are new (all positions still checked and charged). |
| Only new results | off | Monitoring: delivers only organic results not delivered for the same term in earlier runs (first run = everything). You pay for new results; nothing new = $0.0012 per processed request. |
| History store name | `yandex-serp-rank-history` | One history per project or client; failed history reads and saves are reported in `RUN_SUMMARY`. Run one run at a time per history name (two runs writing the same history at once can overwrite each other's records), or use separate names. |
| AI answer | off | Adds Yandex's AI answer with sources per search term (+$0.06; yandex.ru, .kz, .by, .uz) — once per term even with Several regions, since the answer is not region-specific. Yandex allows one AI answer per second, so 1,000 terms with AI answers take at least about 17 minutes. |
| Interface language | Automatic | Russian, Ukrainian, Belarusian or Kazakh on yandex.ru; Turkish on yandex.com.tr; English on yandex.com. |
| Several regions | – | Searches every plain search term in each listed region; each term × region is charged as its own search (at most 10,000 searches per run). |
| Device | Desktop | Desktop or mobile results page (full results page). |
| Save the page HTML | off | Stores each full results page's HTML and adds `htmlUrl` (included in the price). |
| Time period | Any time | Past 24 hours, past 2 weeks or past month. |
| Sort by | Relevance | Or by page date, newest or oldest first. |
| Safe search | Moderate | Strict (family filter) or off. |
| Fix typos automatically | on | Off searches exactly what you typed. |
| Results per website | 1 | 2–3 also shows other pages of the same website under its position. |
| Snippet passages | 4 | 1–5 text passages per snippet. |
| Location by IP address | – | Localizes results as if searched from that public IP (for domains without regions). |
| Maximum wait per search | 15 min | Safety limit; searches normally take seconds. |

Region is supported on yandex.ru and yandex.com.tr; when empty, the whole country is used. Options that do not apply to the chosen domain are ignored with a warning in the log.

### Output example

Organic result (real output of build 1.0.59 for `python` on yandex.ru, whole Russia; `savedCopyUrl` shortened):

```json
{
    "id": "da771f1da55fe13c",
    "runId": "Hs4ujkV031SOo3a9H",
    "searchQuery": "python",
    "searchDomain": "yandex.ru",
    "region": "Russia",
    "regionId": 225,
    "language": "auto",
    "device": "desktop",
    "scrapedAt": "2026-10-01T19:36:02.717Z",
    "type": "organic",
    "position": 1,
    "title": "The official home of the Python Programming Language",
    "url": "https://www.python.org/",
    "domain": "python.org",
    "snippet": "The core of extensible programming is defining functions. Python allows mandatory and optional arguments, keyword arguments, and even arbitrary argument lists. More about defining functions in Python 3.",
    "headline": null,
    "passages": [
        "The core of extensible programming is defining functions. Python allows mandatory and optional arguments, keyword arguments, and even arbitrary argument lists. More about defining functions in Python 3."
    ],
    "modifiedDate": "2006-10-29",
    "documentLanguage": "en",
    "mimeType": "text/html",
    "savedCopyUrl": "https://yandexwebcache.net/yandbtm?fmode=inject&…",
    "isTracked": false,
    "totalResults": 244710,
    "correctedQuery": null
}
```

`modifiedDate` is Yandex's own date for the page (often its first-seen date), unrelated to dates inside the snippet text. When Yandex shows the page description instead of text passages, `passages` is empty and `snippet` equals `headline`.

Full results page for `купить ноутбук` in Moscow (real output, first four rows; long texts shortened, context fields left out):

```json
[
    { "type": "block", "position": 1, "organicPosition": null, "adPosition": null, "title": null, "url": null, "domain": null, "sitelinks": [], "blockType": "products", "blockText": "Фильтры с оперативной памятью 16 ГБ с оперативной памятью 4 ГБ с SSD 1 …" },
    { "type": "organic", "position": 2, "organicPosition": 1, "adPosition": null, "title": "Ноутбуки для учёбы купить по низкой цене...", "url": "https://www.mvideo.ru/noutbuki-planshety-komputery-8/noutbuki-118/f/collection_bottom=dlya-ucheby", "domain": "mvideo.ru", "breadcrumbs": ["Ноутбуки, планшеты, компьютеры", "Ноутбуки"], "rating": 3.9, "sitelinks": [] },
    { "type": "ad", "position": 3, "organicPosition": null, "adPosition": 1, "title": "Ноутбуки - купить ноутбук цены, отзывы, характеристики...", "url": null, "domain": "citilink.ru", "snippet": "Купить ноутбук в СИТИЛИНК. Выгодные цены, кэшбэк и бонусы для юрлиц и физлиц…", "rating": 4.4, "sitelinks": [{ "title": "Ноутбуки Huawei MateBook", "url": null }, { "title": "Ноутбуки Asus", "url": null }] },
    { "type": "organic", "position": 4, "organicPosition": 2, "adPosition": null, "title": "Ноутбуки: купить в Москве недорого, цены...", "url": "https://www.xcom-shop.ru/catalog/kompyutery_i_noytbyki/noytbyki/", "domain": "xcom-shop.ru", "breadcrumbs": ["Компьютеры и ноутбуки", "Ноутбуки"], "rating": 4.6, "sitelinks": [] }
]
```

AI overview and related searches from the full results page for `эйфелева башня` (real output, shortened):

```json
[
    { "type": "block", "position": 1, "blockType": "ai-overview", "title": "Быстрый ответ Алисы AI", "blockText": "Эйфелева башня — один из самых узнаваемых символов Парижа и всей Франции. …", "blockLinks": [{ "title": "ru.wikipedia.org", "url": "https://ru.wikipedia.org/wiki/Эйфелева_башня" }, { "title": "znanierussia.ru", "url": "https://znanierussia.ru/articles/Эйфелева_башня" }] },
    { "type": "related-searches", "position": null, "relatedSearches": ["эйфелевая башня", "эйфелева башня в париже", "эйфелева башня высота", "эйфелева башня год постройки"] }
]
```

One row per search term with tracked domains (yandex.com.tr, Istanbul, shortened):

```json
{
    "searchQuery": "kahve makinesi",
    "searchDomain": "yandex.com.tr",
    "region": "Istanbul",
    "regionId": 11508,
    "totalResults": 230014,
    "totalResultsText": "230 bin yanıt bulundu",
    "organicCount": 5,
    "organicResults": [
        { "type": "organic", "position": 1, "title": "Kahve Makinesi Fiyatları, Markaları ve Modelleri 2026 | Trendyol.com", "url": "https://www.trendyol.com/kahve-makinesi-x-c1079", "domain": "trendyol.com" }
    ],
    "trackedDomains": [
        { "domain": "trendyol.com", "position": 1, "url": "https://www.trendyol.com/kahve-makinesi-x-c1079" },
        { "domain": "amazon.com.tr", "position": null, "url": null }
    ]
}
```

### Pricing

Typical cost: **$6 per 1,000 search terms with up to 20 results** on the Free plan, **$4 on Gold and above**. Apify platform usage (256 MB memory) is billed separately by Apify: in our tests about **$0.05–$0.08 per 1,000 search terms** of 10 organic results and about **$0.15 per 1,000 terms** with the full results page; usage grows with results per term, so measure with 10 terms first for large jobs.

| Event | Free | Bronze | Silver | Gold, Platinum, Diamond |
|---|---|---|---|---|
| Results page — per started 20 delivered organic results | $0.006 | $0.0055 | $0.005 | $0.004 |
| Full results page — per started 10 delivered organic results, with all ads and blocks between them | $0.008 | $0.007 | $0.006 | $0.005 |
| Search without results | $0.0012 | $0.0012 | $0.0012 | $0.0012 |
| AI answer (option) — per search term | $0.06 | $0.06 | $0.06 | $0.06 |

**Tip:** if you only want Yandex's AI overview when it appears, choose **Full results page**: for 10 results it costs only $0.002 more than Organic results on Free ($0.001 on Gold); for 20 results it is $0.016 vs $0.006 ($0.010 vs $0.004 on Gold) and needs no $0.06 AI answer fee.

The **AI answer** option is different: it is a separate, more expensive request in which Yandex writes a fresh answer for *every* search term, so it has its own fee ($0.06). For comparison, Actors that scrape only the AI block of a page charge about $0.002–$0.005 per row.

All-in example: **1,000 terms × up to 20 results on Free = $6.00 Actor fee + about $0.05–$0.08 platform usage ≈ $6.06–$6.08** ($4.05–$4.08 on Gold).

Worked examples (Free plan / Gold plan):

- **1,000 search terms × top 20:** 1,000 pages = **$6.00 / $4.00**.
- **100 search terms × top 100:** 500 pages = **$3.00 / $2.00**.
- **50 search terms × full results page, top 20:** 100 full pages = **$0.80 / $0.50**.
- **100 search terms × top 20 with AI answers:** $0.60 + $6.00 = **$6.60 / $6.40**.
- A search term that returns 3 results is charged 1 page; one with no results pays $0.0012.
- **Only new results** with nothing new: $0.0012 per processed request — a 10-result term costs $0.0012, a 250-result term up to $0.0036 (organic, 3 requests) or $0.006 (full results page, 5 requests); a backup request, rarely needed, adds the same fee once more. 1,000 unchanged 10-result terms = **$1.20**.
- Full results page with 250 results is requested in up to 5 pieces; you still pay per delivered 10 organic results.

**Limits and the Free plan**

- **Maximum charge per run:** a search term only starts when all its requested pages still fit your limit, so the limit is never exceeded; terms that return fewer results leave room for more. If the limit is lowered during a run (for example by the Free-plan allowance), the last term can be delivered in part, and the run says so in its status message.
- **Skipped search terms** are counted (not charged) in the log, the status message and `RUN_SUMMARY.searchTermsSkippedByLimit`.
- **Apify Free plan:** each Actor can be used for up to $0.25 of results per month (about 40 searches of up to 20 results, or about 4 AI answers — enough to try it; the full results page includes Yandex's AI overview at no extra fee). Any paid Apify plan removes this limit.

### Integrations

Use the results anywhere Apify connects: **Google Sheets**, **Make**, **Zapier**, **n8n**, **Slack**, webhooks or the Apify API. De-duplicate appended exports on `id` + `runId`: `id` identifies a result at a position for one search and does not include the date. AI agents can call the Actor as a rank-check tool through Apify's MCP server or API; the `searches` view gives one compact row per term.

**Daily rank tracking in 3 steps:**

1. Save your input as a **task** with `"compareWithPreviousRun": true`, `"outputFormat": "searches"` and your `trackDomains`.
2. **Schedules → Create** → pick the task, e.g. every day at 06:00 (cron `0 6 * * *`).
3. **Integrations → Webhook** on "Run succeeded" → your URL (or Slack/Make/Zapier). The payload contains `resource.defaultDatasetId`; read `https://api.apify.com/v2/datasets/<datasetId>/items?view=searches` to get each term's `trackedDomains` with `position`, `previousPosition` and `positionChange`.

### FAQ

**Is it legal, and does the output contain personal data?**
The Actor collects publicly visible search results: titles, URLs and snippets of web pages (which may mention people, e.g. on news or profile pages). No account, cookie or user data is collected, and nothing about you is sent to Yandex except your search terms and options. Make sure your use of the data complies with the laws of your country and the rights of the content owners.

**How fresh is the data, and is it the same as in my browser?**
Every search is made live when you run the Actor; nothing is served from an old cache. You get the non-personalized results Yandex shows to a signed-out user in the chosen region and device; your own browser can differ slightly because of your search history, account and exact location.

**How fast and reliable is it?**
Each search term usually takes 2–10 seconds, and many run in parallel: 1,000 search terms take about 6 minutes (measured: 136 terms in 51 seconds). In our live load tests 276 of 276 search terms were completed without a failure; in a separate timing test of 60 searches the median was 3 seconds and 2 searches waited about 95 seconds in Yandex's queue — the Actor now sends one backup request after 15 seconds for such cases (counted in `RUN_SUMMARY.backupRequests`).

**Why did I get fewer results than I asked for?**
Yandex shows at most 250 results per search term, and for rare terms far fewer. For deep results (above 100), Yandex can reorder results between its result pages; a URL that appears twice is delivered once, so a few positions may be missing. You are charged only for delivered results.

**Why was I charged for a search with no results, or for a declined AI answer?**
Yandex processed the search but found nothing (or it could not be completed after processing), which costs a small no-results fee of $0.0012. Likewise, when Yandex declines to write an AI answer, it still bills that request, so the $0.06 AI answer fee applies (`answerRejected: true`). Search terms rejected before processing (e.g. longer than 400 characters) are free. If a later results page of a term fails, the delivered part is kept and only those pages are charged (`Only part of the results could be collected` in `problems`).

**Which region should I use, and can I use search operators?**
Rankings on yandex.ru depend strongly on the city: use the city your customers search from ("Moscow", "Saint Petersburg", "Novosibirsk"); without a region you get results for the whole country (Russia or Turkey). Russian names and region IDs work too, and an unknown name gets suggestions. Yandex operators such as `site:`, `"exact phrase"`, `-word` and `!word` work in search terms. `term | City` sets a region for one term only when the part after `|` is a known place; if you need Yandex's OR operator `|` followed by a place name, put the region in the Region field instead.

**Is there a limit on the Apify Free plan?**
Yes: up to $0.25 of results per Actor per month (about 40 searches of up to 20 results). The run then ends with a clear message; any paid Apify plan removes the limit. Apify platform usage is billed separately for all plans.

**How do I track rankings or get only new results?**
Schedule the Actor (e.g. daily) and turn on **Compare with the previous run** — every organic result gets `previousPosition`, `positionChange` (positive = moved up) and `isNew`, and each tracked domain its position change — or **Only new results**, which delivers only organic results whose URL is new for that search term (you pay only for those; if nothing is new, $0.0012 per processed request applies). Both options can be combined: you get only the new results, while tracked-domain `position` and the rank history still cover every result found this run. The history stays in your account.

**Why is `url` null for ads?**
Ads link through Yandex's click-tracking redirect, which is not the advertiser's page. You get the advertiser's displayed domain, title, text and rating instead.

### Support

Questions, a wrong result or a feature request? Open the **Issues** tab of this Actor and include the run ID — we aim to answer within one working day.

### Limitations

- Results are not personalized (no Yandex account or search history), so positions can differ slightly from a signed-in browser.
- Positions above 100 come from separate result pages, which Yandex may reorder slightly between requests.
- AI answers are not region-specific, are written in Russian, Kazakh or Uzbek, and Yandex sometimes declines to answer (the request is still charged).
- The full results page reflects Yandex's layout; if Yandex redesigns the page, ads and blocks may be classified less precisely until we update the Actor (organic results mode is not affected).
- The AI overview (Alice AI quick answer), knowledge panel and related searches are returned when Yandex includes them in the results page it serves; Yandex shows them only for some search terms, and some are added later by the browser and then not included.
- `modifiedDate` is the date Yandex reports for the page, which is often older than the last edit.
- Region selection works for yandex.ru and yandex.com.tr; for other domains use **Location by IP address**.
- Now and then Yandex answers a full-results-page request with a verification page instead of results. The Actor sends it once more; if that fails too, the search term is reported in `RUN_SUMMARY` and charged only the $0.0012 no-results fee.
- Raising **Results per search term** later: the added positions get `isNew: null` (unknown) in the first comparison, because the previous run did not look that deep. To start the history from scratch, delete the history key-value store in your account (Storage → Key-value stores; default name `yandex-serp-rank-history`, or your **History store name**). It keeps one small record per search term and settings; for **Only new results** it remembers at most the latest 10,000 URLs per term, so older URLs beyond that could be delivered again as new.
- **Compare with the previous run** compares runs with the same search term and the same settings (domain, region, language, device, period, sort, safe search, typo fixing, results per website, location IP, result type).
- A region outside the domain's country (e.g. Moscow on yandex.com.tr) is allowed — it shows that domain as seen from the region — and the log says so.

# Actor input Schema

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

What you would type into Yandex, one per line (up to 400 characters / 40 words each). Up to 10,000 searches per run (search terms × <b>Several regions</b>); duplicates are removed.<br>• Yandex search operators work: <code>site:</code>, <code>"exact phrase"</code>, <code>-word</code>, <code>!word</code>.<br>• Own region for one term: <code>купить диван | Kazan</code> (only when the part after <code>|</code> is a known place; for a literal Yandex OR like <code>a | Moscow</code>, set the region in the Region field instead).<br>• Or paste a Yandex results-page URL (<code>https://yandex.ru/search/?text=…\&lr=213</code>): its search term, domain and region are used.

## `searchDomain` (type: `string`):

Which Yandex search to use. Each domain has its own index and rankings. For yandex.com, .kz, .by and .uz, clear <b>Region</b> (they use <b>Location by IP address</b>).

## `region` (type: `string`):

Where the search is made from — rankings differ a lot between cities.<br>• A city or country name in English or Russian ("Moscow", "Kazan", "Istanbul", "Москва") or a Yandex region ID (213 = Moscow).<br>• Works on yandex.ru and yandex.com.tr.<br>• Empty = the whole country (Russia or Turkey).<br>• One term can have its own region: <code>term | Kazan</code>.<br>• A name that exists in several places means the larger region; give the numeric ID to be exact.<br>• Clear this field for yandex.com, .kz, .by and .uz (they use <b>Location by IP address</b> instead).

## `maxResults` (type: `integer`):

How many organic results to collect for each search term (1–250; Yandex shows at most 250). Organic results are charged per started group of 20 delivered results (20 results = 1 page, 100 results = 5 pages); the full results page per started group of 10.

## `resultType` (type: `string`):

<b>Organic results</b>: the ranked organic results with title, URL, snippet passages, page date and language — the right choice for rank tracking. <b>Full results page</b>: everything the results page shows, in order — organic results (with sitelinks and shop ratings), ads, the Alice AI quick answer (AI overview) with sources, the knowledge panel, image/video/product blocks and related searches — for desktop or mobile, optionally with the page HTML.

## `outputFormat` (type: `string`):

<b>One row per result</b> is best for spreadsheets. <b>One row per search term</b> puts all results of a search term in one row (with tracked-domain positions), which is handy for rank tracking and APIs.

## `trackDomains` (type: `array`):

Your own or competitors' domains, e.g. <code>citilink.ru</code> or <code>trendyol.com</code> (subdomains included), or a section of a site, e.g. <code>example.com/blog</code> (only URLs under that path). Matching results get <code>isTracked: true</code>. Choose Output format “One row per search term” to also get each entry's position (or null when not found) in one row per search term. Free.

## `trackedOnly` (type: `boolean`):

With <b>Track domains</b> and Output format “One row per result”: the dataset gets only the results of your tracked domains (all positions are still checked). The checked results pages are charged as usual — this only keeps your dataset small. Ignored unless Track domains is filled and Output format is “One row per result”.

## `excludeDomains` (type: `array`):

Domains (or site sections such as <code>example.com/forum</code>) whose results you do not want in the dataset, e.g. marketplaces. All positions are still checked and charged as usual and keep their real position numbers; only the matching rows are left out. With “One row per search term” they are left out of the nested lists (tracked-domain positions still count every result).

## `compareWithPreviousRun` (type: `boolean`):

Rank tracking over time: remembers the positions of this run in a key-value store in your account (the <b>History store name</b>, default <code>yandex-serp-rank-history</code>) and adds <code>previousPosition</code>, <code>positionChange</code> (positive = moved up) and <code>isNew</code> to every organic result of the next run with the same search term and settings. Free; ideal with a daily schedule.

## `minPositionChange` (type: `integer`):

With <b>Compare with the previous run</b> and “One row per result”: store only organic results whose position changed by at least this many places (up or down) or that are new — ideal for daily change alerts. 0 = store everything. All positions are still checked and charged as usual; the first run (nothing to compare with yet) stores everything. Ignored unless Compare with the previous run is on.

## `onlyNewResults` (type: `boolean`):

Monitoring: deliver only organic results whose URL was not delivered for the same search term (and settings) in earlier runs — the first run delivers everything and remembers it (in the <b>History store name</b> store of your account, default <code>yandex-serp-rank-history</code>). You pay only for new results; when nothing is new, the small no-results fee ($0.0012) per processed request applies, because the search was really made (a 10-result term: $0.0012; a 250-result term: up to $0.0036 in organic mode or $0.006 with the full results page). Together with <b>Compare with the previous run</b>, the delivered new results also get their comparison fields, and the rank history still covers every result.

## `historyName` (type: `string`):

Name (lowercase letters, digits and hyphens) of the key-value store in your account that keeps the rank history for Compare / Only new results (default <code>yandex-serp-rank-history</code>). Use one name per project or client to keep their histories apart; delete the store to start over.

## `aiAnswer` (type: `boolean`):

Also get an AI answer written by Yandex search for each search term: the answer text (Markdown with \[n] citation marks) and its sources. Yandex writes these answers in Russian, Kazakh and Uzbek, so this works on yandex.ru, .kz, .by and .uz. Costs $0.06 per search term (10× a results page on Free, 15× on Gold), charged also when Yandex declines to answer. Tip: if you only need Yandex's AI overview when it is shown, choose Result type “Full results page” instead — it includes the overview at no AI answer fee. Ignored on yandex.com and yandex.com.tr.

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

Language of the Yandex interface, which slightly influences results. yandex.ru supports Russian, Ukrainian, Belarusian and Kazakh; yandex.com.tr supports Turkish; yandex.com supports English. Other combinations are ignored with a warning.

## `regions` (type: `array`):

Search every search term in each of these regions (city or country names, or region IDs), e.g. <code>Moscow</code>, <code>Saint Petersburg</code>, <code>Kazan</code>. Replaces <b>Region</b> for plain search terms; each term × region is charged as its own search. yandex.ru and yandex.com.tr only. Search terms × regions must not exceed 10,000 searches per run.

## `device` (type: `string`):

Desktop or mobile results page (the mobile page shows ads and blocks in a different order). Applies to “Full results page”.

## `saveHtml` (type: `boolean`):

“Full results page” only: also store the complete HTML of every results page in the run's key-value store; each row gets an <code>htmlUrl</code> link to it. Included in the price.

## `period` (type: `string`):

Only return pages that were updated within this period, using Yandex's page date (pages without a date may be left out). Leave “Any time” for rank tracking.

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

Normal Yandex ranking, or sorted by page date. Use Relevance for rank tracking.

## `safeSearch` (type: `string`):

Filtering of adult content in the results. Moderate is what most Yandex users see; Strict is the family filter; Off shows everything.

## `fixTypos` (type: `boolean`):

When on, Yandex silently searches for the corrected spelling of a misspelled term (the correction is returned in <code>correctedQuery</code>). Turn off to search exactly what you typed.

## `resultsPerDomain` (type: `integer`):

1 = one result per position, exactly like the normal results page. 2–3 = also show up to 2–3 pages of the same website under its position (<code>domainGroupPosition</code>), which Yandex otherwise hides. Organic results only.

## `snippetPassages` (type: `integer`):

How many text passages to return in each organic result's snippet (1–5). Organic results only.

## `locationIp` (type: `string`):

Optional: a public IPv4 or IPv6 address; results are localized as if the search was made from that address. Useful for yandex.com, .kz, .by and .uz, which do not support Region. Leave empty in most cases.

## `maxWaitMinutes` (type: `integer`):

How long to wait for one search before giving up. Searches normally finish in 2–10 seconds; the wait only matters when Yandex is overloaded.

## Actor input object example

```json
{
  "queries": [
    "купить ноутбук",
    "погода москва",
    "купить диван | Kazan"
  ],
  "searchDomain": "yandex.ru",
  "region": "Moscow",
  "maxResults": 20,
  "resultType": "organic",
  "outputFormat": "results",
  "trackedOnly": false,
  "compareWithPreviousRun": false,
  "minPositionChange": 0,
  "onlyNewResults": false,
  "aiAnswer": false,
  "language": "auto",
  "device": "desktop",
  "saveHtml": false,
  "period": "any",
  "sortBy": "relevance",
  "safeSearch": "moderate",
  "fixTypos": true,
  "resultsPerDomain": 1,
  "snippetPassages": 4,
  "maxWaitMinutes": 15
}
```

# Actor output Schema

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

No description

## `rankTracking` (type: `string`):

No description

## `searches` (type: `string`):

No description

## `ads` (type: `string`):

No description

## `aiAnswers` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `runSummary` (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 = {
    "queries": [
        "купить ноутбук",
        "погода москва",
        "купить диван | Kazan"
    ],
    "searchDomain": "yandex.ru",
    "region": "Moscow",
    "maxResults": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("cheapapi/yandex-serp-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": [
        "купить ноутбук",
        "погода москва",
        "купить диван | Kazan",
    ],
    "searchDomain": "yandex.ru",
    "region": "Moscow",
    "maxResults": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("cheapapi/yandex-serp-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": [
    "купить ноутбук",
    "погода москва",
    "купить диван | Kazan"
  ],
  "searchDomain": "yandex.ru",
  "region": "Moscow",
  "maxResults": 20
}' |
apify call cheapapi/yandex-serp-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cheapapi/yandex-serp-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/oK3VgMBTqY3XSviXN/builds/IhDbPPUbUsU0wiIVJ/openapi.json
