# Yandex Maps Scraper - Places, Phones & New Business Monitor (`neverempty/yandex-maps-scraper`) Actor

For lead lists and local market research: Yandex Maps (Яндекс Карты) places by category and city with name, address, phones, website, hours and rating - only places that really match your category, city and street, not other trades or nearby towns. Monitor mode returns only new or changed places.

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

## Pricing

from $4.50 / 1,000 place returneds

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 & New Business Monitor

Get places from **Yandex Maps** (Яндекс Карты, yandex.ru/maps) by business type and city: name, categories, full address with street, house and postal code, coordinates, **phones**, website, social links, **opening hours by day**, status, rating, number of ratings and reviews, and whether the place pays Yandex for placement. Search by what you would type into Yandex Maps (стоматология, кафе, автосервис, dentist…) plus a city, paste a Yandex Maps search URL, or give place URLs or IDs.

**Only places that really match.** Yandex Maps mixes other trades and nearby towns into its results (a plain search for dentists also shows clinics in Mytischi and Krasnogorsk outside Moscow; a street name also matches a boulevard with a similar name). This Actor checks every place and, by default, returns and charges **only places whose name or categories match the search term, whose city is the Location you gave, and whose address contains the street or postal code you asked for**. Each row says how it matched (`matchedBy`, `locationMatch`, `addressMatch`), and a free row says how many places were left out, with examples.

**Monitor mode** reads the same search again and returns **only what changed**: places that appear for the first time, and places whose name, phones, website, address, opening hours, status or categories changed (with the old values). Every change is confirmed on the place's own page before it is returned, so a result page that shows something different for a moment is not sold as a change.

Unofficial. Reads public Yandex Maps pages only, without logging in. Not affiliated with Yandex.

### What you get

| Field | Meaning |
|---|---|
| `placeId`, `url` | Yandex Maps place ID (organization ID) and the place page |
| `name`, `categories` | Name and Yandex categories (for example `Стоматологическая клиника`, `детская стоматология`) |
| `address`, `street`, `house`, `locality`, `area`, `postalCode`, `country`, `addressDetails` | Full address and its parts (`addressDetails` is a note such as a floor) |
| `latitude`, `longitude` | Coordinates |
| `phone`, `phones` | First phone, and all phones as `{number, display, type, mobile}`; `mobile` is `true` / `false` for Russian and Kazakh +7 numbers and `null` for other countries |
| `website`, `websites` | Website(s) with Yandex ad tracking (`yclid`, `utm_*`) removed |
| `socialLinks` | Telegram, VK, WhatsApp and other links shown on the place card |
| `hoursText`, `hours`, `openNow` | Opening hours as shown, and by day: `{"mon": ["09:00-21:00"], …, "sun": []}` (`[]` = closed that day, `00:00-24:00` = open 24 hours) |
| `businessStatus` | Yandex status of the place, for example `open` |
| `rating`, `ratingCount`, `reviewCount` | Rating out of 5 (one decimal), number of ratings, number of text reviews |
| `sponsored` | `true` when the place pays Yandex for placement in the results |
| `verifiedOwner` | `true` when Yandex marks the owner as verified |
| `matchedBy` | `name` or `category` (the search term is in the name or a category name), or `yandex-rubric` (the place has a category Yandex itself chose for the search term) |
| `locationMatch` | `city` (the Location is the place's city or district) or `region` (a region name found in the address) |
| `addressMatch` | The `addressContains` entry the address matched |
| `page`, `positionOnPage` | Where the place was in the Yandex Maps results |
| `changeType`, `changedFields`, `previous` | Monitor mode only: `first-check`, `new-in-results` or `changed`, which fields changed, and their old values |

Rows that explain something (no results, places left out as not matching, nothing changed, a place ID that does not exist, a check page, a run that reached its maximum charge) have a `status` other than `ok` and a `note`. **They are never charged.**

### Input

| Input | What it does |
|---|---|
| `searchQueries` | What you would type into Yandex Maps: `стоматология`, `кафе`, `автосервис`, `dentist`, a chain name. Empty together with `searchUrls` and `placeUrls` = example search `стоматология` in `Казань` |
| `location` | City, district or region: `Казань`, `Москва`, `Санкт-Петербург`, `Almaty`, `Московская область`. Added to each search term, and used to keep only places in that city |
| `addressContains` | Keep only places whose address contains one of these, word for word: `Тверская улица`, `проспект Мира`, or a postal code `420111` (exact) |
| `searchUrls` | Yandex Maps search pages copied from the browser (`https://yandex.ru/maps/213/moscow/search/кафе/`, `https://yandex.ru/maps/?text=кафе&ll=…&z=…`) |
| `placeUrls` | Place pages (`https://yandex.ru/maps/org/<name>/<id>/`) or place IDs, up to 100 per run |
| `language` | `auto` (default: Russian when the input has Cyrillic), `ru` or `en` |
| `onlyMatching` | On (default): only places that match the search term, location and address filter. Off: everything Yandex Maps shows, with the match columns filled |
| `maxResultsPerSearch` | Most places per search, 1 to 500 (default 50) |
| `maxPages` | Results pages per search, 25 places a page, 1 to 20 (default 4) |
| `includeSponsored` | Return places that pay for placement too (default on), marked `sponsored` |
| `onlyNew` | Monitor mode: only new places and changed details |
| `includeRatingChanges` | Monitor mode: a rating change also counts (default off) |
| `watchName` | Separate monitor memories, for example one per client |
| `resetMonitoringState` | Forget what this monitor has seen and start again |

Up to 10 searches (search terms plus search URLs) and 100 places by URL/ID per run.

### Tips

- **Write search terms and the city in Russian** for places in Russia (`стоматология` + `Москва`). In our tests the English `dentist Moscow` returned only 1 place on the first Yandex Maps page, while `стоматология Москва` returned 25.
- Write the full city name (`Санкт-Петербург`, not `СПб`), in the same language as `language`.
- A city name matches the place's city only. To cover a whole region, write the region (`Московская область`, `Республика Татарстан`).
- `addressContains` is strict on purpose: `Тверская улица` does not match `Тверской бульвар` or `1-я Тверская-Ямская улица`.

### Monitor mode

1. First run: returns up to `maxResultsPerSearch` places (`first-check`) and remembers them.
2. Next runs: read the same pages and return only
   - `new-in-results`: a place this monitor has not seen in these results before. It may be newly opened, or it may have moved into the pages this Actor reads; Yandex Maps does not show an opening date, so this Actor does not invent one;
   - `changed`: the name, phones, website, address, opening hours, status or categories differ from what this monitor remembered, **and the place's own page confirms it** (`changedFields` and `previous` say what changed). Ratings are watched only with `includeRatingChanges`; the number of ratings is never watched.
3. If a results page cannot be read, the monitor judges nothing for that search: nothing is returned, remembered or charged, and the next run checks again.
4. If a run reaches your maximum charge, the places it could not return are returned by the next run.

Yandex Maps rotates places that pay for placement through the first results page from one request to the next. In our test (автосервис in Казань, 2 pages, 4 checks) every place that looked new after the first check was such an advertised place from further down the list. So in monitor mode **an advertised place seen for the first time is remembered but not returned as new**; its later changes are still returned. For the same reason, a place that drops out of the results is not reported: disappearing from a page is not a reliable sign of closing.

### Phone numbers and personal data

Phones, websites and social links are returned exactly as the business shows them on its public Yandex Maps card. Some small businesses list a personal mobile number; such numbers are marked `mobile: true` so you can treat them separately. This Actor does not return anything Yandex does not show on the card, and it drops the advertiser's legal name and tax number that Yandex keeps in the page data. If you contact businesses, follow the rules that apply to you (for example, Russian advertising law requires prior consent for advertising calls and messages).

### Pricing

Pay per event:

- **Run start**: one small fee per run (not per page and not per GB of memory).
- **Place returned**: per place row.

Places left out as not matching and all explanation rows are free. A search that finds nothing is not charged at all. In monitor mode, the run start fee is the price of the check itself, so it is charged even when nothing changed. Set a maximum charge per run and the Actor will not start a run that cannot return at least one place.

### Reliability

- Reads the plain Yandex Maps pages; no browser. Measured 2026-09-25 from Apify's servers (3 pages × 5 times): 15 of 15 answered without a proxy, 14 of 15 through datacenter proxies and 13 of 15 through residential proxies (the misses were 30-second timeouts), 0 check pages.
- In 18 test runs of this Actor on 2026-09-25 (Kazan, Moscow, Saint Petersburg; 1 to 6 pages each), every page was read on the first request without a proxy, and a run took 5 to 25 seconds.
- If Yandex refuses an IP address (403, 429, 5xx) or times out, the Actor asks again from other datacenter IPs, then from a residential IP outside Russia.
- If Yandex shows its check page ("Are you not a robot?"), the Actor **does not solve or bypass it**: it stops, returns a free row and remembers nothing.
- robots.txt of yandex.com is read on every run and every URL is checked against it before it is requested.

### Example output

```json
{
  "status": "ok",
  "placeId": "137241302033",
  "name": "Стоматология Хаят смайл",
  "categories": ["Стоматологическая клиника", "детская стоматология"],
  "address": "Республика Татарстан (Татарстан), Казань, улица Галактионова, 3",
  "street": "улица Галактионова",
  "house": "3",
  "locality": "Казань",
  "postalCode": "420015",
  "latitude": 55.793206,
  "longitude": 49.126781,
  "phone": "+79011439356",
  "phones": [{ "number": "+79011439356", "display": "+7 (901) 143-93-56", "type": "phone", "mobile": true }],
  "website": "https://hayat-smile.ru/",
  "socialLinks": [{ "type": "telegram", "url": "https://t.me/prestigedent" }],
  "hoursText": "ежедневно, 9:00 AM–9:00 PM",
  "hours": { "mon": ["09:00-21:00"], "tue": ["09:00-21:00"], "wed": ["09:00-21:00"], "thu": ["09:00-21:00"], "fri": ["09:00-21:00"], "sat": ["09:00-21:00"], "sun": ["09:00-21:00"] },
  "businessStatus": "open",
  "rating": 5,
  "ratingCount": 752,
  "reviewCount": 625,
  "sponsored": true,
  "url": "https://yandex.com/maps/org/hayat_smile_dentistry/137241302033/",
  "matchedBy": "name",
  "locationMatch": "city",
  "page": 1,
  "positionOnPage": 3,
  "searchQuery": "стоматология",
  "searchLocation": "Казань"
}
```

### Support

Questions, a search that returns something unexpected, or a field you need: open an issue in the **Issues** tab of this Actor. Include the run ID.

# Actor input Schema

## `searchQueries` (type: `array`):

What you would type into the Yandex Maps search box, for example стоматология, кафе, автосервис, dentist, pharmacy, or a chain name. Russian terms give the best results. Put the city in Location, not here. Leave Search terms, Search URLs and Place URLs all empty to run the example search стоматология in Казань.

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

Optional. City, district or region the search is about, for example Казань, Москва, Санкт-Петербург, Almaty, Московская область. It is added to each search term, and with Only matching places on, a place is returned only when this name is its city (or, for a region name with область / край / республика / region / oblast, anywhere in its address). Write the full name (Санкт-Петербург, not СПб).

## `addressContains` (type: `array`):

Optional. Keep only places whose address contains one of these, word for word and in this order, for example Тверская улица, проспект Мира, 420111. A 5 or 6 digit entry is matched against the postal code exactly. Other places Yandex Maps shows nearby are left out and not charged.

## `searchUrls` (type: `array`):

Optional. Yandex Maps search pages copied from your browser, for example https://yandex.ru/maps/213/moscow/search/кафе/ or https://yandex.ru/maps/?text=кафе\&ll=37.62,55.75\&z=13 (the map window ll, z, spn is kept). A place page pasted here is read as a place.

## `placeUrls` (type: `array`):

Optional. Yandex Maps place pages or place IDs, for example https://yandex.ru/maps/org/short_talk/80065192585/ or 80065192585. Up to 100 per run. Returns the details of each place; with Only new or changed, only places whose details changed.

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

Language of names, addresses and categories. Location is matched in this language, so write it in the same language. Empty = auto.

## `onlyMatching` (type: `boolean`):

On (default): return and charge only places where the search term is in the name or categories (or is a category Yandex itself chose for the term), the Location is the place's city, and the address matches Address must contain when given. Places Yandex Maps mixes in from nearby towns or other trades are left out, and a free row says how many. Off: return everything Yandex Maps shows; the match columns still say how each place matched.

## `maxResultsPerSearch` (type: `integer`):

Most places returned for one search. Empty = 50. In monitor mode it limits the places returned per search in one run; the rest come in the next run.

## `maxPages` (type: `integer`):

How many Yandex Maps results pages to read for each search (25 places a page, 1 to 20). Reading stops earlier when enough places matched or the list ends. Empty = 4.

## `includeSponsored` (type: `boolean`):

On (default): return places that pay Yandex for placement too, marked sponsored true. Off: leave them out.

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

Off (default): return the places found. On: the first run returns all of them marked first-check; later runs return only places that appear in this search for the first time (new-in-results) and places whose name, phones, website, address, opening hours, status or categories changed (changed, with the old values). A change is confirmed on the place's own page before it is returned. Schedule it daily or hourly.

## `includeRatingChanges` (type: `boolean`):

Monitor mode only. On: a change of the rating (one decimal, for example 4.8 to 4.9) also counts as a change. Off (default): ratings are returned but not watched. The number of ratings is never watched (it grows every day).

## `watchName` (type: `string`):

Optional. Name of this monitor (letters, digits, dot, dash, underscore). Monitors with different names remember separately. Empty = default.

## `resetMonitoringState` (type: `boolean`):

Forget what this monitor remembered and treat this run as the first check.

## Actor input object example

```json
{
  "searchQueries": [
    "стоматология"
  ],
  "location": "Казань",
  "onlyMatching": true,
  "includeSponsored": true,
  "onlyNew": false,
  "includeRatingChanges": false,
  "resetMonitoringState": false
}
```

# Actor output Schema

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

One row per Yandex Maps place: place ID, name, categories, full address with street, house, city and postal code, coordinates, phones (marked mobile or landline for +7 numbers), website without ad tracking, social links, opening hours by day, open now, status, rating, number of ratings and reviews, advertised flag, link, and how the place matched the search term, location and address filter. Monitor mode marks rows first-check, new-in-results or changed (with the changed fields and old values). A search with no places, no matching places, nothing changed, a place ID that does not exist, a check page, a refused request or a run that hit its maximum charge comes back as a free row that says why.

# 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 = {
    "searchQueries": [
        "стоматология"
    ],
    "location": "Казань"
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/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 = {
    "searchQueries": ["стоматология"],
    "location": "Казань",
}

# Run the Actor and wait for it to finish
run = client.actor("neverempty/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 '{
  "searchQueries": [
    "стоматология"
  ],
  "location": "Казань"
}' |
apify call neverempty/yandex-maps-scraper --silent --output-dataset

```

## MCP server setup

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