# 2GIS Scraper — Business Leads: Phones, Emails, Reviews & Hours (`logiover/2gis-scraper`) Actor

Scrape 2GIS business listings by keyword or category across any city. Extract names, phones, emails, websites, social links, addresses, ratings, reviews and opening hours for B2B lead generation. No API key, no login.

- **URL**: https://apify.com/logiover/2gis-scraper.md
- **Developed by:** [Logiover](https://apify.com/logiover) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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 Scraper — Business Leads: Phones, Emails, Reviews & Opening Hours (No API Key)

![Apify Actor](https://img.shields.io/badge/Apify-Actor-00A67E?logo=apify&logoColor=white) ![No API key](https://img.shields.io/badge/No%20API%20key-required-2ea44f) ![Pay per result](https://img.shields.io/badge/Pricing-Pay%20per%20result-1C7ED6) ![Category](https://img.shields.io/badge/Category-Lead%20Generation-8B5CF6) ![Export](https://img.shields.io/badge/Export-JSON%20%7C%20CSV%20%7C%20Excel-F59E0B)

An **unofficial 2GIS scraper** and structured **2GIS business-data API** in a single Apify Actor. Pull local-business leads from **2GIS** (2gis.ru) by **keyword** or by **category**, across one city or **many cities at once** — with **phones, emails, websites, social links, addresses, GPS coordinates, ratings, review counts and opening hours** on every row. Powered directly by **2GIS's own public Catalog API** — no API key, no login, no cookies, no headless browser. Just fast HTTP and clean, flat JSON you can export to CSV, Excel or JSON. **Three modes share one input form**, and every result is tagged with `_mode` so you can mix modes in a single dataset and filter later.

> ### 🏆 Why this 2GIS scraper?
> **3 modes in 1 Actor** (keyword search, whole-category sweep, batch details) · powered by 2GIS's own Catalog API · **thousands of businesses per city** · **multi-city batch** (loop many regions in one run) · full contact extraction (phones + emails + VK/Telegram/Instagram/WhatsApp) · clean **split address** fields (country / region / city / district) · **keyless with automatic key refresh** — no browser and no key to manage. The unofficial **2GIS API alternative** for lead generation, local SEO, market mapping and AI agents.

---

### ✨ What this Actor does / Key features

- 🔎 **Keyword search** — find every business matching a term (`restaurant`, `dentist`, `coffee`, `аптека`, `hotel`…), optionally scoped to one or more cities; paginates the full result set (thousands of matches).
- 🗂️ **Whole-category sweep** — browse an entire 2GIS **rubric** (category) across one or many cities via `rubric_id` + `region_id` — e.g. every restaurant in Moscow (3,900+), every pharmacy, every beauty salon.
- 🌍 **Multi-city batch** — pass an array of region IDs (and, in category mode, an array of rubric IDs) and the Actor loops the **cross-product** so **one run sweeps many cities and verticals** at once.
- ☎️ **Full contact extraction** — `phone` + all `phones[]`, `email` + all `emails[]`, `website` + all `websites[]`, plus **VK, Telegram, Instagram, WhatsApp and Facebook** links — the real value for B2B lead gen.
- 📍 **Clean split address** — `country`, `region`, `city`, `district`, `address`, `postcode`, plus precise `lat`/`lon` — geo fields most competitors flatten away.
- ⭐ **Ratings & reviews** — `ratingValue` and `reviewCount` on every listing, straight from 2GIS/Flamp.
- 🕒 **Opening hours** — a human-readable `workingHours` string, an `is24x7` flag and a structured per-day `scheduleStructured` object.
- 🧩 **Batch details** — feed many 2GIS firm/branch IDs at once with `byId` for enrichment.
- 🔑 **Keyless & self-healing** — the Actor mints 2GIS's public web key itself at startup (with a built-in fallback), so you never supply a key. No browser, no OAuth; every item carries `_mode` and `scrapedAt` (ISO 8601).
- 🗂️ **3 pre-built dataset views** — Overview, Leads (contacts) and Location — slice the data with zero post-processing.

#### The 3 modes

| Mode | What it returns |
|---|---|
| `search` | Free-text business search by keyword (`q`), optional multi-city scope — highest volume |
| `category` | Whole category (rubric) across one or more cities via `rubric_id` + `region_id` |
| `byId` | Full details for one or many 2GIS firm/branch IDs (batch) |

### 🚀 Quick start (3 steps)

1. **Pick a Mode** — start with `search` and a keyword to build a lead list, or `category` with a `rubric_id` + `region_id` to sweep a whole vertical of a city.
2. **Fill the fields that mode needs** — the input form shows which apply (a `query` keyword, a `regionId` city, a `rubricId` category, or a batch of `ids`).
3. **Run & export** — download results as **JSON, CSV, Excel, HTML, RSS or JSON Lines**, or pull them via the Apify API.

Empty input works too — it returns **Moscow restaurants** so you can see real rows immediately.

### 📥 Input

Pick a `mode`, then fill only the fields that mode needs. Nothing is required.

#### Example — keyword search for restaurants in Moscow
```json
{
  "mode": "search",
  "query": "restaurant",
  "regionId": "32",
  "maxResults": 600
}
````

#### Example — sweep an entire category (all restaurants in Moscow)

```json
{
  "mode": "category",
  "rubricId": "164",
  "regionId": "32",
  "maxResults": 2000
}
```

#### Example — multi-city lead sweep (dentists in 3 cities)

```json
{
  "mode": "search",
  "query": "dentist",
  "regionIds": ["32", "2", "1"],
  "maxResults": 1500
}
```

#### Example — batch details by 2GIS ID

```json
{
  "mode": "byId",
  "ids": ["70000001031659781", "70000001006481143"]
}
```

| Field | Type | Default | Used by | Description |
|-------|------|---------|---------|-------------|
| `mode` | string (select) | `search` | all | `search`, `category` or `byId`. |
| `query` | string | `кафе` | search | Free-text business keyword (a type or brand). |
| `regionId` | string | — | search, category | 2GIS region/city ID, e.g. `32` = Moscow. |
| `regionIds` | array | `[]` | search, category | Many region IDs to sweep several cities in one run. |
| `rubricId` | string | `164` | category | 2GIS category (rubric) ID, e.g. `164` = Restaurants. |
| `rubricIds` | array | `[]` | category | Many rubric IDs to sweep several categories. |
| `id` | string | — | byId | A single 2GIS firm/branch ID. |
| `ids` | array | `[]` | byId | Batch of 2GIS firm/branch IDs. |
| `maxResults` | integer | `200` | all | Row cap across the whole run; drives pagination. |
| `proxyConfiguration` | object | Apify Proxy (auto) | all | Proxy settings; default works well. |

#### Finding region and rubric IDs

- **Region (city) ID** appears in a city's 2gis.ru URL and in the `regionId` you pass. Common ones: `32` Moscow · `2` Saint Petersburg · `1` Novosibirsk · `4` Yekaterinburg · `54` Kazan.
- **Rubric (category) ID**: the easiest way is to run a `search` first and read the `categories` field on the results, or copy the ID from a 2gis.ru category URL. Common ones: `164` Restaurants · `161` Cafes · `165` Bars · `271` Pharmacies · `327` Beauty salons.

### 📤 Output — what data you get

Results stream to the dataset; every item is a flattened business lead tagged with `_mode` and `scrapedAt`. Contacts are the headline value, so phones, emails and socials are all extracted.

#### Field reference

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | 2GIS firm/branch ID. |
| `name` | string | Business name. |
| `type` | string | Object type (`branch`, `building`, `admin`, `street`…). |
| `categories` | string | All 2GIS categories (rubrics), comma-joined. |
| `primaryCategory` | string | The primary category only. |
| `address` | string | Full street address (`address_name`). |
| `addressComment` | string | Extra locator (floor, entrance…). |
| `postcode` | string | Postal code. |
| `country` | string | Country (from `adm_div`). |
| `region` | string | Region / oblast (from `adm_div`). |
| `city` | string | City (from `adm_div`). |
| `district` | string | City district (from `adm_div`). |
| `lat` | number | Latitude. |
| `lon` | number | Longitude. |
| `phone` | string | First / primary phone. |
| `phones` | array | All phone numbers. |
| `website` | string | Primary website. |
| `websites` | array | All websites. |
| `email` | string | First email. |
| `emails` | array | All emails. |
| `vk` | string | VKontakte URL. |
| `telegram` | string | Telegram URL. |
| `instagram` | string | Instagram URL. |
| `whatsapp` | string | WhatsApp contact. |
| `facebook` | string | Facebook URL. |
| `workingHours` | string | Human-readable opening hours (e.g. `Mon 09:00-22:00; Sat 10:00-23:00`, or `24/7`). |
| `is24x7` | boolean | Whether the business is open 24/7. |
| `scheduleStructured` | object | Per-day `working_hours[]` (`{from,to}`) object. |
| `ratingValue` | number | Average rating. |
| `reviewCount` | number | Number of reviews. |
| `description` | string | Short description, when present. |
| `orgId` | string | Parent organization ID (chains). |
| `branchCount` | number | Number of branches of the parent org. |
| `twogisUrl` | string | Canonical `https://2gis.ru/firm/<id>` link. |
| `_mode` | string | Which mode produced the row. |
| `scrapedAt` | string | ISO-8601 timestamp. |

#### Output example

```json
{
  "_mode": "category",
  "rubricId": "164",
  "regionId": "32",
  "id": "70000001031659781",
  "name": "Мясо&Рыба, ресторан",
  "type": "branch",
  "categories": "Рестораны, Доставка еды",
  "primaryCategory": "Рестораны",
  "address": "улица Архитектора Щусева, 4 к1",
  "addressComment": "1 этаж",
  "postcode": "115432",
  "country": "Россия",
  "region": "Москва",
  "city": "Москва",
  "district": "Даниловский",
  "lat": 55.766672,
  "lon": 37.599969,
  "phone": "+74956409640",
  "phones": ["+74956409640", "+79917271660"],
  "website": "delikateska.ru",
  "websites": ["delikateska.ru", "dzen.ru"],
  "email": "mail@delikateska.ru",
  "emails": ["mail@delikateska.ru"],
  "vk": "https://vk.com/delikateska",
  "telegram": "https://t.me/delikateska_ru",
  "instagram": null,
  "whatsapp": null,
  "facebook": null,
  "workingHours": "24/7",
  "is24x7": true,
  "scheduleStructured": null,
  "ratingValue": 4.8,
  "reviewCount": 4130,
  "description": null,
  "orgId": "4504136499435533",
  "branchCount": 11,
  "twogisUrl": "https://2gis.ru/firm/70000001031659781",
  "scrapedAt": "2026-07-24T12:00:00.000Z"
}
```

### 💡 Use cases

- **B2B lead generation** — build targeted lists of local businesses (restaurants, dentists, gyms, contractors…) with phones, emails and social channels ready for outreach or CRM import.
- **Local SEO & citation building** — audit a category across a city, check names/addresses/phones (NAP), find businesses with missing websites or hours.
- **Market & competitor mapping** — pull every competitor in a vertical per city, plot them by `lat`/`lon`, compare ratings and review volume.
- **Sales territory planning** — sweep multiple cities in one run and segment leads by district, category and rating.
- **Data enrichment** — feed your own business IDs into `byId` to attach fresh contacts, hours and ratings.
- **AI agents & RAG** — wire the Actor as a tool so an LLM can answer "list top-rated pharmacies in Kazan with phone numbers" and return structured leads.

### 👥 Who uses it

Sales & lead-gen teams building outreach lists · local-SEO and marketing agencies · market researchers and analysts mapping verticals · data teams enriching a CRM · directory and aggregator builders · AI-agent developers wiring 2GIS as a data tool.

### 💰 Pricing

This Actor runs on a simple **pay-per-result** model — you pay for the leads you extract, with no separate Apify platform fees to calculate. It uses no browser (just HTTP against 2GIS's JSON API), so runs are quick and lightweight. Try it on the **free tier** first, then scale up. See the **Pricing** tab on this page for the current rate.

### ⚙️ How it works

The Actor calls **2GIS's own public Catalog API** (`catalog.api.2gis.com`) — the same endpoint the 2gis.ru web map uses. That API needs a public "web API key", which the Actor **mints itself** at startup by reading the current `webApiOutsourceKey` from 2gis.ru (with a known-good built-in fallback), so **you never supply a key**. In `search` and `category` modes it paginates 50 results per page until it hits `maxResults` or the last page, looping every region (and rubric) you pass. Requests go through **Apify Proxy (residential group)** with a fresh IP per retry — the 2GIS API blocks datacenter IPs, so residential proxying is handled automatically for you. There is a ~4-minute time budget: on very large sweeps it pushes what it has collected and exits successfully rather than running forever.

### 🧭 Tips for best results

- **Scope by city for cleaner leads.** Pass a `regionId` (e.g. `32` for Moscow) so results are one city; leave it empty only if you want the broadest possible match.
- **Use `category` for exhaustive coverage.** Keyword search is great for a term; `rubric_id` + `region_id` returns the *entire* vertical of a city (thousands of rows).
- **Sweep many cities in one run** with `regionIds`, and many verticals with `rubricIds` — the Actor loops the cross-product automatically.
- **Discover rubric IDs** by running a quick `search` first and reading the `categories` field, then switch to `category` mode with that ID.
- **Raise `maxResults`** to pull a whole city; keep it modest (100–500) for a fast, cheap sample.
- **Filter for leads with contacts** after export by keeping rows where `phone` or `email` is non-null.
- **Coordinates are real numbers** (`lat`/`lon`) — drop them straight into a map or geo join.
- **Chains** share an `orgId` and expose `branchCount`; de-dupe on `orgId` if you only want one row per brand.
- **Localized text**: 2GIS data is primarily Russian/CIS; names and categories come back in the local language.
- **Re-run on a schedule** to keep phones, hours and ratings fresh.

### 🔌 Integrations

Push 2GIS leads anywhere Apify connects:

- **Google Sheets** — export the dataset straight into a sheet for the sales team.
- **Slack** — notify a channel when a new sweep finishes.
- **Zapier / Make / n8n** — trigger workflows on new items (add to CRM, enrich, email).
- **Webhooks** — POST results to your own endpoint on run completion.
- **Schedules** — refresh a city/category dataset daily or weekly.
- **Apify API & clients** — pull items on demand from your stack (see below).

### 🧑‍💻 API usage

Run the Actor and fetch results from your own code. Get your token from **Apify Console → Settings → Integrations**.

**cURL**

```bash
curl -X POST "https://api.apify.com/v2/acts/logiover~2gis-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"mode":"category","rubricId":"164","regionId":"32","maxResults":500}'
```

**Node.js** (Apify client)

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });

const run = await client.actor('logiover/2gis-scraper').call({
  mode: 'search',
  query: 'restaurant',
  regionId: '32',
  maxResults: 600,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, 'leads');
```

**Python** (Apify client)

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")

run = client.actor("logiover/2gis-scraper").call(run_input={
    "mode": "category",
    "rubricId": "164",
    "regionId": "32",
    "maxResults": 500,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["name"], item.get("phone"))
```

### 🤖 Use with AI agents (MCP)

This Actor works as a tool for LLM agents via the **Apify MCP server**, so an assistant can fetch live 2GIS leads on demand. Point your MCP client at Apify, expose `logiover/2gis-scraper`, and prompt naturally — e.g. *"Get me 100 top-rated coffee shops in Saint Petersburg (region 2) with phone numbers and websites, as a table."* The agent runs the Actor and reads the structured dataset back.

### ❓ Frequently Asked Questions

#### Do I need a 2GIS API key or account?

No. This is an unofficial 2GIS scraper that reads publicly available data through 2GIS's own Catalog API. The Actor mints the required public web key itself (with a built-in fallback), so you only need an Apify account — no 2GIS key, no login, no cookies.

#### Is this a 2GIS API or a 2GIS API alternative?

Both, effectively. It works as an unofficial **2GIS API** and a practical **2GIS data-export alternative**: send structured input (keyword, category, IDs), get structured JSON back with contacts, geo, ratings and hours — without applying for 2GIS's official developer API.

#### How do I scrape 2GIS phone numbers and emails?

Every row includes `phone` (first) and `phones[]` (all), plus `email` and `emails[]` when the business publishes them. Use `search` with a keyword or `category` with a rubric ID, then filter exported rows to those with a non-empty `phone` or `email`.

#### Which cities and countries does it cover?

2GIS covers Russia and several CIS/other markets (e.g. Kazakhstan, Kyrgyzstan, the UAE, and more). Scope any city with its `regionId` (e.g. `32` Moscow, `2` Saint Petersburg), or sweep several at once with `regionIds`.

#### How do I find a region ID or a rubric (category) ID?

A region ID appears in a city's 2gis.ru URL. For a rubric ID, run a quick `search` first and read the `categories` field on the results, or copy the ID from a 2gis.ru category URL. Common rubrics: `164` restaurants, `161` cafes, `271` pharmacies.

#### How many businesses can one run return?

A single city category can hold **thousands** of businesses (e.g. 3,900+ restaurants in Moscow). The Actor paginates up to your `maxResults`, and with `regionIds` / `rubricIds` you can sweep many cities and verticals in one run.

#### Why are some fields empty (null)?

Not every business publishes every detail. A listing may have no email, no website, or no posted hours — those fields come back `null` while the rest of the row is fully populated. Contacts are extracted whenever 2GIS exposes them.

#### Can I get opening hours in a structured form?

Yes. `workingHours` is a readable string, `is24x7` is a boolean, and `scheduleStructured` is a per-day object with `{from,to}` spans — use whichever fits your pipeline.

#### How do I export 2GIS data to CSV, JSON or Excel?

Run any mode and download the dataset as CSV, JSON, Excel (XLSX), HTML, RSS or JSON Lines from the run page, or pull it via the Apify API. This makes it a simple 2GIS data-export and business-directory tool.

#### How fast is it, and does it use a browser?

It uses no browser — just HTTP against 2GIS's JSON API (through residential proxies, which the 2GIS API requires) — so it's efficient. Large sweeps stop at a ~4-minute time budget and still return everything collected so far.

#### Is it legal to scrape 2GIS?

The Actor collects only publicly available business data served by 2GIS's own endpoints. You are responsible for using the data in compliance with 2GIS's terms of service, applicable privacy laws (e.g. for personal data) and any local regulations.

### ⚖️ Is it legal?

This Actor extracts only **publicly available** business information served by 2GIS's own public endpoints, and is intended for legitimate use such as lead generation, market research, local SEO and dataset-building. It does not bypass any login or access control. You are responsible for complying with **2GIS's terms of service**, applicable **data-protection/privacy laws** when handling any personal data (for example, contacting individuals), and any other relevant local regulations.

### 🔗 Related scrapers by logiover

Building a local-business or lead-gen dataset? Pair 2GIS with the rest of the suite:

| Actor | What it does |
|---|---|
| [B2B Lead Scraper](https://apify.com/logiover/b2b-lead-scraper) | Sector + country B2B leads (company, person, email) from open map data |
| [LinkedIn Company Scraper](https://apify.com/logiover/linkedin-company-scraper) | Company profiles & firmographics, no login |
| [Meta Ad Library Scraper](https://apify.com/logiover/meta-ad-library-scraper) | Advertiser ads, spend and impressions |
| [Company Registry Scrapers](https://apify.com/logiover) | Official company registries across many countries |

👉 Browse all **[logiover scrapers on Apify Store](https://apify.com/logiover)** — 180+ actors across real estate, jobs, crypto, social media & B2B data.

***

### 📝 Changelog

#### 2026-07-24

- 🎉 Initial release: three 2GIS modes (keyword search, whole-category sweep, batch details) over 2GIS's public Catalog API — keyless with automatic web-key refresh, multi-city/multi-category batch, full contact extraction (phones + emails + VK/Telegram/Instagram/WhatsApp), clean split address (country/region/city/district), coordinates, ratings, review counts and opening hours. Three dataset views: Overview, Leads and Location.

# Actor input Schema

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

How to pull businesses from 2GIS.

• **search** — free-text business search by keyword (e.g. "restaurant", "dentist", "кафе"), optionally scoped to one or more cities; paginates through thousands of matches (highest volume)
• **category** — browse an entire category (rubric) across one or more cities via rubric\_id + region\_id; sweeps whole verticals of a city
• **byId** — full details for one or more 2GIS firm/branch IDs (batch)

## `query` (type: `string`):

Free-text business keyword for **search** mode — a business type or brand (e.g. `restaurant`, `dentist`, `coffee`, `аптека`, `hotel`). Empty input defaults to "кафе" (cafe).

## `regionId` (type: `string`):

2GIS region (city) ID to scope results, e.g. `32` = Moscow, `1` = Novosibirsk, `2` = Saint Petersburg. Used by **search** (optional) and **category** (recommended). Find a city's ID in its 2gis.ru URL. For many cities at once, use the list below.

## `regionIds` (type: `array`):

Sweep MANY cities in one run — array of 2GIS region IDs. The Actor loops every region (× every rubric in category mode). Example: `["32","2","1"]` = Moscow + St Petersburg + Novosibirsk.

## `rubricId` (type: `string`):

2GIS rubric (category) ID for **category** mode, e.g. `164` = Restaurants, `161` = Cafes, `327` = Beauty salons, `271` = Pharmacies, `165` = Bars. Empty input defaults to `164` (Restaurants). Discover IDs by running a **search** first and reading the categories, or from a 2gis.ru category URL.

## `rubricIds` (type: `array`):

Array of 2GIS rubric IDs to sweep several categories in one run (looped × every region). Example: `["164","161","165"]` = restaurants + cafes + bars.

## `id` (type: `string`):

A single 2GIS firm/branch ID for **byId** mode, e.g. `70000001031659781`. The digits in a 2gis.ru/firm/<id> URL.

## `ids` (type: `array`):

Array of 2GIS firm/branch IDs for batch **byId** lookups. The Actor fetches them in efficient batches.

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

Upper bound on rows returned across all regions/categories in the run. Drives pagination. Keep it modest to stay fast & cheap; raise it to pull whole cities (a single Moscow category can hold thousands).

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

Apify Proxy settings. 2GIS's catalog API blocks datacenter IPs, so this Actor uses **Residential** proxies by default (a fresh IP per retry) — leave the default for reliable results. You can override the groups if you have your own residential proxy setup.

## Actor input object example

```json
{
  "mode": "search",
  "query": "restaurant",
  "regionId": "32",
  "regionIds": [],
  "rubricId": "164",
  "rubricIds": [],
  "id": "70000001031659781",
  "ids": [],
  "maxResults": 200,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Full results dataset. Use the Leads view for contacts (phones/emails/socials) and the Location view for address & coordinates.

# 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": "restaurant",
    "regionIds": [],
    "rubricIds": [],
    "ids": [],
    "maxResults": 200,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("logiover/2gis-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": "restaurant",
    "regionIds": [],
    "rubricIds": [],
    "ids": [],
    "maxResults": 200,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("logiover/2gis-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": "restaurant",
  "regionIds": [],
  "rubricIds": [],
  "ids": [],
  "maxResults": 200,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call logiover/2gis-scraper --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "2GIS Scraper — Business Leads: Phones, Emails, Reviews & Hours",
        "description": "Scrape 2GIS business listings by keyword or category across any city. Extract names, phones, emails, websites, social links, addresses, ratings, reviews and opening hours for B2B lead generation. No API key, no login.",
        "version": "1.0",
        "x-build-id": "gfFT1iQQRQlwmbXG6"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/logiover~2gis-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-logiover-2gis-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/logiover~2gis-scraper/runs": {
            "post": {
                "operationId": "runs-sync-logiover-2gis-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/logiover~2gis-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-logiover-2gis-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "mode": {
                        "title": "Mode",
                        "enum": [
                            "search",
                            "category",
                            "byId"
                        ],
                        "type": "string",
                        "description": "How to pull businesses from 2GIS.\n\n• **search** — free-text business search by keyword (e.g. \"restaurant\", \"dentist\", \"кафе\"), optionally scoped to one or more cities; paginates through thousands of matches (highest volume)\n• **category** — browse an entire category (rubric) across one or more cities via rubric_id + region_id; sweeps whole verticals of a city\n• **byId** — full details for one or more 2GIS firm/branch IDs (batch)",
                        "default": "search"
                    },
                    "query": {
                        "title": "Search query",
                        "type": "string",
                        "description": "Free-text business keyword for **search** mode — a business type or brand (e.g. `restaurant`, `dentist`, `coffee`, `аптека`, `hotel`). Empty input defaults to \"кафе\" (cafe)."
                    },
                    "regionId": {
                        "title": "Region / city ID",
                        "type": "string",
                        "description": "2GIS region (city) ID to scope results, e.g. `32` = Moscow, `1` = Novosibirsk, `2` = Saint Petersburg. Used by **search** (optional) and **category** (recommended). Find a city's ID in its 2gis.ru URL. For many cities at once, use the list below."
                    },
                    "regionIds": {
                        "title": "Region / city IDs (multi-city batch)",
                        "type": "array",
                        "description": "Sweep MANY cities in one run — array of 2GIS region IDs. The Actor loops every region (× every rubric in category mode). Example: `[\"32\",\"2\",\"1\"]` = Moscow + St Petersburg + Novosibirsk.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "rubricId": {
                        "title": "Category (rubric) ID",
                        "type": "string",
                        "description": "2GIS rubric (category) ID for **category** mode, e.g. `164` = Restaurants, `161` = Cafes, `327` = Beauty salons, `271` = Pharmacies, `165` = Bars. Empty input defaults to `164` (Restaurants). Discover IDs by running a **search** first and reading the categories, or from a 2gis.ru category URL."
                    },
                    "rubricIds": {
                        "title": "Category (rubric) IDs (multi-category batch)",
                        "type": "array",
                        "description": "Array of 2GIS rubric IDs to sweep several categories in one run (looped × every region). Example: `[\"164\",\"161\",\"165\"]` = restaurants + cafes + bars.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "id": {
                        "title": "2GIS ID",
                        "type": "string",
                        "description": "A single 2GIS firm/branch ID for **byId** mode, e.g. `70000001031659781`. The digits in a 2gis.ru/firm/<id> URL."
                    },
                    "ids": {
                        "title": "2GIS IDs (batch)",
                        "type": "array",
                        "description": "Array of 2GIS firm/branch IDs for batch **byId** lookups. The Actor fetches them in efficient batches.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "maxResults": {
                        "title": "Max results",
                        "minimum": 1,
                        "maximum": 100000,
                        "type": "integer",
                        "description": "Upper bound on rows returned across all regions/categories in the run. Drives pagination. Keep it modest to stay fast & cheap; raise it to pull whole cities (a single Moscow category can hold thousands).",
                        "default": 200
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Apify Proxy settings. 2GIS's catalog API blocks datacenter IPs, so this Actor uses **Residential** proxies by default (a fresh IP per retry) — leave the default for reliable results. You can override the groups if you have your own residential proxy setup.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
