# Yandex Maps Scraper: Places, Phones, Websites (`amitaviv/yandex-maps-scraper`) Actor

Scrape Yandex Maps business listings by search term and area: name, categories, address, coordinates, phones, website, social links, opening hours, rating and review counts. No browser; places are de-duplicated and large areas are split into tiles. New-places-only mode. Pay per delivered place.

- **URL**: https://apify.com/amitaviv/yandex-maps-scraper.md
- **Developed by:** [Amit Aviv](https://apify.com/amitaviv) (community)
- **Categories:** Lead generation, Travel
- **Stats:** 1 total users, 1 monthly users, 75.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 place delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Yandex Maps Scraper: Places, Phones, Websites

Business listings from Yandex Maps for a search term and an area: name, categories, address, coordinates, phones, website, social links, opening hours, rating and review counts. It reads the public search pages over plain HTTP (no browser), you pay only for places delivered, and a run that delivers nothing because of an error or a block ends as Failed, never as a green empty run.

### What you get

- Name, short name, categories (names and Yandex category ids), chain name and id
- Full address, street, house, city, postcode, country, latitude and longitude
- Phones (with extensions kept apart), websites (tracking parameters removed), social links (Telegram, WhatsApp, VK and others)
- Opening hours as text and per weekday, open / closed status
- Rating, number of ratings, number of reviews, number of photos, main photo and logo URLs
- Flags: owner verified by Yandex, pays Yandex for placement (`isAdvertiser`), phone may be a call-tracking substitute (`phoneIsCallTracking`), "Good place" award year
- Features Yandex lists for the place (payment methods, Wi-Fi, services and so on), nearby metro stations
- One record per place, as JSON, CSV or Excel, or through the API. A place is delivered and charged once per run, however many times Yandex repeats it.
- A run summary (`OUTPUT_SUMMARY` in the run's key-value store): what was requested, delivered and charged, what was left out and why, how many pages and map tiles were searched, which inputs failed or were ignored, and why the run stopped.

What it does not return: review texts, reviewer names, emails, menus, photo galleries, anything behind a login.

### What is left out by default

Two kinds of listing are not delivered and not charged unless you ask for them; the status message says how many there were.

- **Individual practitioners** (`includeIndividuals`, off): listings that are a person working under their own name, such as "Нотариус Филина Н. В." or "Адвокат Галимов Ш. Г.", or a title that says self-employed or "ИП". Their names and phones are personal data. The actor recognises a person's name (surname with initials, a patronymic, a name right after a profession word) in these Yandex categories: notaries, lawyers and legal services, psychologists and psychotherapists, coaching, tutors, speech therapists, photographers, massage and cosmetology; and in any category when the title also has a profession word (нотариус, адвокат, юрист, психолог, репетитор, логопед, косметолог, массажист, парикмахер, фотограф, тренер, риэлтор, консультант, or the same in Latin letters). In a test over eight such professions in Kazan it held back 120 listings of 904 (`dhAdoHc6C1Z5n0Qmg`). It is a heuristic and not perfect, and some named practitioners remain in the output (4 or 5 of 818 places in a test over professions in Samara, `BNb30NbAEallQGjuC`). What it does not recognise:

  - Beauty salon and nail studio categories are not covered, and "мастер" and "специалист" are not profession words: a named master in a beauty or nail category ("Мастер маникюра Голякова Татьяна", "Специалист Куклева Н. А.") is delivered.
  - A title with an organisation word or a number sign is always treated as an organisation: a lawyer listed as "Адвокатский кабинет № … Фамилия И. О." or under "Палата адвокатов …, Фамилия И. О." is delivered, and so is anything with "центр", "бюро", "коллегия", "компания", "клиника" or "школа" in the title.
  - A studio named after its owner ("Массажный кабинет Алиса Хан"), a name written in another form, a Turkish or Kazakh name form, or a listing with no name in the title is delivered.

  Organisations named after a person are not treated as individuals: in a test of 900 Moscow libraries, schools, museums, theatres, hospitals and universities none was held back (`NjQQ4G6vI5lxXP3Gh`).
- **Permanently closed places** (`includeClosed`, off): places Yandex marks as closed for good.

### How to use

1. Type what you are looking for into **Search terms or Yandex Maps URLs**, in any language (`dentist`, `кофейня`, `kuaför`). Several entries are fine.
2. Say where: a **Location** name (`Kazan`), or a **Bounding box**, or a **Centre point** with **Zoom**. Or skip this and paste a Yandex Maps search URL: its map area is used. For a large city, search its districts (or bounding boxes) rather than the whole city: see "Limits".
3. Set **Max places per search** and press Start.
4. Download the results from the Output tab, or read them from the API.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `queries` | list of text | none (required) | Search terms, Yandex Maps search URLs, or place URLs (`…/maps/org/…/1124715036/` returns that one place). URLs from yandex.com, yandex.ru, yandex.com.tr and the other Yandex country sites are accepted, with or without `https://`. Entries from other sites are ignored and listed in the summary. |
| `location` | text | empty | City, district or region by name. Several, separated by `;`: every term is searched in every location. The run log shows the area Yandex resolved the name to. |
| `boundingBox` | text | empty | `south,west,north,east` in degrees, latitude first, at most 180 degrees wide. Wins over `location`. |
| `coordinates`, `zoom` | text, number | empty, 12 | `latitude,longitude` of the map centre and a Yandex zoom level (3-19). Wins over `location`. |
| `maxItems` | number | 100 | Stop after this many places for each search (each term in each location, or each URL). |
| `language` | choice | `en` | `en`, `ru`, `tr`, `uk` or `kk`: language of names, addresses, categories and hours, as far as Yandex has them. |
| `strictRelevance` | yes/no | yes | Deliver only places inside the requested area and in a category Yandex matched to your term. See "Strict relevance". |
| `includeIndividuals` | yes/no | no | Also deliver listings of individual practitioners, marked `isIndividual: true`. See "What is left out by default". |
| `includeClosed` | yes/no | no | Also deliver permanently closed places (`status: permanent-closed`). |
| `onlyNew` | yes/no | no | Deliver and charge only places earlier runs have not delivered. See "Only new places". |
| `monitorKey` | text | empty | Name of the "only new" memory, to keep two schedules apart. |
| `maxConcurrency` | number | 5 | Requests sent to Yandex Maps at the same time (1-5). |
| `proxyConfiguration` | proxy | off | Not needed. See the FAQ. |

Runs use 512 MB by default. Less memory also means less processor share and slower runs; more is not needed.

This input was run as `hf7NNDPrj5brNiCJg` (a place URL, a search URL with its own map area, a Turkish search URL, and one term in a district):

```json
{
  "queries": [
    "https://yandex.ru/maps/org/1124715036/",
    "https://yandex.com/maps/?ll=49.12,55.79&spn=0.04,0.02&text=pharmacy",
    "https://yandex.com.tr/harita/11508/istanbul/search/kuaf%C3%B6r/",
    "eczane"
  ],
  "location": "Kadıköy Istanbul",
  "maxItems": 40,
  "language": "tr"
}
```

It ended as `Scraped 110 places from 4 queries — 3 not delivered and not charged by strict relevance (3 outside the area, 0 in another category)`, in 12 seconds. (The current build adds a note to this message when a search ends below the maximum because Yandex listed no more: see "Reliability and failure behaviour".)

### Example result

Taken from run `30ei0cKEuDx94dTzz` (`coffee shop` in `Kazan`) on 2026-10-13, unedited:

```json
{
  "id": "214802898351",
  "url": "https://yandex.com/maps/org/chocolateria_roero/214802898351/",
  "title": "Chocolateria Roero",
  "shortTitle": "Chocolateria Roero",
  "categories": [
    "Coffee shop",
    "confectionary"
  ],
  "categoryIds": [
    "35193114937",
    "184108017"
  ],
  "address": "Republic of Tatarstan, City of Kazan, Peterburgskaya Street, 25",
  "additionalAddress": null,
  "street": "Peterburgskaya Street",
  "house": "25",
  "city": "City of Kazan",
  "postalCode": "420107",
  "country": "Russian Federation",
  "latitude": 55.784472,
  "longitude": 49.127404,
  "phone": "+79600610250",
  "phones": [
    "+79600610250"
  ],
  "phoneExtensions": [],
  "phoneIsCallTracking": false,
  "website": "https://www.roero.ru/",
  "websites": [
    "https://www.roero.ru/"
  ],
  "socialLinks": [
    {
      "type": "telegram",
      "url": "https://t.me/roerocioccolato"
    }
  ],
  "openingHours": "Mon-Fri 8:00 AM–10:00 PM; Sat,Sun 9:00 AM–10:00 PM",
  "openingHoursByDay": {
    "sunday": [
      "09:00-22:00"
    ],
    "monday": [
      "08:00-22:00"
    ],
    "tuesday": [
      "08:00-22:00"
    ],
    "wednesday": [
      "08:00-22:00"
    ],
    "thursday": [
      "08:00-22:00"
    ],
    "friday": [
      "08:00-22:00"
    ],
    "saturday": [
      "09:00-22:00"
    ]
  },
  "status": "open",
  "rating": 5,
  "ratingCount": 114,
  "reviewCount": 87,
  "photoCount": 137,
  "imageUrl": "https://avatars.mds.yandex.net/get-altay/14795363/2a0000019584995e64650c099a717223299d/orig",
  "logoUrl": null,
  "chainName": null,
  "chainId": null,
  "isVerifiedOwner": false,
  "isAdvertiser": false,
  "isIndividual": false,
  "goodPlaceYear": null,
  "features": {
    "food delivery": true,
    "coffee to go": true,
    "wheelchair accessibility": [
      "unavailable"
    ]
  },
  "nearbyMetro": [
    {
      "name": "Tukay Square",
      "distanceMeters": 136
    },
    {
      "name": "Sukonnaya Sloboda",
      "distanceMeters": 1178
    },
    {
      "name": "Kremlyovskaya",
      "distanceMeters": 1758
    }
  ],
  "timezoneOffsetSeconds": 10800,
  "searchQuery": "coffee shop",
  "searchLocation": "Kazan",
  "language": "en",
  "scrapedAt": "2026-10-13T16:26:10.044Z"
}
```

| Field | Meaning |
|---|---|
| `id` | Yandex's own id of the place; stable between runs. |
| `url` | The place's page on Yandex Maps. |
| `categories`, `categoryIds` | Yandex categories of the place, names in the chosen language. |
| `city` | The locality of the address; where Yandex gives none (Turkey), the city region of the place, e.g. `İstanbul`. |
| `phone`, `phones` | First phone and all phones as Yandex lists them, each once: normally international format (`+78432587858`), now and then a short number. |
| `phoneExtensions` | Extensions Yandex lists for the first phone, e.g. `["2", "3"]`; empty when there are none. |
| `phoneIsCallTracking` | `true` when the place advertises with Yandex call tracking and the actor could not get a number without it: the phone may be a Yandex substitute that forwards to the business. |
| `website`, `websites` | First website and all websites, without `utm_` and click-id parameters; Cyrillic domains are written in Cyrillic. |
| `socialLinks` | `[{ "type": "telegram", "url": "…" }]` |
| `openingHoursByDay` | Opening intervals per weekday, local time; an empty list means closed that day; `null` when Yandex has no hours. |
| `status` | `open`, `permanent-closed` or another value, as Yandex reports it. |
| `rating`, `ratingCount`, `reviewCount` | Yandex rating (1-5), how many ratings, how many written reviews. `rating` is `null` for a place nobody rated. |
| `photoCount`, `imageUrl`, `logoUrl` | Number of photos as the result list states it (the place's own page often shows one fewer), main photo and logo. |
| `isVerifiedOwner` | Yandex shows the "owner verified" mark. |
| `isAdvertiser` | The place pays Yandex for priority placement. |
| `isIndividual` | The listing looks like an individual practitioner. Always `false` unless `includeIndividuals` is on. |
| `goodPlaceYear` | Year of Yandex's "Good place" award, or `null`. |
| `features` | What Yandex lists for the place, by Yandex's own labels. |
| `searchQuery`, `searchLocation`, `language` | The search that found the place. A place found by two searches of one run is delivered once, for the first. |

Fields Yandex does not provide for a place are `null` (or an empty list), never missing.

Yandex serves some rows cut down, without rating and photo data. The actor asks for such a page again and then reads the place's own page; for the few places that still come without it, `rating`, `ratingCount`, `reviewCount`, `photoCount`, `imageUrl`, `logoUrl`, `goodPlaceYear` and `nearbyMetro` are `null` (not known, which is different from 0) and the status message counts them: 6 of 2,500 in run `3mWdTD1qprZ37rkaJ`.

### Pricing

Pay per event. You pay for what is delivered, not for time or memory.

| Event | Free | Bronze | Silver | Gold and above |
|---|---|---|---|---|
| Actor start (once per run) | $0.0048 | $0.004 | $0.0036 | $0.0032 |
| Place delivered | $0.003 | $0.0025 | $0.00225 | $0.002 |

That is $2.50 per 1,000 places on the Bronze plan. Phones, websites and social links are included; there is no extra charge for them.

Worked example: one search that delivers 500 places on the Bronze plan costs 500 × $0.0025 + $0.004 = $1.254; on the Free plan 500 × $0.003 + $0.0048 = $1.5048. A scheduled "only new" run on Bronze that finds 3 new places costs 3 × $0.0025 + $0.004 = $0.0115; one that finds nothing new costs $0.004.

- Repeats, places dropped by strict relevance, individual practitioners and permanently closed places left out by default are not delivered and not charged.
- The start event is charged by Apify when a run starts, also when the run then fails on unusable input, and again when you resurrect a finished or aborted run.
- The maximum total charge you set for a run is respected: the actor stops before it would go over, keeps what was delivered, and says so in the status message. With a limit of $0.0165 a run delivered exactly 5 places (`M8xSkISgebufZaZci`).

### Strict relevance

Yandex Maps does not keep its list to the map view: it also lists places just outside it and, when an area has few matches, places from nearby towns. With **Strict relevance** on (the default) a place is delivered only if

- its coordinates are inside the requested area (location, bounding box, centre and zoom, or the area of a pasted URL with `ll` and `spn`), and
- it belongs to one of the categories Yandex matched to your term, when Yandex matched any.

What was dropped is counted in the status message and under `relevance` in `OUTPUT_SUMMARY`, and is not charged. In run `hf7NNDPrj5brNiCJg` 3 places outside the requested areas were dropped. When your term is part of a place name rather than a category, Yandex matches no category and only the area rule applies. For a term without any area (`dentist Almaty` with no location) the area is the one Yandex picks and only the category rule applies. Turn it off to get everything Yandex lists.

### Reliability and failure behaviour

| What happened | Run status | Status message |
|---|---|---|
| Places delivered | Succeeded | `Scraped 1500 places from 1 query` |
| Places delivered, but fewer than the maximum because Yandex's lists for the area ran out | Succeeded | `Scraped 472 places from 1 query — Yandex listed no more places for this area; search smaller districts for fuller coverage` (with several searches: `… for 1 of 3 searches; …`) |
| Yandex Maps has nothing for the search | Succeeded | `0 results: Yandex Maps has no places for this query` |
| Some searches worked, some failed | Succeeded | `Scraped 120 places from 2 queries — 1 of 2 queries failed ("…": …)` |
| Nothing delivered because of errors or blocking | **Failed** | `No places delivered: Yandex Maps blocked every attempt; try again later. No results were charged.` |
| Input the actor cannot use | **Failed**, within seconds | `Nothing to do: … Add a search term such as "dentist" (with "location": "Almaty") or a Yandex Maps search URL to "queries". No results were charged.` |
| Maximum charge reached | Succeeded | `… — stopped at the maximum charge set for this run` |
| Run timeout close | Succeeded | `… — stopped just before the run timeout; raise the timeout to get the rest` |
| Aborted gracefully | Aborted | `OUTPUT_SUMMARY` says `ABORTED` and how many places were delivered |

- Requests are retried up to 3 times with increasing pauses on network errors, HTTP 429 and 5xx, and when Yandex answers with its captcha page.
- When no proxy is set and Yandex answers a request with its captcha page, the retries and the rest of the run go through Apify Proxy: datacenter addresses first, residential addresses after 3 blocked answers. The run log says when this happens and `OUTPUT_SUMMARY` names the proxy group under `proxy`. The price per place stays the same.
- Now and then Yandex serves a result page with no answer in it. The actor asks for that page again (up to 3 more times) instead of taking it as "no results"; a page that stays unanswered is skipped and counted in the status message. If the first page of a search stays unanswered, that search fails and says so.
- Places are saved and charged page by page, so a run that stops early keeps what it delivered. When a page fails in the middle of a search (a block, an HTTP error), the pages before it are delivered first and the search is then reported as failed in the status message.
- Abort: data and charges are complete either way. A graceful abort also leaves a final `OUTPUT_SUMMARY` (`ZZVaoIh5PQaS1PHQP`: 188 places, summary `ABORTED`); an immediate abort stops the container at once, so the summary record is missing and the status message stays at "N places delivered so far".
- A resurrected run continues where it stopped and delivers and charges nothing twice.
- Measured on 2026-10-13 from the Apify platform without a proxy, on builds 0.1.8 and 0.1.9 (the current build differs from them only in the status message): 17 test runs, about 1,900 requests, none blocked, 12 retried after a network error or timeout. The largest (`U5JfAdrOr1fUL6ssG`, 1,045 requests) had 12 result pages that stayed unanswered and were skipped. In every test run the number of charged places equalled the number of dataset items.

### Limits

- **Coverage is what Yandex Maps lists, not a census.** For one map view Yandex serves at most 40 pages of up to 25 rows, with many repeats. When a list runs to 500 rows or more the actor searches the four quarters of that area as well, all four before any of them is cut further, so large areas keep yielding places and a run that stops at your maximum is not confined to one corner: 5,000 restaurants in Moscow from 23 map tiles (`U5JfAdrOr1fUL6ssG`), 2,500 pharmacies in Saint Petersburg from 10 tiles (`3mWdTD1qprZ37rkaJ`). But Yandex lists a slightly different set for each map view: in one test a single search of central Kazan returned 265 coffee places, and searching its four quarters afterwards turned up 10 more. In another test a whole-city search of Kazan delivered 472 coffee places (`Ah0p0Gvxe7q6xcU0s`); searching three small parts of the city separately found about 5% more in those parts (9 places the whole-city run did not have, against 187 it could have had there, 8 of them in the city centre). Treat the result as "the places Yandex shows for this search". **If you need a complete list, search districts one by one** (several locations separated by `;`, or bounding boxes) instead of the whole city; places found twice are delivered and charged once per run. When a search ends below your maximum because Yandex listed no more, the status message says `Yandex listed no more places for this area; search smaller districts for fuller coverage`.
- **A city-wide view of a very large city, or of a city Yandex covers thinly, returns only what Yandex lists at that view.** That can be a few dozen places: a pharmacy search over all of Istanbul (a pasted city-wide URL) returned 26 of 60 requested (`XjweaezQNdz8cGsXL`), because Yandex reported 23 results in total at that view, while a 0.04 × 0.02 degree box in Kadıköy alone reported 45. The actor splits an area only when a list runs long (500 rows or more), so a short list is never split. For large cities outside Russia, and for any city where a whole-city run comes back short, search districts or bounding boxes rather than the whole city.
- The same search run twice can return a slightly different set, for the same reason.
- No emails: Yandex Maps does not show them.
- Speed, measured on 2026-10-13 at the default 512 MB: 100 places in 11 to 19 seconds (`30ei0cKEuDx94dTzz`, `dmIb4tPLkR3uiPlHi`; the slower one with three runs going at once), 600 in 46 seconds (`w1LTllQW4ajS5bQKu`), 900 over six terms in 70 seconds (`NjQQ4G6vI5lxXP3Gh`). Large runs slow down as deeper tiles repeat what is already delivered, and places that advertise with call tracking need an extra request each: 2,500 pharmacies took 6.5 minutes and 5,000 Moscow restaurants 28 minutes, both at 256 MB. Count on 3 to 12 places per second. Result pages are about 1 MB each and reading them is processor work, so a run given 256 MB took 1.7 times as long for the same 600 places (`T7dc6Q5rpEkjfhcT5`) and cost about the same.
- Names and addresses come in the chosen language as far as Yandex has them; many are transliterated rather than translated.
- Coverage follows Yandex Maps. Tested searches: Moscow, Saint Petersburg, Kazan, Yekaterinburg, Novosibirsk, Zelenodolsk (Russia), Almaty (Kazakhstan), Tbilisi (Georgia), Istanbul (Türkiye; by district, see above for the whole city).
- Up to 100,000 places per search can be requested; the largest run tested delivered 7,796 (on an earlier build).

### Only new places

1. Turn on **Only new places** and save the input as a task.
2. Schedule the task (daily or weekly is enough for business listings).
3. The first run delivers what it finds, up to the maximum. Every later run delivers and charges only places it has not delivered before for the same search and area; a run with nothing new ends as Succeeded with `0 new places in 1 monitored query (no results charged)` and costs the start event only.

Tested: `x3hLcbti9AKHrEgB9` delivered 119 coffee places in a part of Kazan, and the same input run again (`T6FHp66Rboh1bpViW`) delivered 0.

**Keep each monitored search to an area of about 1,000 places or fewer.** A later run stops a search after 80 result pages in a row without a new place and says so in the status message, so in a larger area it checks only the top of Yandex's lists. Tested on pharmacies in all of Saint Petersburg: the first run delivered 2,500 (`3mWdTD1qprZ37rkaJ`); the second (`XrwyAe0L5Ar4TA6YD`) met 1,749 of them again, delivered 3 new ones and stopped with `1 search stopped after 80 result pages in a row without a new place; the area is too large to check in one "only new" search, use smaller areas`. For a big city, monitor its districts as separate searches (several locations separated by `;`, or several bounding boxes in separate tasks).

"New" means new to your memory, not necessarily newly opened: because Yandex lists a slightly different set each time, a later run can deliver a place that existed before and was not listed in earlier runs.

The memory is a key-value store named `yandex-maps-scraper-monitor` in your own account (one record per search and monitor name, at most 100,000 places each, least recently seen forgotten first). Delete the store or change **Monitor name** to start over. Places cut off by the maximum or by your charge limit are not marked as seen: the next run delivers them.

### FAQ

**Do I need a proxy?** No. Leave it off. The actor sends requests directly, which is fastest, and if Yandex blocks them it switches to Apify Proxy on its own (see "Reliability and failure behaviour"). From the Apify platform Yandex Maps answered every request directly in our tests on 2026-10-13; in October 2026 Apify's own automated test of this actor was shown the captcha, which is why the switch was added. Choosing Apify Proxy yourself also works but was many times slower per page on an earlier build (`qFMNOCPhqyq2eC7TF`: 12 pages in 123 seconds, none blocked).

**Why did I get fewer places than I asked for?** Yandex listed no more for the search at that map view (the status message then says `Yandex listed no more places for this area`), or strict relevance dropped the rest, or they were individual practitioners or permanently closed places (the status message says how many of each). Yandex lists a different set for each map view, so searching the districts of the area separately usually finds more; for a whole large city outside Russia it can find many times more. You can also try a broader term or turn strict relevance off.

**Why are some places outside my city when strict relevance is off?** Yandex fills short lists with places nearby. Strict relevance removes them.

**Why is `phoneIsCallTracking` true on some places?** The place advertises on Yandex with call tracking, and Yandex showed a substitute number in every answer the actor got. The number reaches the business, but it is not the business's own.

**Can I run it from code?** Yes: the API and the Apify clients for JavaScript and Python. The Output tab shows the URLs.

**What happens when Yandex Maps changes its pages?** Runs fail with a message that says so instead of returning empty data. Report the run id under Issues.

### Legal and responsible use

This actor collects business listing data that Yandex Maps shows publicly without a login. It does not collect reviews, reviewer names or any account data. Listings that look like one person working under their own name are left out by default (see "What is left out by default"); the recognition is not perfect (beauty and nail studios, for example, are not covered, and some named practitioners remain), and where a business is a sole trader its listed name and phone may be those of a person, so data-protection law can still apply to how you use them.

Yandex's terms of use for Maps say the service's information is for personal, non-commercial use. You are responsible for how you use the data: respect the site's terms, copyright and database rights, and data-protection law (GDPR, Russian Federal Law 152-FZ and others) in your country and the country of the data. Do not use the output for unsolicited marketing to individuals. If you are unsure, ask a lawyer before you build on it.

### Related actors

- [Europages Company Scraper](https://apify.com/amitaviv/europages-company-scraper): European B2B companies by keyword and country, with address, phone, website, employees and products, and the company's email on request. The same kind of lead list for Europe that this actor gives for Russia, the CIS and Türkiye.
- [TheFork Restaurants Scraper](https://apify.com/amitaviv/thefork-restaurants-scraper): restaurants on twelve TheFork sites (France, Italy, Spain, the UK and eight more), with cuisine, average price, rating, discounts and Michelin distinctions, if your restaurant or café research also covers Western Europe.
- [Company Hiring Tracker](https://apify.com/amitaviv/company-hiring-tracker): open jobs and newly opened roles for a list of companies, read from their public job boards (Greenhouse, Lever, Ashby and others), to see which companies on a lead list are growing. It finds only companies that use one of the supported job boards.

### Changelog

- 2026-10-17, 0.1.11: when Yandex blocks direct requests, the run continues through Apify Proxy (datacenter, then residential) instead of failing.
- 2026-10-13, 0.1: first version. The status message says when a search ended below the maximum because Yandex listed no more places.

### Support

Open an issue on the actor's **Issues** tab with the run id.

# Actor input Schema

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

What to search for, as you would type it on Yandex Maps, in any language (e.g. dentist, кофейня, kuaför). You can also paste Yandex Maps URLs: a search or category URL (the map area and filters of the URL are used) or a place URL (that one place). A URL of the map without a search cannot be used. A URL that shows a whole large city returns only what Yandex Maps lists at that view, which can be a few dozen places: zoom in to a district before copying it. Each term is searched in each location below.

## `location` (type: `string`):

City, district or region to search in, by name (e.g. Kazan, Almaty, Kadıköy Istanbul). Yandex Maps resolves the name to an area; the run log shows which. For a complete list of a large city search its districts one by one (or bounding boxes): a whole-city search misses some places, and for a very large city or one Yandex covers thinly (e.g. Istanbul) it can return only a few dozen. For several locations separate them with a semicolon (Kazan; Samara). Leave empty if you use a bounding box, coordinates or URLs, or if the place is part of the search term (e.g. dentist Almaty).

## `boundingBox` (type: `string`):

Exact rectangle to search: south,west,north,east in decimal degrees, latitude first (e.g. 55.70,37.50,55.80,37.70 is central Moscow), at most 180 degrees wide. Takes precedence over Location.

## `coordinates` (type: `string`):

latitude,longitude of the centre of the map (e.g. 55.7558,37.6173). Together with Zoom this defines the area, as a map window of about 1280 x 800 pixels would show it. Takes precedence over Location; a bounding box takes precedence over this.

## `zoom` (type: `integer`):

Yandex Maps zoom level around the centre point, 3 to 19 (default 12): 10 is a large city, 12 a district, 14 a neighbourhood, 16 a few streets. Used only with Centre point.

## `maxItems` (type: `integer`):

Maximum number of places to deliver for each search (each search term in each location, or each URL), 1 to 100,000 (default 100; e.g. 500). You are charged only for delivered places. Yandex Maps serves at most 40 pages of results for one map view, with many repeats; when a list runs long, the area is split into four smaller tiles and searched again, until this number is reached or the tiles run out. A run that ends below this number because Yandex Maps listed no more says so in its status message; smaller areas then find more.

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

Language of names, addresses, categories and opening hours in the output, as far as Yandex Maps has them in that language: en (default), ru, tr, uk or kk. It does not change which places are found.

## `strictRelevance` (type: `boolean`):

On (default): deliver only places whose coordinates are inside the requested area and, when Yandex Maps matched your search term to categories, that belong to one of those categories. Yandex Maps also lists places just outside the map view and from nearby towns; those are dropped. Dropped places are not charged and are counted in the status message and in OUTPUT_SUMMARY. Off: deliver everything Yandex Maps returns.

## `includeIndividuals` (type: `boolean`):

Off (default): listings that are a person working under their own name (for example a notary, lawyer, psychologist or tutor listed by surname and initials, or a title that says self-employed) are not delivered and not charged; the status message says how many. On: they are delivered, marked with isIndividual: true. Their names and phone numbers are personal data: turn this on only if you have a lawful basis to process them. Recognition looks for a person's name in the listing title, in the categories for notaries, lawyers and legal services, psychologists, coaching, tutors, speech therapists, photographers, massage and cosmetology, or next to a profession word such as нотариус, адвокат or репетитор. It is not perfect and named practitioners can remain: beauty salon and nail studio categories are not covered (a listing like "Мастер маникюра Фамилия Имя" is delivered), names written in other ways and listings without a name are not recognised, and a title with an organisation word or a number sign ("Адвокатский кабинет № 567 Фамилия И. О.", "палата", "центр", "бюро") is treated as an organisation. Organisations named after a person (a hospital, a library, a law firm with partners) are not treated as individuals.

## `includeClosed` (type: `boolean`):

Off (default): places Yandex Maps marks as permanently closed are not delivered and not charged; the status message says how many. On: they are delivered with status permanent-closed.

## `onlyNew` (type: `boolean`):

Deliver and charge only places that earlier runs of this actor in your account have not delivered for the same search and area. The first run delivers everything it finds, up to the maximum; later runs deliver what is left: places the earlier runs did not reach, and places that appeared on Yandex Maps since. A later run stops a search after 80 result pages in a row without a new place, so keep each monitored search to an area of about 1,000 places or fewer. The memory is a key-value store named yandex-maps-scraper-monitor in your account; delete it to start over.

## `monitorKey` (type: `string`):

Only with "Only new places". A free-text name (e.g. kazan-weekly). Runs with the same search, area and monitor name share one memory; give two schedules different names to keep their memories apart. Empty by default: runs with the same search and area share one memory.

## `maxConcurrency` (type: `integer`):

How many requests are sent to Yandex Maps at the same time, 1 to 5 (default 5). Lower it if your runs are being blocked.

## `proxyConfiguration` (type: `object`):

Leave off (default). The actor sends requests directly, which is about ten times faster, and when Yandex Maps answers with its captcha page it switches to Apify Proxy on its own: datacenter addresses first, residential after 3 blocked answers. Set a proxy here only to force every request through it from the start.

## Actor input object example

```json
{
  "queries": [
    "coffee shop"
  ],
  "location": "Kazan",
  "zoom": 12,
  "maxItems": 100,
  "language": "en",
  "strictRelevance": true,
  "includeIndividuals": false,
  "includeClosed": false,
  "onlyNew": false,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One JSON object per delivered place: id, url, title, categories, address, city, country, latitude, longitude, phone, phones, website, websites, socialLinks, openingHours, openingHoursByDay, status, rating, ratingCount, reviewCount, photoCount, isVerifiedOwner, isAdvertiser, features, nearbyMetro, searchQuery, searchLocation, scrapedAt. Missing values are null.

## `resultsCsv` (type: `string`):

The same places as a CSV file, one row per place.

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

JSON record OUTPUT_SUMMARY: places delivered per search and why each search stopped, events charged, places left out and why (strict relevance, individual practitioners, closed places, repeats), pages and map tiles searched, proxy used, failed or ignored inputs, and why the run stopped.

# 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": [
        "coffee shop"
    ],
    "location": "Kazan",
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("amitaviv/yandex-maps-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": ["coffee shop"],
    "location": "Kazan",
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("amitaviv/yandex-maps-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": [
    "coffee shop"
  ],
  "location": "Kazan",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call amitaviv/yandex-maps-scraper --silent --output-dataset

```

## MCP server setup

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