2GIS $1💰 Extract Phones, Emails, Reviews & Locations
Pricing
from $1.00 / 1,000 results
2GIS $1💰 Extract Phones, Emails, Reviews & Locations
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.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
14
Total users
3
Monthly active users
5 days ago
Last modified
Categories
Share
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"] |
| contact@example.com | |
| website | http://example.com |
| https://wa.me/70000000000 | |
| telegram | https://t.me/example |
| 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
{"mode": "search","query": ["coffee shop", "bakery"],"city": "Moscow","maxResults": 200}
By category in a city
{"mode": "search","categoryQuery": ["Restaurants", "Pharmacies"],"city": "Almaty","maxResults": 500}
Around coordinates (radius)
{"mode": "search","query": ["pizza"],"latitude": "55.7558","longitude": "37.6173","radiusMeters": 1000,"maxResults": 100}
In a map area (bounding box)
{"mode": "search","categoryQuery": ["Pharmacies"],"bbox": "37.55,55.70,37.70,55.80","maxResults": 300}
Everything in an area (no query)
{"mode": "search","latitude": "55.7558","longitude": "37.6173","radiusMeters": 500,"maxResults": 100}
From 2GIS URLs or IDs
{"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 asNEW; later runs return onlyNEW/UPDATED/REAPPEAREDplaces 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.
{"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.
- Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto 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.
{"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.