# 2GIS $1💰 Extract Phones, Emails, Reviews & Locations (`abotapi/2gis-places-scraper`) Actor

From $1/1K. Extract business and place data from 2GIS.com at scale. Get names, addresses, phones, emails, websites, social links, opening hours, ratings, reviews, photos, coordinates, and 80+ fields per place. Supports all regions covered by 2GIS with fast, low-cost extraction.

- **URL**: https://apify.com/abotapi/2gis-places-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Lead generation, Automation, Real estate
- **Stats:** 14 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 2GIS Places Scraper (Phones, Emails, Reviews)

Extract places from 2GIS at scale: names, addresses, phones, emails, websites, social links, per-day opening hours, ratings, reviews, photos, coordinates, and 80+ fields per place. Works across Russia, Kazakhstan, Uzbekistan, Kyrgyzstan, Azerbaijan, Georgia, Armenia, Belarus, the UAE, Saudi Arabia, Qatar, Kuwait, Bahrain, Oman, Cyprus, Czechia, Italy, Chile and every other region 2GIS covers. One flexible search mode, a URL mode, a fast JSON pipeline, and a low running cost.

### Why this scraper

- **80+ fields per place**, including every contact channel split out individually (primary phone, all phones, email, website, WhatsApp, Telegram, Instagram, VK, and more).
- **One flexible search**: combine a WHAT (queries and/or categories) with a WHERE (city, coordinates with a radius, or a map-area bounding box) in a single mode, plus a separate URL mode for direct 2GIS links or IDs. Every field is optional and they work together.
- **Reviews on demand**: pull full review text, author, rating, date, source (2GIS or Flamp), photos, and the official reply.
- **Structured opening hours**: all seven days, each with an explicit open or closed status, plus a ready-to-read summary string.
- **Runs on free datacenter proxy**: no premium proxy required, which keeps every run cheap and fast.
- **Nothing dropped**: the full upstream contact, attribute, and administrative blocks are passed through verbatim alongside the flat fields.

### Data you get

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

| Field | Example |
| --- | --- |
| name | Sample Cafe |
| rating | 4.8 |
| reviewCount | 0 |
| phone | +70000000000 |
| phones | \["+70000000000"] |
| email | contact@example.com |
| website | http://example.com |
| whatsapp | https://wa.me/70000000000 |
| telegram | https://t.me/example |
| instagram | https://instagram.com/example |
| vk | https://vk.com/example |
| fullAddress | City, Sample Street, 1 |
| city | Sample City |
| district | Sample District |
| street | Sample Street |
| houseNumber | 1 |
| postcode | 000000 |
| latitude | 55.0000 |
| longitude | 37.0000 |
| primaryRubric | Cafes |
| rubrics | \["Cafes", "Coffee shops"] |
| nameExtension | cafe |
| orgRating | 4.7 |
| orgReviewCount | 0 |
| flampRating | 4.8 |
| nearestStations | \[{"id": "0000", "distanceMeters": 300}] |
| badges | \[{"text": "Award winner", "type": "award"}] |
| floorCount | 2 |
| isPromoted | false |
| isAdvertised | false |
| is24x7 | false |
| hoursText | Mon: 09:00-21:00; Tue: 09:00-21:00; ... |
| photos | \["https://cdn.example.com/0000.jpg"] |
| orgName | Sample Org |
| orgBranchCount | 1 |
| isPromoted | false |
| url | https://2gis.ru/city/firm/00000000 |

Review records (when `maxReviews` is above zero) are written to the same dataset with `recordType` set to `review`:

| Field | Example |
| --- | --- |
| recordType | review |
| placeId | 00000000 |
| placeName | Sample Cafe |
| rating | 5 |
| text | Full review text appears here. |
| authorName | Jane Doe |
| authorPhotoUrl | https://cdn.example.com/profile/0000.jpg |
| authorReviewsCount | 0 |
| dateCreated | 2026-01-01T00:00:00.000Z |
| likesCount | 0 |
| commentsCount | 0 |
| hasOfficialAnswer | true |
| provider | 2gis |
| officialAnswerText | Thank you for your feedback. |
| reviewUrl | https://2gis.ru/moscow/firm/00000000/tab/reviews |
| photos | \["https://cdn.example.com/0000.jpg"] |

### How to use

Search mode combines a WHAT (queries and/or categories) with a WHERE (city, coordinates, or map area). Every field is optional. WHERE precedence: map area beats coordinates beats city.

#### By text query in a city

```json
{
  "mode": "search",
  "query": ["coffee shop", "bakery"],
  "city": "Moscow",
  "maxResults": 200
}
```

#### By category in a city

```json
{
  "mode": "search",
  "categoryQuery": ["Restaurants", "Pharmacies"],
  "city": "Almaty",
  "maxResults": 500
}
```

#### Around coordinates (radius)

```json
{
  "mode": "search",
  "query": ["pizza"],
  "latitude": "55.7558",
  "longitude": "37.6173",
  "radiusMeters": 1000,
  "maxResults": 100
}
```

#### In a map area (bounding box)

```json
{
  "mode": "search",
  "categoryQuery": ["Pharmacies"],
  "bbox": "37.55,55.70,37.70,55.80",
  "maxResults": 300
}
```

#### Everything in an area (no query)

```json
{
  "mode": "search",
  "latitude": "55.7558",
  "longitude": "37.6173",
  "radiusMeters": 500,
  "maxResults": 100
}
```

#### From 2GIS URLs or IDs

```json
{
  "mode": "url",
  "urls": [
    "https://2gis.ru/moscow/firm/70000001063551091",
    "https://2gis.ru/moscow/search/coffee",
    "70000001063551091"
  ],
  "maxReviews": 50
}
```

### Resume & recurring updates (incremental mode)

Two different features, both optional:

- **Resume from a previous run** (`resumeFromRunId`) continues ONE specific interrupted crawl: paste a run ID or dataset ID and this run skips places already collected there (and their reviews — a skipped place is never re-fetched at all).
- **Incremental mode** (`incrementalMode`, off by default) is for scheduling this actor on the SAME search again and again (daily, hourly, ...) and getting only what changed. The actor remembers the previous run itself in a key-value store — no run ID to paste. The first run returns everything as `NEW`; later runs return only `NEW` / `UPDATED` / `REAPPEARED` places and reviews by default.

**Two independent record grains.** This actor tracks places and reviews separately: a place getting a brand-new review does **not** make the place itself `UPDATED` (only the new review row is `NEW`), and a place's real fields changing does not touch its reviews' classification. Reviews do not get an `EXPIRED` state — review fetching is bounded by `maxReviews` and the review filters, so an absent review in one run's sample is not reliable evidence it was deleted upstream; only places can classify `EXPIRED` (present in a previous run, no longer found after a search reached its natural end this run).

Every place and review row gets four extra fields **only when `incrementalMode` is on**:

| Field | Meaning |
| --- | --- |
| changeType | `NEW`, `UPDATED`, `UNCHANGED`, `REAPPEARED`, or (places only) `EXPIRED`. |
| changedFields | Which fields differ from the last run (empty for NEW/UNCHANGED). |
| firstSeenAt | When this place/review was first seen by this monitoring campaign. |
| lastSeenAt | When it was last seen (refreshed every run it is scanned, even if suppressed). |

`emitUnchanged` (off by default) also returns — and bills — rows that did not change. `emitExpired` (off by default) also returns tombstoned places that disappeared, only when the run was not resuming, did not hit `maxResults`, and fully scanned every search/category/URL in this run. `stateKey` names the monitoring campaign explicitly; leave it blank and the actor derives one automatically from your search/category/URL and filter setup, so two different searches never share state.

```json
{
  "mode": "search",
  "categoryQuery": ["Restaurants"],
  "city": "Moscow",
  "maxReviews": 10,
  "incrementalMode": true,
  "emitUnchanged": false,
  "emitExpired": true
}
```

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| mode | string | search | search or url. |
| query | array | \["кофейня"] | WHAT to find, as text. Each query runs separately. Optional. |
| categoryQuery | array | \[] | WHAT to find, as category names. Optional, combines with query. |
| city | string | Москва | WHERE, by city. Ignored if coordinates or bbox are set. |
| latitude | string | | WHERE, center latitude. Set with longitude. Overrides city. |
| longitude | string | | Center longitude. Set with latitude. |
| radiusMeters | integer | 1000 | Radius in meters around the point (max 40000). |
| bbox | string | | WHERE, bounding box lon1,lat1,lon2,lat2. Overrides city and coordinates. |
| urls | array | | URL mode: 2GIS place, search, building links, short links, or raw IDs. |
| language | string | ru | Response language for names and content. |
| sortBy | string | relevance | relevance, rating, or distance. |
| minRating | string | | Keep only places at or above this rating. |
| minReviews | integer | | Keep only places with at least this many reviews. |
| onlyWithPhone | boolean | false | Skip places without a phone. |
| onlyWithWebsite | boolean | false | Skip places without a website. |
| skipAds | boolean | false | Skip promoted entries. |
| maxReviews | integer | 0 | Reviews per place. 0 disables review fetching. |
| reviewsSort | string | date\_edited | Order of fetched reviews. |
| reviewsProvider | string | all | Keep all sources, 2gis only, or flamp only. |
| reviewsRating | string | all | Keep all, only positive (4-5), or only negative (1-3). |
| reviewsMinRating | string | | Keep only reviews at or above this star rating. |
| reviewsWithAnswer | boolean | false | Keep only reviews that have an official reply. |
| reviewsStartDate | string | | Keep only reviews created on or after YYYY-MM-DD. |
| reviewsKeyword | string | | Keep only reviews whose text contains this phrase. |
| includePhotos | boolean | true | Include photo URLs in place records. |
| maxResults | integer | 10 | Total places across all queries (shared fairly across them). 0 = unlimited. |
| proxy | object | Apify datacenter | Proxy configuration. |
| resumeFromRunId | string | | Continue one interrupted crawl by run/dataset ID. |
| incrementalMode | boolean | false | Recurring monitoring: classify places/reviews as NEW/UPDATED/UNCHANGED/REAPPEARED/EXPIRED against the actor's own remembered state. |
| stateKey | string | | Name the incremental monitoring campaign. Auto-derived when blank. |
| emitUnchanged | boolean | false | Also return (and bill) unchanged rows in incremental mode. |
| emitExpired | boolean | false | Also return (and bill) places no longer found, in incremental mode. |

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the 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.

**What gets written to the connector:** a condensed, human-readable **summary** of each record — not the full JSON. Each item becomes one entry with a **title** and its key fields flattened to plain text. The **complete record always stays in the Apify dataset**.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

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

### Output example

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

```json
{
  "recordType": "place",
  "id": "00000000",
  "name": "Sample Cafe",
  "url": "https://2gis.ru/city/firm/00000000",
  "rating": 4.8,
  "reviewCount": 0,
  "primaryRubric": "Cafes",
  "rubrics": ["Cafes", "Coffee shops"],
  "phone": "+70000000000",
  "phones": ["+70000000000"],
  "email": "contact@example.com",
  "website": "http://example.com",
  "whatsapp": "https://wa.me/70000000000",
  "telegram": "https://t.me/example",
  "instagram": "https://instagram.com/example",
  "vk": "https://vk.com/example",
  "fullAddress": "City, Sample Street, 1",
  "country": "Sample Country",
  "region": "Sample Region",
  "city": "Sample City",
  "district": "Sample District",
  "street": "Sample Street",
  "houseNumber": "1",
  "postcode": "000000",
  "latitude": 55.0000,
  "longitude": 37.0000,
  "is24x7": false,
  "hoursText": "Mon: 09:00-21:00; Tue: 09:00-21:00; Wed: 09:00-21:00; Thu: 09:00-21:00; Fri: 09:00-22:00; Sat: 10:00-22:00; Sun: closed",
  "hours": {
    "Monday": { "status": "open", "intervals": [{ "from": "09:00", "to": "21:00" }] },
    "Sunday": { "status": "closed", "intervals": [] }
  },
  "photos": ["https://cdn.example.com/0000.jpg"],
  "photoCount": 1,
  "orgName": "Sample Org",
  "orgBranchCount": 1,
  "isPromoted": false,
  "attributesByTag": { "food_service_food_european": "European cuisine" }
}
```

### Plan requirement

This actor runs on the default Apify datacenter proxy, which is available on every plan including the free tier, so there is no premium proxy requirement to get started. Residential proxy is optional and only useful for very large repeated runs; when selected, the actor rotates the exit country (your chosen country first, then nearby ones) on a rejected connection and fails over to a backup connection after repeated failures, so a single flagged exit does not stall a run. The 2GIS platform itself caps a single query near 3000 results, so to gather more places for a city use several narrower queries, categories, or map areas. Reviews and photos are optional and only add work when you enable them.

# Actor input Schema

## `mode` (type: `string`):

search = find places by query, category, city, coordinates, or map area (any combination). url = scrape specific 2GIS links or IDs.

## `query` (type: `array`):

WHAT to find, as free text, for example coffee shop, dentist, hotel. Each query runs separately. Optional: leave empty (and no categories) to return every place in the chosen area.

## `categoryQuery` (type: `array`):

WHAT to find, as category names, for example Restaurants, Pharmacies, Car repair. Each is matched against the 2GIS category tree and runs separately. Optional, and combine freely with queries.

## `city` (type: `string`):

Where to look, by city name, for example Moscow, Москва, Almaty, Dubai. Ignored if you provide coordinates or a map area.

## `latitude` (type: `string`):

Search around a center point. Latitude, for example 55.7558. Provide together with longitude. Overrides city.

## `longitude` (type: `string`):

Center longitude, for example 37.6173. Provide together with latitude.

## `radiusMeters` (type: `integer`):

Search radius around the center point, in meters. Max 40000. Only used when latitude and longitude are set.

## `bbox` (type: `string`):

Rectangle: lon1,lat1,lon2,lat2 (south-west corner then north-east corner), for example 37.55,55.70,37.70,55.80. Overrides city and coordinates.

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

Response language for names and content.

## `sortBy` (type: `string`):

Result ordering. Distance only applies when searching around coordinates; otherwise it falls back to relevance.

## `minRating` (type: `string`):

Keep only places with rating at or above this value (0 to 5). Leave blank for no filter.

## `minReviews` (type: `integer`):

Keep only places with at least this many reviews. Leave blank for no filter.

## `onlyWithPhone` (type: `boolean`):

Skip places that have no phone number.

## `onlyWithWebsite` (type: `boolean`):

Skip places that have no website.

## `skipAds` (type: `boolean`):

Skip advertising or promoted entries.

## `urls` (type: `array`):

Paste 2GIS links: place pages (/firm/ID), searches (/search/query), buildings (/inside/ID), short links (go.2gis.com), or raw numeric firm IDs. Multiple supported. Used only when mode = url.

## `maxReviews` (type: `integer`):

How many reviews to fetch per place. 0 = do not fetch reviews. Reviews are pushed as separate records. Fetching reviews adds an extra request per place.

## `reviewsSort` (type: `string`):

Order of fetched reviews.

## `reviewsProvider` (type: `string`):

Which review source to keep: all, 2GIS only, or Flamp only.

## `reviewsRating` (type: `string`):

Keep all reviews, only positive (4 to 5 stars), or only negative (1 to 3 stars).

## `reviewsMinRating` (type: `string`):

Keep only reviews at or above this star rating (1 to 5). Leave blank for no limit.

## `reviewsWithAnswer` (type: `boolean`):

Keep only reviews that have an official reply from the place.

## `reviewsStartDate` (type: `string`):

Keep only reviews created on or after this date (YYYY-MM-DD). Leave blank for no limit.

## `reviewsKeyword` (type: `string`):

Keep only reviews whose text contains this word or phrase. Leave blank for no filter.

## `includePhotos` (type: `boolean`):

Include photo URLs available in the place record.

## `maxResults` (type: `integer`):

Maximum total places across all queries / URLs. 0 = unlimited (capped at the 2GIS per-query ceiling of about 3000).

## `proxy` (type: `object`):

2GIS APIs work on datacenter proxy, which is the cheapest and fastest option. Residential is optional for very large runs.

## `mcpConnectors` (type: `array`):

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON — the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue a large crawl of places without returning or charging for places already collected there. Use this after an interrupted run, or when continuing a large pull in another run. For recurring daily monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

Turn this on for daily or recurring monitoring. The first run returns all matching places (and their reviews) as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED places and reviews. Places and reviews are tracked separately, so a place with a brand-new review is not itself reported as UPDATED. Turn on "Emit unchanged" or "Emit expired" only when you also want those rows returned (and billed). State is kept separately for each search/category/URL and filter setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.

## `stateKey` (type: `string`):

Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the search/category/URL and filter settings — different searches then never mix state with each other.

## `emitUnchanged` (type: `boolean`):

Off by default. Turn on to also return places and reviews that have not changed since the last run, marked UNCHANGED. This returns — and bills — extra rows you already have, so leave it off unless you specifically want the full snapshot every run.

## `emitExpired` (type: `boolean`):

Off by default. Turn on to also return places 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 — not when Max places capped it or when Resume was used. Reviews do not have an EXPIRED state: review fetching is limited by Max reviews per place and the review filters, so an absent review is not reliable evidence it was deleted. This returns — and bills — extra synthetic rows, so leave it off unless you need expiry tracking.

## Actor input object example

```json
{
  "mode": "search",
  "query": [
    "кофейня"
  ],
  "categoryQuery": [],
  "city": "Москва",
  "radiusMeters": 1000,
  "language": "ru",
  "sortBy": "relevance",
  "onlyWithPhone": false,
  "onlyWithWebsite": false,
  "skipAds": false,
  "urls": [
    "https://2gis.ru/moscow/firm/70000001063551091"
  ],
  "maxReviews": 0,
  "reviewsSort": "date_edited",
  "reviewsProvider": "all",
  "reviewsRating": "all",
  "reviewsWithAnswer": false,
  "includePhotos": true,
  "maxResults": 10,
  "proxy": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 50,
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false
}
```

# Actor output Schema

## `places` (type: `string`):

Individual place records with 80+ fields including contacts, per-day hours, ratings, attributes and coordinates. Review records (when enabled) are added to the same dataset with a recordType of review.

## `output` (type: `string`):

Run summary with total places, reviews, pages fetched, duration and rate.

# 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 = {
    "mode": "search",
    "query": [
        "кофейня"
    ],
    "categoryQuery": [],
    "city": "Москва",
    "latitude": "",
    "longitude": "",
    "radiusMeters": 1000,
    "bbox": "",
    "minRating": "",
    "urls": [
        "https://2gis.ru/moscow/firm/70000001063551091"
    ],
    "maxReviews": 0,
    "reviewsMinRating": "",
    "reviewsStartDate": "",
    "reviewsKeyword": "",
    "maxResults": 10,
    "proxy": {
        "useApifyProxy": true
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/2gis-places-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 = {
    "mode": "search",
    "query": ["кофейня"],
    "categoryQuery": [],
    "city": "Москва",
    "latitude": "",
    "longitude": "",
    "radiusMeters": 1000,
    "bbox": "",
    "minRating": "",
    "urls": ["https://2gis.ru/moscow/firm/70000001063551091"],
    "maxReviews": 0,
    "reviewsMinRating": "",
    "reviewsStartDate": "",
    "reviewsKeyword": "",
    "maxResults": 10,
    "proxy": { "useApifyProxy": True },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/2gis-places-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "search",
  "query": [
    "кофейня"
  ],
  "categoryQuery": [],
  "city": "Москва",
  "latitude": "",
  "longitude": "",
  "radiusMeters": 1000,
  "bbox": "",
  "minRating": "",
  "urls": [
    "https://2gis.ru/moscow/firm/70000001063551091"
  ],
  "maxReviews": 0,
  "reviewsMinRating": "",
  "reviewsStartDate": "",
  "reviewsKeyword": "",
  "maxResults": 10,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false
}' |
apify call abotapi/2gis-places-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=abotapi/2gis-places-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6LCx6XnWL8wAEtko2/builds/FqBPnlN11OOCzleMd/openapi.json
