Yandex Search Engine Scraper (SERP API)
Pricing
from $3.40 / 1,000 search result returneds
Yandex Search Engine Scraper (SERP API)
The same query put to Yandex from Moscow (lr=213) and from Istanbul (lr=11508) is not the same page. Yandex ranks by region and this pins whichever lr you want, wherever it runs. Rank, title, URL, snippet, sitelinks, result type. No API key. $3.40 per 1,000 plus $0.001 a run.
Pricing
from $3.40 / 1,000 search result returneds
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
2 days ago
Last modified
Categories
Share
The same query put to Yandex from Moscow (lr=213) and from Istanbul (lr=11508) does not come
back as the same page. Yandex ranks by region, and the region is a code in the URL, so you can ask
for any of them from anywhere. Set one and you get that region's ranking, wherever the run happens
to be.
One row per result: rank, title, URL, the domain Yandex displays, the snippet, sitelinks, and whether the slot is an organic listing, a Yandex Direct ad or a featured block.
Yandex runs its own index and ranks it its own way. Russia and Belarus are where most of its traffic comes from, and it holds a real share of search in Kazakhstan, Uzbekistan, Turkey and the Caucasus. The practical point is that a page sitting at rank 3 on Google can sit at rank 20 here, so if you track visibility in those markets, Google-only data isn't the whole picture.
No Yandex account, no API key, no captcha-solving service.
$3.40 per 1,000 results, plus $0.001 to start a run. The per-result rate is the same on a free account as on a paid one, at any volume.
What you get
One row per result:
| Field | Example |
|---|---|
position | 2 — rank in the result list as Yandex ordered it, ads and widgets included |
organicPosition | 1 — rank counting organic listings only (null for ads and featured blocks) |
type | organic, ad or featured |
featureType | video, images, related, neuro-answer, … (null for organic and ads) |
title | Amazon.com: Discover Ergonomic Desk Chairs Engineered... |
url | https://www.amazon.com/ergonomic-chair/s?k=ergonomic+chair |
displayedUrl | amazon.com › ergonomic-chair — the breadcrumb Yandex prints |
displayedDomain | amazon.com |
brandName | Amazon — the site name Yandex shows above the title |
snippet | Discover ergonomic desk chairs engineered with adjustable components… |
sitelinks | [{ "title": "Rental cars", "url": "https://…" }] |
isAd | false |
page, positionOnPage | which SERP page it came from |
region, regionRequested | the Yandex lr region code that produced this ranking |
domain, domainRequested, searchUrl, searchQuery, scrapedAt | provenance — domain is the Yandex host that actually answered |
Input
{"queries": ["купить пластиковые окна", "ergonomic office chair"],"region": 213,"maxItemsPerQuery": 50,"maxItems": 200}
queries— keywords, any language. Cyrillic, Turkish and Kazakh all work.startUrls— paste Yandex search URLs instead, e.g.https://yandex.com/search/?text=pizza&lr=213. The query, region and start page are read out of the URL.region— the Yandexlrcode that decides which regional ranking you get. All of these are tested and confirmed working: 225 Russia, 213 Moscow, 2 Saint Petersburg, 65 Novosibirsk, 54 Yekaterinburg, 43 Kazan, 47 Nizhny Novgorod, 39 Rostov-on-Don, 35 Krasnodar, 51 Samara, 187 Ukraine, 143 Kyiv, 149 Belarus, 157 Minsk, 159 Kazakhstan, 163 Astana, 10393 Almaty, 983 Turkey, 11508 Istanbul, 171 Uzbekistan, 10335 Tashkent, 168 Azerbaijan, 167 Armenia, 10262 Yerevan, 169 Georgia, 84 USA, 102 Germany, 95 United Kingdom.maxItemsPerQuery/maxItems— the actor pages through Yandex on its own until it hits either.includeAds,includeFeatured— set either tofalseif you only want the organic listings.
Region really does change the ranking
Same query, different lr, first organic result:
lr | Region | Top result for pizza |
|---|---|---|
| 213 | Moscow | youtube.com |
| 983 | Turkey | dominos.com.tr |
| 11508 | Istanbul | nefisyemektarifleri.com |
| 10393 | Almaty | nefisyemektarifleri.com |
Pagination
Yandex re-ranks between pages, so consecutive pages overlap. The actor deduplicates as it goes,
which means maxItemsPerQuery: 100 gives you 100 distinct results, not 100 rows with 20 repeats in
them. A 20-page run on one keyword returned 171 unique results from 180 raw cards.
Speed, from real runs
| Run | Results | Time |
|---|---|---|
| One keyword, first page | 5 | 4.1 s |
One keyword with ads, Istanbul (lr=11508) | 15 | 7.8 s |
| Three keywords, English + Russian + Turkish, 10 pages deep | 250 | 58.9 s |
Roughly 4 results per second, and it holds at depth.
What this does not do
- No total result count. Modern Yandex SERPs no longer print "about 12,000,000 results" into the HTML, so there is nothing honest to return. The field does not exist rather than being guessed.
- Ad destination URLs are Yandex click trackers. A Yandex Direct ad links through
yabs.yandex.ru/count/…. The advertiser's real domain is indisplayedDomain, taken from the breadcrumb Yandex prints. We do not follow the tracker — that would cost you a request per ad and register a fake ad click. - The AI answer ("Yazeka") is a teaser only. Yandex loads that text with JavaScript after the page renders. You get the fact that the block occupied a rank slot, not its body text.
- Not images, video, maps or news search. This is
/search/, the web index. Yandex Maps places and reviews are separate actors. - Not a live rank checker down to position 500. Yandex gets progressively less willing to serve very deep pages. Fifteen pages per query is the default ceiling and around 20 is realistic.
Reliability
Yandex defends its SERPs with SmartCaptcha, and it is genuinely aggressive. Two things make this actor work where a plain HTTP client gets a wall of "are you a robot":
- A Firefox TLS fingerprint. Measured on the same addresses: a Chrome fingerprint got 0 pages out of 8; Firefox got 5 out of 8. Plain Node.js gets none.
- A different exit address on every single request. Yandex challenges an address after a handful of searches and then keeps challenging it, so reusing one address is what kills a run — not the address being "bad". With a new proxy session per request, a 20-page run needed exactly 20 requests, no retries.
When Yandex does challenge a page anyway, the actor retries on new addresses, and if it still cannot get through it writes an uncharged diagnostic row saying so. You are never billed for a captcha page.
FAQ
Is there a Yandex search API I could use instead?
Yandex's XML search interface (xmlsearch.yandex.ru) answers HTTP 403 without a paid Yandex Cloud
key, and the paid Search API is billed per query with a signup that expects a Russian legal entity.
This actor needs neither.
Do I need my own proxies? No. Leave the proxy input alone and it uses Apify's datacenter proxy, which is what it is tuned for. You can supply your own proxy URLs if you want a specific country.
Does it work for Russian-language queries?
Yes, and that is the main use case. Pass Cyrillic straight through in queries.
Can I get results as they look in Moscow while running from anywhere?
Yes. Set region: 213. The region code, not the proxy country, is what selects the ranking, and the
row records which region Yandex actually served in region.
How many results per keyword can I get?
About 10-20 on the first page and roughly 9 per page after that. 100-170 unique results per keyword
is comfortable. Set maxItemsPerQuery to whatever you need and the actor pages until it gets there.
What counts as a charged result? Every row that carries a real result — organic, ad or featured. Diagnostic rows, the empty-input sample row, and captcha pages are never charged. A 250-result run billed exactly 250 result events and one actor-start event.
How is the price structured? $0.0034 per result plus $0.001 each time a run starts. There is no per-page minimum, so a run that returns 5 results costs $0.018. A 250-result run comes to $0.851.
Can I track a competitor's rank over time?
Yes. Run it on a schedule with queries set to your keyword list and read organicPosition for the
domain you care about. displayedDomain is there to make that a one-line filter.
Why does the run use yandex.com.tr by default?
Every Yandex front-end serves the same index, but they do not defend themselves equally. Over 20
consecutive paginated requests, yandex.com.tr and yandex.uz answered every one on the first
attempt while yandex.com and yandex.ru served page 1 and then challenged every deeper page.
You can override it with the domain input.
yandex.com.tr also obeys the lr region code — asking it for lr=213 returns Moscow-ranked
Russian results, and lr=225, 149 and 159 come back pinned to Russia, Belarus and Kazakhstan.
yandex.uz does not: it answers lr=213 with region 10335 (Tashkent). Use yandex.com.tr
whenever the region matters.
What if the host I picked answers with a robot check?
The query is retried once on yandex.com.tr, pinned to the same region — your own region if you
set one, otherwise the region of the host you asked for (yandex.ru → lr=225, yandex.by →
149, yandex.kz → 159, and so on), so the ranking still matches what you asked for. The run
pushes one uncharged DOMAIN_FAILOVER notice row saying it happened, and every result row carries
domain (the host that answered) alongside domainRequested (the host you asked for). If the
retry is challenged too, the page is reported as an uncharged CAPTCHA row and nothing is billed.