Quick answer
The 2GIS Places Scraper turns 2GIS searches into a clean table of local businesses for any 2GIS city, including Moscow, Saint Petersburg, Novosibirsk, Almaty and Dubai: 2GIS id, name, categories, street address, building, district, latitude and longitude, rating, review count, opening hours per weekday, last-updated date and a direct 2GIS link. Switch on includeContacts and it also opens each place page to add business phones, website and e-mail. Give it lists of cities and queries and it runs every combination, deduplicated by place. Pricing is pay-per-result, $0.20 per run plus $0.003 per place, $3.20 per 1,000 places.
Does 2GIS have an API for this?
2GIS sells API access for maps, routing and its places catalogue under commercial keys and quotas. If you want a one-off lead list of every pharmacy in Almaty with its rating and opening hours, that means a sales conversation and an integration project before the first row. The same data is already printed on 2GIS's public search pages. We read those pages and hand you the rows.
Why does page 6 of a 2GIS search give you page 1 again?
This is the trap that inflates naive scrapers. 2GIS serves at most five result pages of 12 places for any single search: 60 places. Ask for page 6 and it doesn't return an error or an empty page. It silently serves page 1 again. A scraper that pages "until the results run out" never sees them run out. It loops, re-downloading the same 12 places, and if it counts rows instead of ids it reports a city far bigger than it is.
2GIS caps every search at 5 pages of 12 places, and page 6 silently returns page 1, so "page until empty" never ends.
We measured that limit and stop cleanly at page 5. We also dedupe on placeId across every page, query and city in the run, so a cafe that matches both кафе and кофейня is emitted and billed once. To cover more ground than 60 places, use several specific queries and more cities.
What else we handle
-
Contacts are opt-in. Phones, website and e-mail live on each place's own page, not in search results. With
includeContacts: false(the default) those fields stay empty and the run is fast. Turn it on and we make one extra request per place to fillphone,phones,websiteandemail, when the business publishes them. -
Branches vs companies.
placeIdis the branch.organizationIdis shared by every branch of a chain, so you can group a chain's locations. -
Country sites. Kazakhstan and UAE cities live on their own 2GIS country domains. Give the city slug (
almaty,dubai) and we route to the right one. -
Paid placement is flagged.
isPromotedtells you which rows are ads, so promotion doesn't skew your rankings.
What the Actor gives you
One row per place, 26 fields: placeId, name, organizationId, category, categories, address, addressComment, buildingName, postcode, city, district, latitude, longitude, rating, reviewCount, phone, phones, website, email, workingHours, updatedAt, isPromoted, url, query, searchCity and scrapedAt.
{
"placeId": "70000001007179642",
"name": "Му-Му, кафе",
"organizationId": "4504136498368318",
"category": "Кафе",
"categories": ["Кафе", "Доставка еды", "Быстрое питание"],
"address": "Манежная площадь, 1 ст2",
"buildingName": "Охотный ряд",
"city": "Москва",
"district": "Тверской",
"latitude": 55.755301,
"longitude": 37.614586,
"rating": 4.8,
"reviewCount": 1107,
"phone": "+74957818781",
"website": "http://cafemumu.ru",
"workingHours": { "Mon": "08:00-23:00", "Sun": "08:00-23:00" },
"url": "https://2gis.ru/moscow/firm/70000001007179642",
"query": "кафе",
"searchCity": "moscow",
"scrapedAt": "2026-10-01T10:00:00+00:00"
}
That sample was run with includeContacts: true. Input: cities (2GIS slugs), queries (in the city's language works best), maxItemsPerQuery up to 60, maxPages up to 5, a run-wide maxResults up to 50,000, and includeContacts.
Honest limitations 🚧
60 places per city and query, because that is all 2GIS serves. includeContacts makes runs slower, with one extra page per place. Rating, review count and opening hours appear only when 2GIS lists them. Search-result data only: no review text, menus or photos. A query with no matches is a successful run that costs only the start fee.
FAQ
Do I need a 2GIS account or API key?
No. Add cities and queries and start the run.
What about blocks and rate limits?
That's our job. We rotate real-browser TLS fingerprints (Chrome, Firefox, Safari) through curl-cffi, route through Apify Proxy with a fresh exit on every failed attempt, and retry with exponential backoff on 408, 429 and 5xx, up to 5 attempts per page. One failing page or place never kills the run.
Are the phone numbers personal data?
No. includeContacts reads only the business contacts a company publishes on its own 2GIS page.
How does pricing work?
$0.20 per run plus $0.003 per unique place: $3.20 per 1,000 places. Contacts enrichment costs no extra per row.
→ 2GIS Places Scraper on Apify
Built by Devil Scrapes. We handle the pager trap, the fingerprints, the proxies and the retries, and we count unique places, not repeated pages. 😈
Top comments (0)