Yandex Search API: How to Track Rankings in Russia and CIS Markets

Learn how to use a Yandex Search API to track keyword rankings in Russia and CIS-focused markets. Use Python to collect localized SERP data by city, country, language, and device, then export ranking results to CSV.

talor ai
最后更新于
10 分钟阅读

Quick answer: A Yandex Search API helps SEO teams collect Yandex search results programmatically, track keyword rankings by city, country, language, and device, and export the results for reporting. This is useful when your SEO work targets Russia or CIS-focused markets where Yandex visibility matters.

If your SEO reporting only tracks Google, you may miss an important part of search visibility in Russia and nearby Russian-speaking or CIS-focused markets.

Yandex rankings can differ from Google rankings. A page that performs well on Google may not have the same visibility on Yandex. For SEO teams, agencies, marketplaces, and international brands, that means Yandex should be tracked as a separate search channel.

A SERP API makes this easier. Instead of manually checking Yandex results from different locations, you can send structured requests and receive search results in a format your system can store and analyze.

What We Will Build

We will create a Python workflow:

Keyword list
→ Market and language list
→ Yandex SERP API request
→ Extract organic results
→ Find target domain ranking
→ Export ranking data to CSV

The final CSV can include:

Field

Meaning

keyword

Search query

market

Target market label

location

City or region

country

Target country or market

language

Search language

device

Desktop or mobile

position

Ranking position of the target domain

matched_url

Ranking URL

matched_title

Ranking page title

top_domains

Top-ranking domains

collected_at

Collection timestamp

This setup is useful for Yandex SEO reporting, competitor monitoring, Russian-language SEO, cross-market visibility checks, and recurring rank tracking.

Why Track Yandex Rankings Separately?

Yandex should not be treated as a copy of Google.

When tracking Russia and CIS-focused SEO campaigns, you may need to compare:

Dimension

Why it matters

City

Rankings may vary by local market

Language

Russian and local-language queries can return different results

Device

Mobile and desktop layouts may differ

Keyword wording

Translated keywords may not match real user phrasing

Competitors

Local competitors may be more visible on Yandex than on Google

For example, these two queries may need separate tracking:

купить ноутбук
buy laptop

They may describe the same product category, but they represent different user behavior, language intent, and SERP competition.

Step 1: Set Environment Variables

Do not hardcode your API key.

export TALORDATA_API_KEY="your_api_key_here"
export TALORDATA_SERP_ENDPOINT="your_talordata_serp_endpoint_here"

On Windows PowerShell:

$env:TALORDATA_API_KEY="your_api_key_here"
$env:TALORDATA_SERP_ENDPOINT="your_talordata_serp_endpoint_here"

Install the Python package:

pip install requests

View detailed API documentation>>

Step 2: Define Keywords and Target Markets

Start with a small test set.

KEYWORDS = [
    "купить ноутбук",
    "доставка цветов",
    "онлайн курсы английского",
]

MARKETS = [
    {
        "market": "Russia - Moscow",
        "location": "Moscow, Russia",
        "country": "ru",
        "language": "ru",
    },
    {
        "market": "Kazakhstan - Almaty",
        "location": "Almaty, Kazakhstan",
        "country": "kz",
        "language": "ru",
    },
    {
        "market": "Belarus - Minsk",
        "location": "Minsk, Belarus",
        "country": "by",
        "language": "ru",
    },
]

TARGET_DOMAIN = "example.com"
DEVICE = "desktop"

For production tracking, use real keyword groups, target locations, and language settings based on your SEO strategy.

Step 3: Create a SERP API Request Helper

Keep the request layer separate from parsing logic.

import os
import requests


def require_env(name):
    value = os.getenv(name)
    if not value:
        raise RuntimeError(f"Missing required environment variable: {name}")
    return value


TALORDATA_API_KEY = require_env("TALORDATA_API_KEY")
TALORDATA_SERP_ENDPOINT = require_env("TALORDATA_SERP_ENDPOINT")


def call_serp_api(payload):
    headers = {
        "Authorization": f"Bearer {TALORDATA_API_KEY}",
        "Content-Type": "application/json",
    }

    response = requests.post(
        TALORDATA_SERP_ENDPOINT,
        json=payload,
        headers=headers,
        timeout=30,
    )

    response.raise_for_status()
    return response.json()

Some API setups use GET instead of POST, or pass the API key as a query parameter. If your account works differently, update only this helper.

Step 4: Fetch Yandex SERP Results

Now create a function for localized Yandex search requests.

def fetch_yandex_serp(keyword, location, country, language, device="desktop"):
    payload = {
        "engine": "yandex",
        "q": keyword,
        "location": location,
        "gl": country,
        "hl": language,
        "device": device,
        "num": 10,
        "output": "json",
    }

    return call_serp_api(payload)

The exact parameter names may depend on your SERP API setup. The important idea is to keep keyword, location, country, language, and device explicit in each request.

Step 5: Extract Organic Results

SERP API responses may use different field names, so keep the parser flexible.

from urllib.parse import urlparse


def clean_text(value):
    if not value:
        return ""
    return " ".join(str(value).split())


def get_domain(url):
    if not url:
        return ""

    parsed = urlparse(url)
    return parsed.netloc.replace("www.", "")


def get_organic_results(serp_json):
    return (
        serp_json.get("organic_results")
        or serp_json.get("organic")
        or serp_json.get("results")
        or []
    )


def normalize_organic_results(serp_json):
    results = get_organic_results(serp_json)
    rows = []

    for index, item in enumerate(results, start=1):
        url = item.get("link") or item.get("url") or ""

        rows.append({
            "position": item.get("position") or item.get("rank") or index,
            "title": clean_text(item.get("title")),
            "url": url,
            "domain": get_domain(url),
            "snippet": clean_text(item.get("snippet") or item.get("description")),
        })

    return rows

This gives you a clean ranking list for each keyword and market.

Step 6: Find the Target Domain Ranking

Check whether your target domain appears in the top results.

def find_domain_ranking(results, target_domain):
    target = target_domain.replace("www.", "").lower()

    for item in results:
        domain = item["domain"].lower()

        if domain == target or domain.endswith("." + target):
            return {
                "position": item["position"],
                "matched_url": item["url"],
                "matched_title": item["title"],
            }

    return {
        "position": None,
        "matched_url": "",
        "matched_title": "",
    }


def summarize_top_domains(results, limit=10):
    domains = []

    for item in results[:limit]:
        if item["domain"]:
            domains.append(item["domain"])

    return " | ".join(domains)

If the target domain is not found, keep the position as None. That makes reports more honest than forcing a fake ranking value.

Step 7: Export Yandex Ranking Data to CSV

import csv
from datetime import datetime, timezone


CSV_COLUMNS = [
    "keyword",
    "market",
    "location",
    "country",
    "language",
    "device",
    "target_domain",
    "position",
    "matched_url",
    "matched_title",
    "top_domains",
    "collected_at",
]


def export_to_csv(rows, filename="yandex_rankings.csv"):
    if not rows:
        print("No ranking rows found.")
        return

    with open(filename, mode="w", newline="", encoding="utf-8") as file:
        writer = csv.DictWriter(file, fieldnames=CSV_COLUMNS)
        writer.writeheader()
        writer.writerows(rows)

    print(f"Exported {len(rows)} ranking rows to {filename}")

Complete Python Example

import os
import csv
import requests

from datetime import datetime, timezone
from urllib.parse import urlparse


KEYWORDS = [
    "купить ноутбук",
    "доставка цветов",
    "онлайн курсы английского",
]

MARKETS = [
    {
        "market": "Russia - Moscow",
        "location": "Moscow, Russia",
        "country": "ru",
        "language": "ru",
    },
    {
        "market": "Kazakhstan - Almaty",
        "location": "Almaty, Kazakhstan",
        "country": "kz",
        "language": "ru",
    },
    {
        "market": "Belarus - Minsk",
        "location": "Minsk, Belarus",
        "country": "by",
        "language": "ru",
    },
]

TARGET_DOMAIN = "example.com"
DEVICE = "desktop"

CSV_COLUMNS = [
    "keyword",
    "market",
    "location",
    "country",
    "language",
    "device",
    "target_domain",
    "position",
    "matched_url",
    "matched_title",
    "top_domains",
    "collected_at",
]


def require_env(name):
    value = os.getenv(name)
    if not value:
        raise RuntimeError(f"Missing required environment variable: {name}")
    return value


TALORDATA_API_KEY = require_env("TALORDATA_API_KEY")
TALORDATA_SERP_ENDPOINT = require_env("TALORDATA_SERP_ENDPOINT")


def call_serp_api(payload):
    headers = {
        "Authorization": f"Bearer {TALORDATA_API_KEY}",
        "Content-Type": "application/json",
    }

    response = requests.post(
        TALORDATA_SERP_ENDPOINT,
        json=payload,
        headers=headers,
        timeout=30,
    )

    response.raise_for_status()
    return response.json()


def fetch_yandex_serp(keyword, location, country, language, device="desktop"):
    payload = {
        "engine": "yandex",
        "q": keyword,
        "location": location,
        "gl": country,
        "hl": language,
        "device": device,
        "num": 10,
        "output": "json",
    }

    return call_serp_api(payload)


def clean_text(value):
    if not value:
        return ""
    return " ".join(str(value).split())


def get_domain(url):
    if not url:
        return ""

    parsed = urlparse(url)
    return parsed.netloc.replace("www.", "")


def get_organic_results(serp_json):
    return (
        serp_json.get("organic_results")
        or serp_json.get("organic")
        or serp_json.get("results")
        or []
    )


def normalize_organic_results(serp_json):
    results = get_organic_results(serp_json)
    rows = []

    for index, item in enumerate(results, start=1):
        url = item.get("link") or item.get("url") or ""

        rows.append({
            "position": item.get("position") or item.get("rank") or index,
            "title": clean_text(item.get("title")),
            "url": url,
            "domain": get_domain(url),
            "snippet": clean_text(item.get("snippet") or item.get("description")),
        })

    return rows


def find_domain_ranking(results, target_domain):
    target = target_domain.replace("www.", "").lower()

    for item in results:
        domain = item["domain"].lower()

        if domain == target or domain.endswith("." + target):
            return {
                "position": item["position"],
                "matched_url": item["url"],
                "matched_title": item["title"],
            }

    return {
        "position": None,
        "matched_url": "",
        "matched_title": "",
    }


def summarize_top_domains(results, limit=10):
    domains = []

    for item in results[:limit]:
        if item["domain"]:
            domains.append(item["domain"])

    return " | ".join(domains)


def export_to_csv(rows, filename="yandex_rankings.csv"):
    if not rows:
        print("No ranking rows found.")
        return

    with open(filename, mode="w", newline="", encoding="utf-8") as file:
        writer = csv.DictWriter(file, fieldnames=CSV_COLUMNS)
        writer.writeheader()
        writer.writerows(rows)

    print(f"Exported {len(rows)} ranking rows to {filename}")


if __name__ == "__main__":
    collected_at = datetime.now(timezone.utc).isoformat()
    output_rows = []

    for keyword in KEYWORDS:
        for market in MARKETS:
            serp_json = fetch_yandex_serp(
                keyword=keyword,
                location=market["location"],
                country=market["country"],
                language=market["language"],
                device=DEVICE,
            )

            organic_results = normalize_organic_results(serp_json)
            ranking = find_domain_ranking(organic_results, TARGET_DOMAIN)

            output_rows.append({
                "keyword": keyword,
                "market": market["market"],
                "location": market["location"],
                "country": market["country"],
                "language": market["language"],
                "device": DEVICE,
                "target_domain": TARGET_DOMAIN,
                "position": ranking["position"],
                "matched_url": ranking["matched_url"],
                "matched_title": ranking["matched_title"],
                "top_domains": summarize_top_domains(organic_results),
                "collected_at": collected_at,
            })

    export_to_csv(output_rows)

After running the script, you should get:

yandex_rankings.csv

Example Output

keyword,market,location,country,language,device,target_domain,position,matched_url,matched_title,top_domains,collected_at
купить ноутбук,Russia - Moscow,"Moscow, Russia",ru,ru,desktop,example.com,4,https://example.com/laptops,Example Laptop Store,domain1.ru | domain2.ru | example.com,2026-06-22T00:00:00Z
доставка цветов,Kazakhstan - Almaty,"Almaty, Kazakhstan",kz,ru,desktop,example.com,,,,domain3.kz | domain4.kz | domain5.kz,2026-06-22T00:00:00Z

How to Use the Output

For Yandex SEO reporting, group the CSV by:

Grouping

What it shows

Keyword

Which queries have visibility

Market

Where rankings are strong or weak

Language

Whether Russian or local-language pages are visible

Device

Whether desktop and mobile differ

Top domains

Which competitors appear most often

For example:

Keyword: доставка цветов
Moscow: position 5
Almaty: not found
Minsk: position 9

This tells you where to improve localized landing pages, Russian-language content, internal links, product pages, or regional relevance.

Best Practices

Track Yandex separately from Google. Do not assume one search engine’s ranking equals another’s.

Use real local keyword phrasing. Direct translation may not match how users search.

Store market, location, language, country, and device in every row. Ranking data without context is hard to analyze.

Keep raw API responses during development. They help you debug missing fields and SERP layout changes.

Separate organic results, ads, local results, and special SERP features. Each result type should be labeled clearly.

Move to a database when tracking becomes recurring. CSV is good for testing, but historical dashboards need structured storage.

Test Yandex SERP API for free>>

FAQ

What is a Yandex Search API?

A Yandex Search API lets you collect Yandex search results programmatically. It is useful for SEO rank tracking, competitor monitoring, market research, and localized search analysis.

Why should I track Yandex rankings?

If your audience searches on Yandex, Google-only rank tracking may miss important visibility changes. Yandex rankings should be monitored as a separate channel.

Can I track rankings by city and language?

Yes. A SERP API can send localized requests using city, country, language, and device parameters, depending on the provider’s supported options.

Can I compare Yandex and Google rankings?

Yes. You can run the same keyword list through both search engines and compare ranking positions, top domains, snippets, and landing pages.

Should I store Yandex ranking data in CSV or a database?

CSV works for small tests and reports. For recurring rank tracking, alerts, dashboards, and historical comparison, use a database.

立即开展您的数据业务

加入全球最强大的代理网络

免费试用