# 2GIS Scraper - Places & Business Data, Lowest Price (`dami_studio/2gis-places-scraper`) Actor

The lowest price on the market at $0.50 per 1,000 places. Search any city on 2GIS and get name, category, full address, coordinates, phone, website, rating and review count. Covers Russia, CIS and beyond. No account, no API key. Blocked or empty runs are never charged.

- **URL**: https://apify.com/dami\_studio/2gis-places-scraper.md
- **Developed by:** [Dami's Studio](https://apify.com/dami_studio) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 API

Pulls business listings out of [2GIS](https://2gis.ru) — the maps and business directory used across Russia, Kazakhstan, Uzbekistan and the rest of the CIS, plus the UAE and Cyprus.

Give it a search term and a city. You get back one row per place: name, category, full address, latitude/longitude, phone, email, website, rating, review count and the week's opening hours.

**$0.50 per 1,000 places.** That is the lowest price of any 2GIS scraper on the Apify Store. The next cheapest is $1.80 / 1,000; the popular ones sit at $4.50 / 1,000.

### What a row looks like

```json
{
  "placeId": "70000001041312679",
  "name": "Zotman Pizza, пиццерия",
  "nameShort": "Zotman Pizza",
  "brandName": "Zotman Pizza, служба доставки",
  "chainBranchCount": 21,
  "categoryPrimary": "Доставка еды",
  "categories": ["Пиццерии", "Доставка еды", "Быстрое питание"],
  "address": "улица Солянка, 1/2 ст1",
  "addressFull": "Москва, улица Солянка, 1/2 ст1",
  "addressComment": "1 этаж",
  "postcode": "109028",
  "country": "Россия",
  "region": "Москва",
  "city": "Москва",
  "cityAlias": "moscow",
  "district": "Басманный",
  "latitude": 55.75413,
  "longitude": 37.637247,
  "phone": "+74951502829",
  "phones": ["+74951502829", "+79266279464"],
  "website": "http://zotmanpizza.ru/",
  "websites": ["http://zotmanpizza.ru/"],
  "email": "infozotman@zotman.ru",
  "emails": ["infozotman@zotman.ru"],
  "socialProfiles": [{ "type": "vkontakte", "url": "https://vk.com/zotman_pizza" }],
  "rating": 4.5,
  "reviewCount": 199,
  "openingHours": { "Mon": { "working_hours": [{ "from": "10:00", "to": "22:00" }] } },
  "openingHoursText": "Mon: 10:00-22:00; Tue: 10:00-22:00; ...",
  "url": "https://2gis.ru/moscow/firm/70000001041312679",
  "searchQuery": "пиццерия",
  "position": 1,
  "scrapedAt": "2026-08-07T18:55:00.000Z"
}
```

Website links come out clean. 2GIS wraps every outbound link in a `link.2gis.ru` click tracker with its own `utm_` tags attached; this actor unwraps it and strips those tags, so you get `http://zotmanpizza.ru/` and not a 300-character redirect.

### Input

```json
{
  "searchQueries": ["кафе", "пиццерия"],
  "city": "Moscow",
  "maxItems": 200
}
```

| Field | What it does |
|---|---|
| `searchQueries` | One search term per line. |
| `city` | English or local spelling — `Moscow`, `Москва`, `Almaty`, `Dubai`. A numeric 2GIS city id also works. Leave empty to search the whole catalog. |
| `startUrls` | Optional. Paste 2GIS search pages (`https://2gis.ru/moscow/search/кафе`) or single place pages (`https://2gis.ru/moscow/firm/70000001044357973`). |
| `maxItems` | Hard cap on rows, 1–5000. You are charged per row returned. |
| `latitude` / `longitude` / `radiusMeters` | Search around a point instead of a whole city. |
| `locale` | Optional response language. Leave on Automatic unless you need something specific. |

Run it with no input at all and it returns a single labelled sample row so you can see the shape. That run is not charged.

### How much you get back

2GIS reports the match count for every search, and this actor pages through it 50 rows at a time. `кафе` in Moscow reports about 5,000 matches; `restaurant` in Dubai about 11,500. In practice 2GIS stops serving new pages somewhere around 5,000 rows per search term. To go deeper, split the job: search per district, per rubric, or use `latitude`/`longitude` with a small radius and walk a grid.

Field coverage, measured on a random 50-place sample in Moscow: phone 50/50, opening hours 50/50, rating 50/50, website 45/50, email 38/50. Emails are included at no extra charge — several other 2GIS actors bill those as a separate "add contacts" event.

### Countries

2GIS is a regional directory, not a global one. It covers Russia, Kazakhstan, Uzbekistan, Kyrgyzstan, Azerbaijan, Belarus, Georgia, Armenia, Tajikistan, Cyprus and the UAE. If you need places outside that list, 2GIS is the wrong source.

Search terms in the local language return noticeably more than English ones in Russian-speaking cities. `кафе` beats `cafe` in Moscow; in Dubai it is the other way around.

### Pricing

| Event | When | Price |
|---|---|---|
| Actor start | Once per run | $0.001 |
| Place | Each place row returned | $0.0005 ($0.50 / 1,000) |

Sample rows, error rows and diagnostics are never charged. A run that finds nothing costs you $0.001.

100 places = $0.051. 1,000 places = $0.501. 10,000 places = $5.001.

For comparison, at the time of writing: `zen-studio/2gis-places-scraper-api` charges $0.0045/place plus $0.007 per start, `tugelbay/2gis-scraper` $0.0045, `m_mamaev/2gis-places-scraper` $0.003 plus $0.03 per start, `piotrv1001/2gis-scraper` $0.0018.

### How it works

2GIS's own web front-end sits behind a JavaScript challenge, so scraping the HTML is a losing game. The data behind that page comes from 2GIS's public catalog API at `catalog.api.2gis.ru/3.0`, which answers plain JSON and is not challenged at all. This actor talks to that API directly using the same public web key 2GIS ships in its own front-end config, read live at start-up so a key rotation on their side does not need a redeploy. There is a built-in fallback key if the lookup ever fails.

No browser, no residential proxy, no headless Chrome. That is why it is cheap and why a 1,000-row run finishes in about half a minute.

Requests are made with a real Chrome TLS fingerprint (`impit`), which is what keeps the API answering consistently.

### Limits, stated honestly

- **Reviews and photos are not included.** You get `rating` and `reviewCount`, not the review text or images. Those are separate products.
- **~5,000 rows per search term.** 2GIS stops paging past roughly that depth. Split the search to go further.
- **The public web key can rotate.** The actor re-reads it on every run, so a rotation is usually invisible. If 2GIS ever revokes it outright, runs return an uncharged `KEY_REJECTED` diagnostic instead of silently returning nothing.
- **`rating` is the aggregate 2GIS score.** For chain branches, 2GIS also reports a company-wide rating; this actor returns the branch-level one.
- **Not a global directory.** See the country list above.

### FAQ

**Can I scrape 2GIS without an API key of my own?**
Yes. This actor uses the public key 2GIS's own website uses. You do not register anything.

**How do I get all cafes in a city?**
Set `city`, put `кафе` in `searchQueries`, and raise `maxItems`. Expect to top out around 5,000; beyond that, search per district or per rubric.

**Can I paste a 2GIS URL instead?**
Yes. `startUrls` accepts both search pages and individual place pages. Page numbers in a search URL are respected, so `.../search/кафе/page/3` starts from result 101.

**Does it return email addresses?**
Where 2GIS has them — about three quarters of listings in a Moscow sample. No extra charge.

**Is it faster than a browser scraper?**
Considerably. It is a JSON API call per 50 places, roughly one second each.

**What happens if my search returns nothing?**
You get one uncharged diagnostic row explaining why, and the run costs $0.001.

**Which is the cheapest 2GIS scraper on Apify?**
This one, at $0.50 per 1,000 places. Compare the pricing tab of any other 2GIS actor.

# Actor input Schema

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

What to look for on 2GIS, for example "pizza", "кафе", "dentist". One search per line. 2GIS is a Russian/CIS directory, so local-language terms return more.

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

City to search in. English or local spelling both work ("Moscow", "Москва", "Almaty", "Dubai"). You can also paste a numeric 2GIS city id. Leave empty to search the whole 2GIS catalog.

## `startUrls` (type: `array`):

Optional. Paste 2GIS search pages (https://2gis.ru/moscow/search/кафе) or single place pages (https://2gis.ru/moscow/firm/70000001044357973). Works alongside the fields above.

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

Hard cap on rows returned across all searches (1-5000). You are charged per place returned.

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

Search around a point instead of a whole city. Example: 55.7558

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

Used together with latitude. Example: 37.6173

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

Radius around the latitude/longitude point. Ignored unless both coordinates are set.

## `locale` (type: `string`):

Optional 2GIS locale for names and categories. Leave as Automatic unless you specifically need another language; not every locale is available in every country.

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

Optional. The actor already uses its own egress; leave this alone unless you need to exit from a specific network.

## Actor input object example

```json
{
  "searchQueries": [
    "кафе"
  ],
  "city": "Moscow",
  "startUrls": [],
  "maxItems": 50,
  "radiusMeters": 1000,
  "locale": "",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# 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": [
        "кафе"
    ],
    "city": "Moscow",
    "startUrls": [],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("dami_studio/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 = {
    "searchQueries": ["кафе"],
    "city": "Moscow",
    "startUrls": [],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("dami_studio/2gis-places-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": [
    "кафе"
  ],
  "city": "Moscow",
  "startUrls": [],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call dami_studio/2gis-places-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/2gis-places-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/yxxOZZeWjU1p89U1e/builds/b9mHTZLPkE740eLRU/openapi.json
