# Yandex Search Scraper - Yandex Search API & SERP Results (`s-r/yandex-serp`) Actor

Scrape Yandex search results into clean JSON rows: position, title, URL, domain and snippet for any query on yandex.ru, .com, .com.tr, .kz and .by, with region (lr) control, up to 25 pages, plus free related searches. For SEO and market research in Russia, Turkey and the CIS. Pay per result.

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

## Pricing

$3.00 / 1,000 organic search results

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?

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 Search Scraper - Yandex Search API for SERP Results

This Yandex search API turns any keyword into clean organic search results for SEO rank tracking, competitor analysis and market research in Russia, Turkey, Kazakhstan, Belarus and the wider CIS. Each organic result becomes one dataset row with its position, title, destination URL, domain and snippet. When Yandex displays related searches, the Actor can also include them as separate, free rows.

Use it to inspect searches for Russia, Turkey, Kazakhstan, Belarus and international audiences. Choose a Yandex market and, when location matters, supply a Yandex region identifier. The market and region select the search context; the Actor does not promise that every result comes from a particular national frontend. Result titles and snippets preserve the text Yandex returns.

### Who uses this Yandex search API

- **SEO agencies** that report rankings for clients selling in Russia, Turkey or Kazakhstan, where Google is not the only search engine that matters.
- **In-house SEO teams** checking which pages rank for a keyword in Moscow, Saint Petersburg, Istanbul or Almaty, and how that changes after a release.
- **Market researchers** mapping which marketplaces, brands and publishers own the first pages of Yandex for a product category.
- **Developers** who need Yandex SERP data as JSON in a pipeline, without maintaining their own parser for every layout change.

### How to use the Yandex search API

1. Open the Actor, enter one or more queries and pick the Yandex market (`yandex.ru` by default).
2. Optionally set `region` to a Yandex `lr` identifier, such as 213 for Moscow, and `pages` for deeper results.
3. Start the run. Organic rows are written to the dataset, query by query.
4. Export the dataset as JSON, CSV or Excel, or read it through the Apify API from your own code.

From Python, with the official Apify client:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("s-r/yandex-serp").call(run_input={
    "queries": ["купить диван"],
    "domain": "yandex.ru",
    "region": 213,
    "pages": 2,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["record_type"] == "organic":
        print(row["position"], row["domain"], row["title"])
```

### Yandex Search Results Scraper input

Supply `queries` as a list of strings, or as text with one query per line. Leading and trailing whitespace is removed, and blank entries are ignored. Repeated queries remain separate searches. You may submit up to 1000 queries, each containing at most 400 characters. Search operators in your query are preserved.

This input uses an actual search captured during validation:

```json
{
  "queries": ["купить диван"],
  "domain": "yandex.ru",
  "region": 213,
  "pages": 2,
  "include_related": true
}
```

`domain` defaults to `yandex.ru`. Supported markets are `yandex.ru`, `yandex.com`, `yandex.com.tr`, `yandex.kz` and `yandex.by`. Without `region`, the respective regional defaults are 225 for Russia, 983 for Turkey, 159 for Kazakhstan and 149 for Belarus. The international market has no fixed regional default; supply `region` when you need a reproducible location context.

`region` overrides the market default with a positive Yandex `lr` identifier. Common choices include 213 for Moscow, 2 for Saint Petersburg, 11508 for Istanbul, 10393 for Almaty and 84 for the United States. A correctly shaped number is accepted, but Yandex may silently ignore an identifier it does not recognise. Use region identifiers that you have checked for your intended location.

`pages` sets the maximum pages per query, from 1 to 25. Its default is one. Collection stops earlier when the search has ended. `include_related` defaults to true and adds suggestions only when they are present on the source page. Disable it when you want an organic-only dataset.

`language` accepts an optional lowercase two-letter label such as `ru`, `tr` or `en`. It is echoed in the output and does not control ranking or translate results. Write the query in your target language and use the appropriate region for local searches.

### Output and dataset fields

Organic rows have `record_type: "organic"` and `_type: "serp_result"`. Their main fields are:

- `query`: the original trimmed search query.
- `position`: organic position across the collected pages, after URL deduplication.
- `page`: the one-based source page number.
- `title`, `url` and `domain`: result title, absolute destination and hostname without `www.`.
- `snippet`, `displayed_url` and `site_name`: source text, or null when absent.
- `region` and `yandex_domain`: requested location context and selected market.
- `source`, `engine` and `fetched_at`: product identifier, search engine and UTC retrieval timestamp.

This is the first organic row of a real run for `купить диван` in Moscow (`region` 213) on `yandex.ru`:

```json
{
  "source": "yandex-serp",
  "engine": "yandex",
  "query": "купить диван",
  "fetched_at": "2026-10-05T00:19:17Z",
  "page": 1,
  "language": null,
  "region": 213,
  "yandex_domain": "yandex.ru",
  "url": "https://www.divano.ru/catalog/divany/nedorogo/",
  "title": "Недорогие диваны в Москве, купить диван дешево, цены...",
  "domain": "divano.ru",
  "displayed_url": "divano.ru › catalog › divany › nedorogo",
  "site_name": "Divano.ru",
  "snippet": "Диваны недорого купить от производителя - широкий ассортимент мебели в наличии.",
  "_type": "serp_result",
  "record_type": "organic",
  "position": 1
}
```

Positions start at one for each query. If the same URL appears on multiple pages of that query, the Actor delivers it once. The same URL can still appear for different queries, because those rows describe different searches. Dataset order follows the supplied query list; within each query, organic rows precede related searches.

Related rows have `record_type: "related"`, `_type: "related_search"` and `related_query`. They also contain the original query, page, block position, region and retrieval timestamp. They have no result URL, title or snippet. Filter by `record_type` when exporting organic rankings to a spreadsheet or joining results to a domain report.

A related row from a real run for `как сварить борщ` in Moscow looks like this:

```json
{
  "_type": "related_search",
  "record_type": "related",
  "source": "yandex-serp",
  "engine": "yandex",
  "query": "как сварить борщ",
  "fetched_at": "2026-10-05T00:21:09Z",
  "page": 1,
  "position": 1,
  "language": null,
  "region": 213,
  "yandex_domain": "yandex.ru",
  "related_query": "как сварить борщ со свеклой и свежей капустой пошаговый рецепт"
}
```

Advertisements, local business widgets, video carousels and other search widgets are excluded from organic results. Related searches are optional source content, so their absence is a normal outcome. The Actor does not generate suggestions to fill missing blocks.

### Use cases for Yandex SERP data

**Yandex rank tracking.** Run the same keyword list on a schedule with a fixed `region` and compare `position` per `url` between runs. Because positions are counted across pages after deduplication, a move from 12 to 8 means the page really overtook four organic results.

**Yandex SEO audits.** Collect the first two or three pages for a client's core keywords and group the rows by `domain` to see which competitors, marketplaces and aggregators hold the visibility. This is the quickest way to explain why SEO for Yandex differs from SEO for Google in the same market.

**Regional comparisons.** Run one query with several `region` values, for example Moscow and Saint Petersburg, or Istanbul on `yandex.com.tr`, and compare the domains that appear. Local businesses and regional retailers often rank very differently between cities.

**Keyword and content research.** Related searches show how people phrase follow-up queries in Russian, Turkish or Kazakh. Feed them back in as new queries, or use them to plan content for a market where English keyword tools have little data.

### Compared with other Yandex scrapers

Several Yandex scrapers already exist. This one is built for analysis rather than raw page dumps:

- **One row per organic result.** Many alternatives return one item per page with a nested results array. Here every result is a flat row, ready for a spreadsheet, BI tool or database join.
- **Pay per delivered result, no start fee.** Some tools charge a setup fee per run plus a price per page, whatever the page contains. Here you pay only for organic rows that are actually delivered; related searches and empty searches are free.
- **Region control by `lr` identifier.** Choose the market and the exact Yandex region instead of a language switch that silently changes the location.
- **Ads and widgets excluded from rankings.** Organic positions are not inflated by advertisements, maps or carousels.
- **Search operators preserved.** Queries with quotes, `site:` and similar operators are sent as you write them.

### Pricing and free usage

The Actor uses pay-per-event pricing at a list price of $0.003 per organic result, which is $3 per 1,000 results. Only delivered organic rows are charged through the `result` event. Related searches are free, and a search that delivers no organic results has no result charge. There is no start fee. Check the Actor's Pricing tab for the current event price before running a large collection.

Users without a paid Apify plan receive at most ten dataset rows per run and use one source page per query. Related rows can use part of that row allowance when fewer organic rows are present; they still have no result charge. Paid users can request the full page range. Charges count the rows actually delivered after deduplication and any applicable delivery cap.

The default key-value store contains an `OUTPUT` record with the delivery summary and free-usage flags. When collection encounters source errors, the run can also include structured errors with the query and page involved. Inspect these alongside the dataset when completeness matters.

### Large searches and incomplete results

The Actor continues large query lists and multi-page searches automatically. If a later source page fails, earlier results are retained and the page failure is reported. A query with no organic results does not prevent subsequent queries from being collected. A run can therefore contain useful rows together with a warning about a query or page that could not be completed.

For direct API integrations, a response may include `next_cursor`. Send that value as `cursor` with the same queries and search options to continue. The cursor preserves the next page, previous URLs and pending related searches. Keep the search options unchanged throughout that collection; start again without a cursor when you change them.

### FAQ

#### Does the selected domain guarantee a particular Yandex frontend?

The domain selects the market and its default region. The output echoes that choice in `yandex_domain`. Use an explicit `region` to define the location context; `domain` on an organic row always describes the destination website.

#### Are related searches charged?

No. Only rows with `record_type: "organic"` trigger the result event. Related searches are separate rows so you can filter, export and analyse them without duplicating the same suggestion on every organic result.

#### Why are there fewer results than expected?

Yandex may display fewer organic results on a page, reach the end of a query, repeat URLs across pages or fail to return a usable page. Deduplication and free-usage limits can also reduce the delivered count. Check the run summary and warnings before treating an incomplete search as a ranking change.

#### Does language translate titles or change ranking?

No. It is an output label only. Titles and snippets stay in the language returned by Yandex. Query wording and the requested region are the controls to use for your search context.

#### Is this the official Yandex Search API?

No. Yandex offers its own paid search API through its cloud platform, which requires a Yandex Cloud account and its own billing. This Actor collects the public search results page and returns flat JSON rows, so you can start without a Yandex account and pay per result on Apify.

#### Can I use it as a Yandex rank tracker?

Yes. Schedule the Actor with a fixed query list, market and `region`, then compare `position` per `url` across runs. Keep the options identical between runs so that changes reflect the ranking, not the search context.

#### Which Yandex domains and countries are supported?

`yandex.ru`, `yandex.com`, `yandex.com.tr`, `yandex.kz` and `yandex.by`. Any positive Yandex `lr` region identifier can be combined with them, for example 213 for Moscow or 11508 for Istanbul.

# Actor input Schema

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

Search queries as a list or one query per line. Blank entries are ignored; duplicate queries are retained. At most 1000 queries, each at most 400 characters.

## `domain` (type: `string`):

Yandex market. Selects the default lr region, rather than guaranteeing a particular frontend: ru=225, com.tr=983, kz=159, by=149; com uses the visitor region unless region is supplied.

## `region` (type: `integer`):

Positive Yandex lr region id overriding the market default: 213 Moscow, 2 Saint Petersburg, 11508 Istanbul, 10393 Almaty, 84 USA. Yandex can silently ignore unknown ids.

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

Optional lowercase two-letter language label, echoed in output only. It does not change the search language or ranking; query text and region determine the results.

## `pages` (type: `integer`):

Maximum pages per query. Stops earlier when Yandex has no more organic results. Large requests continue with next_cursor.

## `include_related` (type: `boolean`):

Include free related-query rows after the organic results of each query, only where Yandex displays them.

## `cursor` (type: `string`):

Opaque next_cursor from the previous response. Keep every search option unchanged when continuing; omit for a new search.

## Actor input object example

```json
{
  "queries": [
    "купить диван"
  ],
  "domain": "yandex.ru",
  "region": 213,
  "pages": 1,
  "include_related": true
}
```

# Actor output Schema

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

Filter record_type=organic for ranked results, or related for search suggestions.

## `output` (type: `string`):

Delivered counts, free-tier flags and source errors.

## `errors` (type: `string`):

Structured errors when a query or page could not be collected.

# 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": [
        "купить диван"
    ],
    "region": 213
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/yandex-serp").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": ["купить диван"],
    "region": 213,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/yandex-serp").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": [
    "купить диван"
  ],
  "region": 213
}' |
apify call s-r/yandex-serp --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/yandex-serp"
        }
    }
}
```

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/b9evz7rVeHiYCd2gg/builds/yYg7jh7rMRfjkRFd5/openapi.json
