# 2GIS Places Scraper (`shareze001/2gis-places`) Actor

Scrape places/merchants from 2GIS (2gis.kz) by listing URL or keyword search. Returns name, address, rating, reviews, coordinates, images, and more.

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

## Pricing

from $2.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.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

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

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

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

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

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

# README

## 2GIS Places Scraper

Collect places and merchants from [2GIS Kazakhstan](https://2gis.kz) — cafés, shops, services, and more — with ratings, addresses, photos, and categories ready for export.

Results are written to the dataset **incrementally** (each listing page as a batch; or one-by-one when `enrichContacts` is on), so a cancelled run still keeps what was already scraped.

### Features

- Search by **keyword** in a city (e.g. `кафе` in Almaty)
- Or scrape from a **listing / rubric URL** you already have
- Returns name, address, coordinates, rating, reviews, weekly schedule, contacts, images, rubrics, and attributes
- Caps results with `size` so you only pay for what you need
- Optional `requireImages` to keep only places that have photos
- Optional `enrichContacts` to fetch phones / social links from each firm page (slower)

### How to use

Provide either listing URLs **or** a keyword + city. URLs win when both are set.

#### Keyword search

```json
{
  "city": "almaty",
  "keyword": "кафе",
  "size": 50
}
```

#### Listing URL

```json
{
  "urls": [
    "https://2gis.kz/almaty/search/Кафе/rubricId/161"
  ],
  "size": 50
}
```

#### Only places with photos

```json
{
  "city": "almaty",
  "keyword": "ресторан",
  "size": 30,
  "requireImages": true
}
```

#### Include contacts (slower)

```json
{
  "city": "almaty",
  "keyword": "кафе",
  "size": 20,
  "enrichContacts": true
}
```

### Input

| Field | Required | Description |
| --- | --- | --- |
| `urls` | one of | Direct 2GIS search / rubric listing URLs (highest priority) |
| `keyword` | one of | Search text when `urls` is empty |
| `city` | with keyword | City slug in the 2GIS path, e.g. `almaty`, `astana` (default `almaty`) |
| `size` | no | Max unique places to return (default `50`) |
| `requireImages` | no | If `true`, skip places without photos (default `false`) |
| `enrichContacts` | no | If `true`, fetch contacts from each firm page (default `false`, slower). Each detail lookup emits a `place-detail` pay-per-event charge. |

### Output

Each dataset item is one place:

| Field | Description |
| --- | --- |
| `externalId` | 2GIS place / firm ID |
| `name` | Display name |
| `url` | Firm page URL on 2GIS |
| `address` | Street address |
| `city` | City name |
| `point` | Coordinates as `lon,lat` |
| `rating` | Average rating |
| `reviewCount` | Number of reviews |
| `schedule` | Weekly hours by day (`Mon`…`Sun`, optional `is_24x7`) |
| `poiCategory` | POI category code |
| `imageUrls` | Photo URLs |
| `rubrics` | Rubric list (`id`, `name`, `alias`, `kind`) |
| `attributes` | Place attributes (`id`, `name`, `tag`) |
| `contacts` | Phones, website, email, Instagram, WhatsApp, etc. (only when `enrichContacts` is true) |
| `sourceUrl` | Listing URL used for the scrape |
| `raw` | Original listing payload |

#### Example item

```json
{
  "externalId": "70000001035014267",
  "name": "Friendly, лаундж-бар",
  "url": "https://2gis.kz/almaty/firm/70000001035014267",
  "address": "проспект Достык, 89г",
  "city": "Алматы",
  "point": "76.956,43.238",
  "rating": 4.9,
  "reviewCount": 2560,
  "schedule": {
    "Mon": { "working_hours": [{ "from": "12:00", "to": "02:00" }] },
    "Fri": { "working_hours": [{ "from": "12:00", "to": "04:00" }] }
  },
  "poiCategory": "food_restaurant",
  "imageUrls": ["https://i4.photo.2gis.com/..."],
  "rubrics": [
    { "id": "161", "name": "Кафе", "alias": "kafe", "kind": "primary" }
  ],
  "attributes": [
    { "id": "...", "name": "Европейская кухня", "tag": "food_service_food_european" }
  ],
  "contacts": [
    { "type": "phone", "text": "+7‒702‒007‒70‒89", "value": "+77020077089" },
    { "type": "instagram", "url": "https://instagram.com/friendly.almaty", "value": "https://instagram.com/friendly.almaty" }
  ],
  "sourceUrl": "https://2gis.kz/almaty/search/кафе"
}
```

# Actor input Schema

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

Direct 2GIS listing URLs (search / rubric). Highest priority. Example: https://2gis.kz/almaty/search/Кафе/rubricId/161

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

2GIS city path slug, e.g. almaty, astana. Required for keyword mode.

## `keyword` (type: `string`):

Search keyword when urls are empty. Builds https://2gis.kz/{city}/search/{keyword}.

## `size` (type: `integer`):

Maximum number of unique places to return.

## `requireImages` (type: `boolean`):

If true, skip places with no photos.

## `enrichContacts` (type: `boolean`):

If true, open each firm page to fetch phones, email, Instagram, WhatsApp, etc. Slower (extra request per place).

## Actor input object example

```json
{
  "city": "almaty",
  "keyword": "кафе",
  "size": 50,
  "requireImages": false,
  "enrichContacts": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# 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 = {
    "city": "almaty",
    "keyword": "кафе",
    "size": 50,
    "requireImages": false,
    "enrichContacts": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("shareze001/2gis-places").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 = {
    "city": "almaty",
    "keyword": "кафе",
    "size": 50,
    "requireImages": False,
    "enrichContacts": False,
}

# Run the Actor and wait for it to finish
run = client.actor("shareze001/2gis-places").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 '{
  "city": "almaty",
  "keyword": "кафе",
  "size": 50,
  "requireImages": false,
  "enrichContacts": false
}' |
apify call shareze001/2gis-places --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,shareze001/2gis-places"
        }
    }
}
```

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/1leTcQK4GD2teaNSl/builds/jHnjZwqwVYWXuvufu/openapi.json
