Yandex Search Scraper - Web, Images, Videos & SEO Rankings avatar

Yandex Search Scraper - Web, Images, Videos & SEO Rankings

Pricing

from $1.00 / 1,000 serp results

Go to Apify Store
Yandex Search Scraper - Web, Images, Videos & SEO Rankings

Yandex Search Scraper - Web, Images, Videos & SEO Rankings

Scrape Yandex web, image and video search results with URLs, snippets and organic rankings for SEO and competitor analysis. Парсер Яндекс Поиска, картинок и видео: ссылки, сниппеты и позиции для SEO, мониторинга выдачи и анализа конкурентов.

Pricing

from $1.00 / 1,000 serp results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

2

Bookmarked

4

Total users

2

Monthly active users

16 days ago

Last modified

Categories

Features

Limited permissions

Share

Yandex Search SERP Scraper

Scrape organic Yandex Search results for any list of queries, across web, image, and video search. Every result comes back as clean, structured JSON with its title, URL, domain, and a continuous position across the fetched pages of the query walk, ready for rank tracking, SEO monitoring, and competitor research. Ads and vertical inserts (news, image, and video carousels shown on a web SERP) are left out of the organic rows by default, so every emitted position reflects the organic rank within the walk (the full result list when you start at page 1). Export the dataset as JSON, CSV, or Excel, or pull it straight into your app through the API.

Why This Scraper?

  • Organic results by default. Ads, the knowledge panel and inline image or video strips are left out of the organic rows, so positions are genuine organic ranks. Three opt-in switches (includeAds, includeKnowledgeGraph, includeInlineMedia, all off) return those blocks as separate rows with kind set, never numbered. Yandex serves those blocks only for some queries, regions and exits, so a run can return none of them; the knowledge panel is best effort.
  • Continuous position tracking. Every result carries its query, 1-based SERP page, and a running 1-based position across the whole query walk, not just the current page. When you set startPage above 1, page stays the real SERP page but position counts from 1 at the first page you fetched, so it is the rank inside your window rather than the absolute rank.
  • Three verticals from one input. Pick web, images, or videos with searchType. Media rows add their own thumbnail, duration, view count, and embed fields.
  • Pagination that knows when to stop. The walk keeps requesting pages until maxPages is reached or a page returns no new organic results.
  • A hard run-wide cap. maxItems bounds total emitted results across every query, so run size and cost stay predictable. It defaults to 100000, the maximum, which is effectively uncapped; set a lower value to cap a run. A run that stops at the cap skips EXPIRED detection in incremental mode.
  • Built for monitoring. Incremental mode returns only new and changed results on repeated runs, and resumeFromRunId skips results an earlier run already collected (see the resume notes below for its limits).
  • Loud failures, not silent gaps. A search that is fully refused fails the run with a clear message instead of quietly returning an empty dataset.

Use Cases

  • SEO and rank tracking: monitor organic positions for target keywords over time, using incremental mode to see only what moved.
  • Competitor and SERP research: see which domains and pages currently rank for a query, with breadcrumbs and snippets included.
  • Content and media discovery: pull the current top videos or images for a topic, with thumbnails, durations, and view counts.
  • Brand monitoring: track how a brand or product name surfaces in Yandex search results.
  • Data science and NLP datasets: build structured, position-tagged corpora of titles and snippets for downstream analysis.

Data You Get

Sample shape: values are illustrative placeholders, not from a live SERP.

FieldExample
query"wireless noise cancelling headphones"
page1
position1
title"Sample Audio Shop - Noise Cancelling Headphones"
url"https://www.example-audio-shop.com/noise-cancelling-headphones"
domain"example-audio-shop.com"
breadcrumb"example-audio-shop.com › headphones › noise-cancelling" (null when the SERP served none)
snippet"Compare top noise cancelling headphones in stock at Sample Audio Shop..." (null when the SERP served none)
changeType"NEW" (incremental mode only: NEW, UPDATED, UNCHANGED, or EXPIRED; absent when incremental mode is off)
changedFields["content"] (incremental mode only, populated on UPDATED rows)
firstSeenAt"2026-01-01T00:00:00.000Z" (incremental mode only)
lastSeenAt"2026-03-01T00:00:00.000Z" (incremental mode only)
kindabsent for web rows, "video" or "image" for media rows; "ad", "knowledge_graph", "inline_images" or "inline_videos" for the opt-in side rows (web search)
mediaUrls["https://example-cdn.com/thumb1.jpg"] (inline image and video rows)
clickUrlAd rows only: Yandex's own click-tracking link; the advertiser's site is in domain / url
blockPosition3 (ad, knowledge panel and inline media rows: block index on the page; these rows carry no position)
thumbnailUrl"https://example-cdn.com/thumb.jpg" (media rows)
imageUrl"https://example-cdn.com/original.jpg" (image rows)
sourceHost"example-video-host.com" (video rows)
embedUrl"https://example-video-host.com/embed/sample123" (video rows)
durationSeconds245 (video rows)
durationText"4:05" (video rows, as displayed)
views"12K" (video rows, as displayed)
publishedDate"3 months ago" (video rows, as displayed)

Image and video rows share the same shape as web rows (query, page, position, title, url, domain) plus their own media fields; the web-only breadcrumb and snippet fields are not populated for media rows. EXPIRED rows (incremental mode with emitExpired) are slim tombstones carrying only recordId, url, changeType, and lastSeenAt, where lastSeenAt is the time of the run that marked them expired.

How to Use

  1. Enter one or more search queries.
  2. Pick a search type, web, images, or videos, and set Max pages per query if you need more than the first page.
  3. Set Max results to cap run size and cost, and adjust Proxy & connection if you need a different proxy.
  4. Start the run, then read the dataset as JSON, CSV, or Excel, or through the API. Views: organic-results (all rows), web, images and videos (one view per search type), and changes (incremental changeType, changedFields and timestamps).

Search two queries on the web vertical, two pages each:

{
"queries": ["wireless noise cancelling headphones", "portable espresso maker"],
"maxPages": 2,
"maxItems": 100
}

Image search:

{
"searchType": "images",
"queries": ["minimalist desk setup"],
"maxItems": 50
}

Video search with a region code:

{
"searchType": "videos",
"queries": ["home workout routine"],
"lr": 213,
"maxPages": 2
}

Recurring monitoring of one query:

{
"queries": ["wireless noise cancelling headphones"],
"incrementalMode": true,
"emitExpired": true,
"stateKey": "headphones-watch"
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/yandex-serp-scraper").call(run_input={"queries": ["wireless noise cancelling headphones"], "maxPages": 2})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["position"], item["title"], item["url"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/yandex-serp-scraper').call({ queries: ['wireless noise cancelling headphones'], maxPages: 2 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets, or webhooks from the Integrations tab.

How Max results interacts with pagination and incremental mode

maxItems (Max results) is a hard cap on rows emitted across the whole run, counted by rows actually pushed to the dataset, not by results merely scanned. On web and video search, each query's own walk stops early once a page returns no new organic results, even before maxPages or maxItems is reached; image search keeps paging past a page of repeats and stops on an empty page.

In incremental mode, a page's share of the remaining cap is taken before unchanged rows are suppressed, so on a capped run some new results further down that page can be skipped even though the cap was not filled. They are not lost: they are returned as NEW on a later run.

Known limitation: when incremental mode's emitExpired is on, maxItems only governs the newly collected NEW / UPDATED / UNCHANGED rows. The EXPIRED batch (previously tracked results this run's queries no longer found) is pushed as a separate step that is not counted against maxItems. If your tracked scope holds far more previously-seen results than this run's queries still match, a tightly capped run can still emit, and be billed for, far more rows than maxItems once the EXPIRED batch is added. Leave emitExpired off on tightly capped runs, or budget for it separately from maxItems.

Resume and recurring updates

  • Resume (resumeFromRunId): paste a previous run ID or dataset ID to continue an interrupted pull. Every query is searched again from page 1, and results whose URL was already collected there are skipped, never re-emitted. Cannot be combined with incremental mode.
  • Incremental mode (incrementalMode): for daily or recurring monitoring of the same search. The first run returns everything as NEW; later runs return only NEW and UPDATED rows, with changeType, changedFields, firstSeenAt, and lastSeenAt on every returned result row. A pure rank move alone is not a content change (position and page are excluded from the fingerprint), so a result that only shifted rank classifies UNCHANGED. UNCHANGED rows are suppressed unless emitUnchanged is on. EXPIRED rows are only produced after a run that fully scanned every query and page in scope, and only when emitExpired is on. State is keyed per search scope, or per your own stateKey, in a named key-value store. Compared fields are title, snippet and domain (the URL is the record identity); position, page, media and counter fields are never compared. Use ignoreFieldsForChanges to leave any of the compared fields out of change detection: tracked results are re-checked against the stored per-field snapshot with the current list, so changing it causes no one-time wave of UPDATED rows (results saved by older runs have no per-field snapshot and are compared on all fields once).

Known limitation: resumeFromRunId's dedup set is built from every URL in the resumed dataset, without regard to which query originally returned it. If two different queries in your list can legitimately return the same URL (common for closely related terms), and that URL was already collected under one query in the resumed run, this run silently skips it under every query, including a query that never actually returned it before.

Known limitation: on web and video search, a page where every result was already collected ends that query's walk, just like a page with no new results. So a resume does not reach later pages of a query whose first page was fully collected before the interruption: a maxPages: 3 query interrupted after page 1 returns nothing new on resume. The same applies across queries: if a query's first page consists only of URLs another query already collected, its later pages are never requested. Positions on resumed rows are numbered from 1 over the newly returned results only, so they do not continue the earlier run's numbering. If you need complete, correctly ranked results for a query, run it again fresh (without resumeFromRunId), one query at a time if queries overlap.

Send results into your apps (MCP connectors)

Optionally send a condensed summary of the results to apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

  1. Authorize a connector once under Apify > Settings > Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the mcpConnectors input field.
  3. For Notion, also set notionParentPageUrl to the page where items should be created.
  4. maxNotifyListings caps how many results are sent to each connector per run.

The connection goes through Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
searchTypestringwebWhich Yandex vertical to search: web, images, or videos. Images and videos return media fields like thumbnails and durations.
queriesarraysample queryOne SERP walk per query. Each query gets a fresh proxy session. Required.
maxPagesinteger0SERP pages per query; 0 or empty means 1 page, with a hard cap of 30 pages per query. Stops early when a page returns no new results.
lrinteger(none)Yandex region code for the SERP locale, for example 213 (Moscow), 2 (Saint Petersburg), 21265 (San Francisco). Leave empty for auto-detection.
domainstringyandex.comyandex.com or yandex.ru. Images always run on yandex.com.
startPageinteger1First SERP page to fetch; with Max pages per query it selects a page window.
langstring(any)Two-letter result language, for example en or ru (web search).
periodstringallFreshness window: day, two_weeks or month (web search only).
sortBystringrelevancedate sorts web results newest first.
imageTypestring(any)Image search: photo, clipart, lineart, demotivator or face.
imageColorstring(any)Image search: color, gray, or one color such as red or blue.
imageOrientationstring(any)Image search: horizontal, vertical or square.
imageFileTypestring(any)Image search: jpg, png or gifan.
imageWidthinteger(none)Image search: exact width in pixels; applies only together with imageHeight.
imageHeightinteger(none)Image search: exact height in pixels; applies only together with imageWidth.
imageSitestring(any)Image search: only images hosted on this site, for example example.com.
includeAdsbooleanfalseWeb search: also return sponsored results as separate rows with kind ad; never numbered. Each row counts toward Max results and is billed like any result row. With Incremental mode on, these rows are not tracked: they are re-sent and billed on every run, even when unchanged. The advertiser site is in domain and url; Yandex's own tracking link is in clickUrl.
includeKnowledgeGraphbooleanfalseWeb search: also return the knowledge panel (when Yandex shows one) as a row with kind knowledge_graph. Counts toward Max results and is billed like any result row. With Incremental mode on, these rows are not tracked: they are re-sent and billed on every run, even when unchanged.
includeInlineMediabooleanfalseWeb search: also return inline image and video strips as rows with kind inline_images or inline_videos. Counts toward Max results and is billed like any result row. With Incremental mode on, these rows are not tracked: they are re-sent and billed on every run, even when unchanged.
maxItemsinteger100000Hard cap on emitted dataset items across the whole run. The default is also the maximum (100000), so a run you do not cap yourself is effectively uncapped. In incremental mode a run that stops at this cap skips EXPIRED detection. Very large runs need a long run timeout, each query holds one browser session.
proxySettingsobjectApify residentialProxy configuration. Residential is the default and returns the fullest result pages; it needs a paid Apify plan (see Plan Requirement), or enter your own proxy URLs.
resumeFromRunIdstring(none)Paste a previous run ID or dataset ID to continue an interrupted pull without returning results already collected there. Cannot be combined with incremental mode.
mcpConnectorsarray(none)Optional. Send a condensed summary of the results to apps you authorized under Apify Settings, Integrations, via Model Context Protocol (MCP) connectors.
notionParentPageUrlstring(none)Notion connector only: URL or id of the page under which result pages are created.
maxNotifyListingsinteger50Maximum results sent to each connector per run. Does not affect the dataset.
ignoreFieldsForChangesarray(none)Incremental mode only, last option of the Resume & recurring updates section. Title: Ignore fields when detecting changes (incremental mode only). Supported values: title, snippet, domain.
incrementalModebooleanfalseTurn this on for daily or recurring monitoring. The first run returns every matching result as NEW. Later runs normally return only NEW and UPDATED results. A pure rank move alone is not a content change. Cannot be combined with resumeFromRunId.
stateKeystring(none)Optional. Name this monitoring campaign to keep its state stable, or deliberately share state across differently configured runs. Leave empty to derive a key automatically from the search settings.
emitUnchangedbooleanfalseOff by default. Turn on to also return records that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have.
emitExpiredbooleanfalseOff by default. Turn on to also return records that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search.

Each row also carries searchedAt, servedDomain, and on web rows servedLr and, when Yandex shows one, totalResultsFound. These add no extra billed rows.

Output Example

Sample shape: values are illustrative placeholders, not from a live SERP.

{
"query": "wireless noise cancelling headphones",
"page": 1,
"position": 1,
"title": "Sample Audio Shop - Noise Cancelling Headphones",
"url": "https://www.example-audio-shop.com/noise-cancelling-headphones",
"domain": "example-audio-shop.com",
"breadcrumb": "example-audio-shop.com › headphones › noise-cancelling",
"snippet": "Compare top noise cancelling headphones in stock at Sample Audio Shop..."
}

Plan Requirement

Yandex refuses plain, unproxied requests with a captcha redirect, so this actor needs a proxy connection. The default connection uses Apify residential proxy. Apify free plans do not include residential proxies (or any Apify proxy): on a free plan the run logs "The selected connection is unavailable to this run. Apify free plans do not include residential proxies." and continues on a backup connection, noting "Served over the backup connection" when it is used; some pages may still be unavailable. If that backup cannot load the pages the run stops with "No results: residential proxies are unavailable on this run ... Upgrade at https://apify.com/pricing or supply your own proxy URLs". If your account's proxy access is refused outright the run stops with "The proxy connection was refused for this account ... a paid plan is required". For reliable results use a paid Apify plan, or enter your own proxy URLs in Proxy & connection. This actor charges per event: a fixed run-start charge plus one charge per dataset row returned: every row counts as one result, whether it is an organic, image or video row, an opt-in ad, knowledge panel or inline media row, or an UNCHANGED / EXPIRED row when you turn those on. The Pricing tab shows current rates. Occasional automated verification checks are resolved by the actor itself and are never billed to you as a separate Apify event; see the FAQ below for how that affects a run that fails instead of returning results.

FAQ

How much does it cost?

You pay a run-start charge plus one charge per dataset row returned: organic, image and video rows, the opt-in ad, knowledge panel and inline media rows, and UNCHANGED / EXPIRED rows when you turn those on. The Pricing tab shows the current rates. Use Max results to cap the cost of any run.

This actor collects only publicly available search result data. You are responsible for how you use it: follow Yandex's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Search snippets and thumbnails may reflect third-party content and rights.

Can I get only new or changed results on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated results, and unchanged ones are not billed unless you also turn on Emit unchanged.

Why did my run fail instead of returning an empty dataset?

If a search is refused on every attempt, the run stops with a clear message so "no results for this query" is never confused with "nothing could be read." Run it again in a few minutes. A run can also stop if the cost of resolving automated verification checks would exceed a fixed ceiling relative to the run's size, a sign that the connection is being refused unusually hard; retrying, often with a different proxy country, usually clears it.

Why does an incremental run with Emit expired sometimes return far more rows than Max results?

emitExpired pushes every previously tracked result your queries no longer found, and that batch is not capped by maxItems. On a scope with a large tracked history, this can push and bill well beyond your maxItems setting in a single run. Leave emitExpired off for tightly capped runs, or expect it to add rows outside that cap.

Why is a shared result missing from one of my queries after a resume?

resumeFromRunId skips any URL already present anywhere in the resumed dataset, regardless of which query returned it. If two queries can legitimately share a result, the second query's copy is silently skipped when it was already collected under the first, and if that query's whole first page was already collected, its later pages are not requested at all. Resume is most useful for queries the interrupted run never reached, and even those can lose results shared with other queries; for a query's complete, correctly ranked result set, run it fresh without resumeFromRunId.

Can I use it with AI agents or automation tools?

Yes. Call it from any Apify integration, the API, or an MCP-compatible client, and route the results into your own pipeline or app.

🔗 Want more Yandex data?

Pair this actor with these related scrapers from the same team:

🧩 Yandex Maps Scraper
Scrape Yandex Maps businesses and places by keyword or URL for lead generation, research...
🤖 AI Search Tool
Give your AI agents real-world knowledge. This Actor provides high-quality web, news...
🧩 WEBTOON Scraper
Scrape the WEBTOON catalog into structured data. Extract series, genres, rankings and...
🧩 Dzen.ru Scraper
Scrape Dzen.ru (ex Yandex.Zen): articles, videos and channels. Full article text with...
🧩 ShortMax Scraper
Scrape the ShortMax short-drama catalog: titles, descriptions, creators, view and follow...
🤖 Web Scraper For Llms
Stealth web scraping engine built for LLMs. Converts any web page to clean markdown or...

👉 Browse all abotapi scrapers

💬 Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.