# Yandex Search Scraper: Regional Rank Tracker (`apt_marble/yandex-search-scraper`) Actor

Track Yandex rankings city by city. Give it your search terms and a Russian region and get every ranked result as clean rows: position, title, address, domain, description, related searches and the answer block. Eighteen regional markets, up to 250 ranked positions per term. No account needed.

- **URL**: https://apify.com/apt\_marble/yandex-search-scraper.md
- **Developed by:** [Hamza](https://apify.com/apt_marble) (community)
- **Categories:** SEO tools
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 search result founds

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 Search Scraper

Track where you rank on Yandex, city by city. Give it a list of search terms and
a Russian region, and it returns every result the source ranks for those terms as
clean rows: position, title, address, domain, description, related searches and
the direct-answer block. Built for SEO teams, agencies and marketplaces working
the Russian-language market — no account and no login are needed, just run it.

### What you can do with it

- **Track rankings in the cities you actually sell into.** Moscow, Saint
  Petersburg, Novosibirsk and fifteen more regions each return their own
  ordering, and every row records the region it was answered for.
- **Watch competitors move.** Run the same terms on a schedule and see which
  domains gain and lose positions over time.
- **Audit a whole keyword set at once.** Hundreds of search terms in one run,
  each producing a full table of results.
- **See the whole result surface, not just the ten blue links.** Related
  searches and the direct-answer block come back alongside the ranked results,
  so you can tell when you have lost the answer box.
- **Find where a market's demand actually goes.** Collect the full depth the
  source ranks for a single term — about 250 positions — and see the long tail
  of sites competing for it.
- **Feed it straight into a report.** One flat table, stable columns, ready for
  a spreadsheet or a dashboard.

### What you get

One row per result. A real row, abridged:

```json
{
  "query": "новости города",
  "requestedRegionId": 213,
  "regionId": 213,
  "regionName": "Moscow",
  "page": 1,
  "type": "organic",
  "position": 4,
  "positionOnPage": 4,
  "title": "Новости Москвы сегодня — последние новости города | Москва 24",
  "url": "https://www.m24.ru/news",
  "displayUrl": "m24.ru › news",
  "domain": "m24.ru",
  "snippet": "Последние новости Москвы: происшествия дня, ДТП, транспорт, главные экономические и социальные события города.",
  "sitelinks": [],
  "collectedAt": "2026-08-17T11:57:05.044Z"
}
```

### Input reference

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `queries` | list of text | — (required) | The search terms to look up. Terms written in Russian give the most complete results, because this is the Russian-language search market. Up to 1,000 terms per run. |
| `region` | choice | `Moscow` | The city or region the search is run for. Rankings differ a lot between Russian cities, so pick the market you sell into. Eighteen choices, from nationwide down to individual cities. |
| `maxResultsPerQuery` | number | `20` | How deep to go in the ranked results for each term, up to 250 — which is about as deep as the source ranks a single term. Related searches and the answer block are not counted against this depth: they are one small block each, reported once per search term, and they come back in full beside the ranked rows. |
| `resultTypes` | choice list | `Organic results` | Which parts of the result page to keep: organic results, related searches, the answer block — any combination. Related searches and the answer block are reported once per search, from the first result page the run reads that carries them. |
| `parallelSearches` | number | `3` | How many search terms to work through at the same time. Raise it for large jobs. |

### Output fields

| Field | Type | What it is |
| --- | --- | --- |
| `query` | text | The search term this row came from. |
| `type` | text | `organic`, `related` or `featured`. |
| `position` | number | The result's rank for this term, counted across result pages. Related searches and the answer block are numbered within their own block, not among the ranked results. |
| `positionOnPage` | number | The result's rank within its own result page. |
| `page` | number | Which result page it was found on. |
| `title` | text | The result's headline. |
| `url` | text | Where the result points. Empty for related searches, which are search terms rather than addresses. |
| `displayUrl` | text | The address as the source prints it under the headline. |
| `domain` | text | The result's domain. |
| `snippet` | text | The description shown under the headline. |
| `sitelinks` | list | Extra links shown under a result, where the source shows them. |
| `regionId` | number | The region the result was actually answered for. |
| `regionName` | text | That region's name in English, where it is one of the regions on offer. |
| `requestedRegionId` | number | The region the run asked for, so any difference is visible. |
| `collectedAt` | text | When the row was collected, as an ISO timestamp. |

Every field is present in every row. A value the source does not publish comes
back empty rather than guessed, so your columns stay stable.

### Pricing

You pay per event, and there are two:

| What you pay for | When it is charged |
| --- | --- |
| **Search result found** | Once for every result row written to your table. |
| **Search completed** | Once for each search term in each region, when the search has been carried out — including when it legitimately turns up nothing, because that is still a full unit of work. It is **not** charged when a search could not be completed. |

**Worked example.** 100 search terms, 20 results each, one region: 2,000 result
rows plus 100 completed searches. Nothing else is charged: retrying a search that
came back incomplete costs you nothing, and a search that fails is not billed.

### Limits & what this actor cannot do

- **There is no single true ranking, and this actor does not pretend there is
  one.** Yandex serves slightly different orderings to different visitors and
  changes them continuously. Two collections minutes apart commonly agree on
  eight or nine of the top ten sites but not on their exact order. Treat a
  position as the rank in the market and at the moment it was collected in, and
  compare trends over several collections rather than trusting a single number.
- **The source publishes a limited number of results for any one search** —
  about 250 ranked positions per term per region — so very broad terms return
  what it makes available rather than an unlimited list. It also repeats some
  addresses across its own result pages, and those are reported once, so a term
  taken to full depth typically yields around 200 rows rather than 250.
- **Paid placements are not collected and are not offered.** The entry this
  actor reads does not serve them for these searches at all, so an "ads" column
  could only ever say "none" — which reads like a finding and is not one. Rather
  than sell an answer that is structurally impossible to get right, the type is
  not on the menu.
- **The answer block and related searches appear only on the searches that carry
  them**, and their presence varies in two separate ways. It varies from one
  result page to the next: measured live, the same search served a page one with
  no related strip and a page three with nine. And it varies **between one
  reading of the very same page and the next** — a question that plainly has a
  direct answer served the answer block on **three of six consecutive readings**
  of an identical search. Each is therefore reported **once per search, from the
  first page this run happens to read that carries it** — the row records which
  page that was. No extra page is read to hunt for one, so a search collected to
  a depth of one page reports only what that page carried, and **re-running the
  same job can legitimately return an answer block one time and not the next.**
  If you need one for a specific question, run that search on its own and expect
  to repeat it.
- **There is no date on a result.** The source does not publish when a page was
  written or last updated, so no such column is offered.
- **There is no total-results figure**, and none is invented. The actor reports
  what it actually collected.
- **It reports where pages rank, not how often people search for them.** No
  search-volume figure exists on this surface and none is estimated.
- **Regions are limited to the ones that genuinely change the results.**
  Eighteen Russian markets are offered, each confirmed to return its own local
  sites. Regions outside Russia are not offered, because selecting one would
  return a Russian ranking under another country's name.
- **If the source answers for a different region than the one selected**, the row
  says so: it records the region it was answered for as well as the one asked
  for, and the run summary counts it.
- **There are no star ratings or review counts, and no such columns are
  offered.** This was measured rather than assumed: across twelve live result
  pages chosen because they are exactly the commercial searches that would carry
  ratings if anything did — pizza, hotels, laptops, phones, fridges, dentists,
  sushi, coffee shops, restaurants, car repair — not one ordinary result carried
  a rating widget. The only ratings this entry publishes belong to the business
  cards in its map panel, which are organisations rather than web pages and are
  covered properly by the Yandex Maps actors. Putting them in a ranking table
  would mix shops into a column of web positions, so they are not collected here
  and no empty column is left behind pretending they might be.
- **If the same address appears on more than one result page for the same term,
  it is reported once**, at the first rank the source gave it.
- **A search the source refuses to complete is reported as a failed search,
  never as "no results found."** The run summary counts searches with results,
  searches that genuinely found nothing, and searches that failed as three
  separate numbers, and incomplete answers are detected and retried
  automatically before anything is reported.
- **It reports only what the source publishes to the public.** It does not sign
  in, sees nothing behind a login, and cannot reveal anything the source keeps
  private.
- **Speed depends on the size of the job and on the source's own response
  times.** No fixed throughput is promised.
- **The source's terms govern automated access.** You are responsible for using
  the data lawfully and in line with those terms, and for handling any personal
  data in line with applicable privacy law — including GDPR and Russian personal
  data law where they apply.

### FAQ

**Do I need an account on the source site?**
No. Nothing is signed in to and nothing is set up on your side.

**Does it need my login or password?**
No. It never asks for credentials of any kind, for the source site or anywhere
else.

**Can I schedule it?**
Yes. Schedule the same term list daily or weekly and you get a ranking history
you can chart. That is the intended way to use it.

**Will the positions match exactly what I see in my browser?**
Usually close, rarely identical. Yandex personalises and experiments constantly,
so the set of sites is stable while the exact order moves. Compare across several
collections rather than reading one position as an absolute truth.

**Why did one of my search terms come back with nothing?**
One of three things happened, and the run summary counts them separately so you
can always tell which: the source genuinely found nothing for it, the source
answered normally but carried none of the result types you selected (for example
you asked only for related searches and that search does not print any), or the
search could not be completed at all. A term that failed is never reported as a
term with no results.

**Can I track cities outside Russia?**
No. Only regions that were confirmed to return their own local results are
offered, and those are Russian. Offering a region that quietly returns Moscow's
ranking would be worse than not offering it.

**Can I collect more than 250 results for one term?**
No, and no actor can: about 250 positions is what the source ranks for a single
search. For more coverage, run more terms rather than deeper ones.

# Actor input Schema

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

The search terms to look up. One row is produced for every result found. Terms in Russian give the most complete results, because this is the Russian-language search market.

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

The city or region the search is run for. Rankings differ a lot between Russian cities, so pick the market you actually sell into. Every row also records the region the result was answered for.

## `maxResultsPerQuery` (type: `integer`):

How deep to go in the ranked results for each search term. The source ranks about 250 positions for any one search, so anything above that returns what it makes available. It also repeats some addresses across its own result pages and those are reported once, so a search taken to full depth usually yields around 200 rows. Related searches and the answer block are read from the first result page and come back in addition to this depth, not out of it.

## `resultTypes` (type: `array`):

Organic results are the ranked listings. Related searches are the suggestions printed under the results, and the answer block is the direct answer the source sometimes prints above them. Both are reported once per search term, from the first result page this run reads that carries them, and neither costs an extra page read — a run that asks for those alone reads one page per search term.

## `parallelSearches` (type: `integer`):

How many search terms to work through at the same time. Higher is faster on large jobs; leave it as it is unless a run is slower than you need.

## Actor input object example

```json
{
  "queries": [
    "купить ноутбук",
    "ремонт квартир под ключ"
  ],
  "region": "213",
  "maxResultsPerQuery": 20,
  "resultTypes": [
    "organic"
  ],
  "parallelSearches": 3
}
```

# Actor output Schema

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

Every result collected in this run.

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

The same results as a table, in the order the source ranked them.

## `spreadsheet` (type: `string`):

The results as a spreadsheet file.

## `runSummary` (type: `string`):

How many searches produced results, how many genuinely found nothing, and how many could not be completed.

# 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",
    "maxResultsPerQuery": 20,
    "resultTypes": [
        "organic"
    ],
    "parallelSearches": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("apt_marble/yandex-search-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": [
        "купить ноутбук",
        "доставка цветов",
    ],
    "region": "213",
    "maxResultsPerQuery": 20,
    "resultTypes": ["organic"],
    "parallelSearches": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("apt_marble/yandex-search-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": [
    "купить ноутбук",
    "доставка цветов"
  ],
  "region": "213",
  "maxResultsPerQuery": 20,
  "resultTypes": [
    "organic"
  ],
  "parallelSearches": 3
}' |
apify call apt_marble/yandex-search-scraper --silent --output-dataset

```

## MCP server setup

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