# Yandex SERP Scraper - Organic Results & Ads (`santhej/yandex-serp-scraper`) Actor

Scrape Yandex search results by keyword. Extract organic positions, titles, URLs, domains and snippets with region targeting. Export JSON/CSV.

- **URL**: https://apify.com/santhej/yandex-serp-scraper.md
- **Developed by:** [Santhej Kallada](https://apify.com/santhej) (community)
- **Categories:** SEO tools
- **Stats:** 5 total users, 4 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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 SERP Scraper — Organic Results, Ads & Snippets

Scrape Yandex search results at scale without an API key or captcha handling. Give this Yandex SERP scraper a keyword and it returns every result as a clean row: organic position, title, URL, display domain and snippet — with paid results separated out.

Built for SEO rank tracking, competitor monitoring and market research in **Russia, Turkey, Kazakhstan and the wider CIS**, where Yandex holds a share Google does not.

**$4.00 per 1,000 results** — a full page of 10 organic results costs about **$0.04**.

### Features

- **Scrape Yandex organic search results** — position, title, URL, domain, snippet
- **Track Yandex keyword rankings** — positions numbered in page order for rank monitoring
- **Scrape Yandex ads separately** — paid placements parsed and flagged, returned only if you ask
- **Target a Yandex region** — Moscow, St Petersburg, Istanbul, Almaty and every other `lr` region ID
- **Set the Yandex interface language** — Russian, English, Turkish and more
- **Scrape Yandex results for one domain** — `site:` filtering built in
- **Filter Yandex results by recency** — only results from the last N days
- **Scrape multiple keywords in one run** — up to 50 per run, processed concurrently
- **Export Yandex SERP data to JSON, CSV or Excel** — or pull it from the API

### What you get

Every row includes:

| Field | Description |
|---|---|
| `position` | Rank within the results, numbered from 1 |
| `title` | Result title, reassembled from Yandex's highlighted fragments |
| `url` | Destination URL |
| `displayUrl` | Domain as Yandex displays it |
| `snippet` | Description text shown under the result |
| `isAd` | Whether the result is a paid placement |
| `searchQuery` | The keyword that produced it |
| `sourcePage` | Which SERP page it came from |
| `scrapedAt` | Timestamp |

### Use cases

**Yandex rank tracking.** Monitor where your domain sits for a keyword set in a specific Yandex region, on whatever schedule you choose. `position` and `displayUrl` are all a rank tracker needs.

**Competitor visibility.** See which domains hold the top positions for your commercial keywords, and how that changes over time.

**Keyword and content research.** Snippets show what Yandex considers relevant for a query — useful input for content briefs targeting the RU/TR/KZ market.

**Ad intelligence.** Turn on `includeAds` to see who is bidding on your keywords and what their ad copy says.

**Market entry research.** Yandex is the dominant engine in several markets where Google data tells you very little. This is the equivalent dataset for those markets.

### Input

```json
{
  "queries": ["running shoes", "купить кроссовки"],
  "maxResults": 30,
  "includeAds": false,
  "region": 213,
  "language": "ru",
  "site": "example.com",
  "withinDays": 7
}
```

| Option | Description |
|---|---|
| `queries` | Search keywords, one or more (up to 50 per run) |
| `maxResults` | Organic results per keyword. Yandex serves ~10 per page, so 30 fetches about 3 pages |
| `includeAds` | Also return paid results. Ads are billed like organic results |
| `region` | Yandex region ID (`lr`), e.g. `213` Moscow, `2` St Petersburg, `84` USA, `983` Istanbul |
| `language` | Interface language: `ru`, `en`, `tr`, … |
| `site` | Restrict to one domain — applied as a `site:` operator |
| `withinDays` | Only results published in the last N days |
| `pageConcurrency` | Pages fetched in parallel per keyword |
| `country` | Exit country. **Leave this empty** unless you have a specific reason — see below |

### Output example

```json
{
  "position": 1,
  "title": "1,000+ shoes reviewed and cut in half",
  "url": "https://runrepeat.com/",
  "displayUrl": "runrepeat.com",
  "snippet": "Independent running shoe reviews with lab testing…",
  "isAd": false,
  "searchQuery": "running shoes",
  "sourcePage": 1
}
```

### Notes worth reading

- **Yandex returns about 10 organic results per page.** `maxResults: 30` therefore fetches roughly three pages. Setting it very high returns everything available rather than erroring.
- **Ads are not billed unless you want them.** A typical Yandex page carries around as many paid placements as organic results. They are parsed either way but only returned — and charged — when `includeAds` is on.
- **Blocked and captcha pages are never billed.** If Yandex challenges a request it is retried, and if it still fails the page is skipped and reported in `blocked_pages`.
- **Leave `country` empty.** This is counter-intuitive but measured: pinning an exit country makes Yandex *less* reliable, not more, and returns fewer results. The default is deliberately unset.
- **Region targeting is done with `region`, not `country`.** Yandex's own `lr` parameter is what controls which market's results you get.

### Pricing

| Event | Price |
|---|---|
| Result returned | **$0.004** ($4.00 per 1,000) |
| Zero-result keyword | $0.002 |
| Actor start | $0.0005 |

A full page of 10 organic results costs about **$0.04**. Flat across every Apify plan — no tier gating and no subscription.

### FAQ

**Do I need a Yandex API key or XML quota?**
No. Yandex's official XML API requires registration and imposes quotas; this needs neither.

**Can I track rankings for a specific city?**
Yes — set `region` to the Yandex `lr` ID for that city. Moscow is `213`, St Petersburg is `2`, Istanbul is `983`.

**Does it handle Yandex captchas?**
Yes. Challenged requests are retried automatically, and any page that still fails is skipped without charge.

**Can I scrape Yandex in Russian?**
Yes — pass Cyrillic keywords directly and set `language` to `ru`.

**How do I separate ads from organic results?**
They are separated for you. Organic results come back with `isAd: false`; ads only appear when `includeAds` is enabled.

**Can I run this on a schedule?**
Yes — use Apify's scheduler for daily or weekly rank tracking, or trigger it from your own pipeline via API.

**Why is `country` empty by default?**
Because testing across domains and exit countries showed unpinned requests succeed more often and return more results. Pinning `us` in particular halved the result count.

### Support

Open an issue on the Actor's Issues tab and I'll take a look.

# Actor input Schema

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

What to search on Yandex. One per line. Up to 50 per run.

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

Yandex returns ~10 organic results per page, so 30 fetches about 3 pages.

## `includeAds` (type: `boolean`):

Also return paid results. Ads are billed the same as organic results.

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

e.g. 213 Moscow, 2 St Petersburg, 84 USA, 983 Istanbul. Leave empty for auto.

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

Interface language, e.g. 'en', 'ru', 'tr'.

## `site` (type: `string`):

Only results from this domain, e.g. example.com. Applied as a site: operator.

## `withinDays` (type: `integer`):

Recency window. Leave empty for all time.

## `concurrency` (type: `integer`):

Keywords processed at once.

## `pageConcurrency` (type: `integer`):

Pages fetched in parallel within one keyword. Higher is substantially faster.

## `country` (type: `string`):

Leave EMPTY unless you have a reason. Measured: pinning a country makes Yandex less reliable, not more.

## Actor input object example

```json
{
  "queries": [
    "running shoes"
  ],
  "maxResults": 30,
  "includeAds": false,
  "concurrency": 3,
  "pageConcurrency": 5,
  "country": ""
}
```

# Actor output Schema

## `dataset` (type: `string`):

All scraped Yandex results.

## `summary` (type: `string`):

Queries, result counts and pages fetched.

# 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": [
        "running shoes"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("santhej/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": ["running shoes"] }

# Run the Actor and wait for it to finish
run = client.actor("santhej/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": [
    "running shoes"
  ]
}' |
apify call santhej/yandex-serp-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,santhej/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/bAcu5NXiGpBQ3136e/builds/6TsbHugCTNNmgOutg/openapi.json
