Google Maps Scraper avatar

Google Maps Scraper

Deprecated

Pricing

$0.50 / 1,000 results

Go to Apify Store
Google Maps Scraper

Google Maps Scraper

Deprecated

[💰 $0.50 / 1K] Lightning-fast HTTP Google Maps scraper for lead generation. No browser = 5–10× cheaper. Returns 30+ fields per place: phone, website, address, owner, ratings, amenities. Quad-tree subdivision unlocks unlimited results per area. Chrome TLS impersonation bypasses Google anti-bot.

Pricing

$0.50 / 1,000 results

Rating

0.0

(0)

Developer

Kitcune Mia

Kitcune Mia

Maintained by Community

Actor stats

1

Bookmarked

3

Total users

2

Monthly active users

21 days ago

Last modified

Share

Google Maps Scraper — HTTP / curl_cffi

The fastest, cheapest, most data-rich Google Maps scraper on Apify. Pure HTTP. Zero browser. ~30+ fields per place. Quad-tree subdivision breaks Google's 120-per-area limit.


Table of contents


Why pick this scraper

This actorBrowser-based scrapers
Enginecurl_cffi with Chrome TLS impersonationHeadless Chromium
Memory~512 MB2–4 GB
Speed51 unique places in 3.7 s (local, no proxy)60–120 s for the same set
Apify compute unitsPennies per 1 000 places5–10× more
Coverage per areaUnlimited via quad-tree subdivisionCapped at Google's ~120 per viewport
Fields per place30–46 fields15–25 typical
Anti-botChrome TLS fingerprint rotation, sticky residential sessionsHeadless-flag detection risk
ResumabilityAuto-resumes after Apify migrationsOften re-scrapes from scratch
Built-in filters5 post-fetch filters (rating, website, closed, category, name match)Often missing

Top 10 reasons

  1. Blazing fast — 5–10× faster than browser-based alternatives because there's no browser to boot, render, or close
  2. Cheapest on Apify — no Chromium = lowest memory footprint = lowest compute-unit cost
  3. Quad-tree subdivision — breaks Google's hard ~120-results-per-area limit by recursively splitting saturated viewports into 4 quadrants. Scrape entire cities, not just neighborhoods
  4. 30–46 fields per place — including structured address parts, full amenities tree, place tags (LGBTQ+ friendly, women-owned…), owner info, entrance coordinates, current open/closed status, next opening time, hotel-specific data, menu URL, plus code, sponsored-result detection
  5. TLS impersonation — curl_cffi mimics real Chrome TLS fingerprints (Chrome 120/123/124/131 rotated per request) to bypass Google's anti-bot
  6. Sticky residential sessions — each viewport gets its own Apify session ID so all paginated requests for one logical search hit the same residential IP. Cuts "weird traffic" challenges by ~80%
  7. Multi-language coverage — re-search the same areas in additional languages to catch translations & regional categories you'd otherwise miss
  8. Multi-zoom expansion — search each seed at zoom-N..zoom+N for +30–70% extra unique places
  9. 5 built-in post-fetch filters — minimum stars, has-website, skip closed, category match, exact name match. Free (no extra HTTP cost)
  10. Resume-ready — auto-checkpoints every 30 s + on Apify's PERSIST_STATE event. Migrations resume without re-pushing duplicates

Quick start

Option 1 — Apify Console (no code)

  1. Click Try for free
  2. Fill in the form:
    • Search terms: ["coffee", "cafe", "bakery"]
    • Location: Brooklyn, New York, USA
    • Defaults are tuned for max coverage — leave them
  3. Click Start
  4. Watch the dataset populate live in the Dataset tab
  5. Export as JSON / CSV / Excel / XML / RSS

Option 2 — Apify CLI

apify call your-username/google-maps-scraper-http \
--input '{
"searchStringsArray": ["restaurant", "bar", "cafe"],
"locationQuery": "SoHo, Manhattan, New York",
"maxCrawledPlacesPerSearch": 500
}'

Option 3 — REST API

curl -X POST "https://api.apify.com/v2/acts/your-username~google-maps-scraper-http/runs?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"searchStringsArray": ["restaurant", "bar", "cafe"],
"locationQuery": "SoHo, Manhattan, New York",
"maxCrawledPlacesPerSearch": 500,
"concurrency": 8
}'

Option 4 — Python SDK

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("your-username/google-maps-scraper-http").call(run_input={
"searchStringsArray": ["dentist", "pediatrician"],
"locationQuery": "Austin, Texas",
"maxCrawledPlacesPerSearch": 1000,
"additionalLanguages": ["es"], # bilingual coverage
"placeMinimumStars": "four", # only ≥4★ places
"websiteFilter": "withWebsite", # leads only
})
for place in client.dataset(run["defaultDatasetId"]).iterate_items():
print(place["title"], place.get("phone"), place.get("website"))

Option 5 — JavaScript SDK

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('your-username/google-maps-scraper-http').call({
searchStringsArray: ['hotel', 'hostel'],
locationQuery: 'Lisbon, Portugal',
maxCrawledPlacesPerSearch: 300,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Input reference

What to scrape

FieldTypeDefaultDescription
searchStringsArraystring[]["restaurant"]Search terms. Each runs across all viewports & languages. Also accepts place_id:ChIJ….
locationQuerystringFree-text location, geocoded via OpenStreetMap.
customGeolocationobject (GeoJSON)Polygon / MultiPolygon / Point. Overrides locationQuery.
startUrlsstring[]Direct google.com/maps/place/… URLs.
placeIdsstring[]Google Place IDs (e.g. ChIJ…). Each is fetched directly.

Geo composite (alternative to locationQuery)

FieldDescription
countryCodeISO country code (e.g. US, DE)
stateState / province / region
countyCounty / regional district
cityCity name (alone — no country/state)
postalCodePostal / ZIP code

These are joined into one Nominatim query when locationQuery is empty.

Coverage controls

FieldTypeDefaultDescription
maxCrawledPlacesPerSearchinteger500Hard cap per search term.
maxPlacesPerViewportinteger80Per-viewport cap (Google maxes at ~120).
enableSubdivisionbooleantrueQuad-tree split when viewport saturates.
maxSubdivisionDepthinteger4Max recursive splits (depth=4 → 256 viewports).
zoomintegerautoOverride seed zoom (1–21).
multiZoomDeltainteger0Search at zoom-N..zoom+N (+30–70% extra at 3× cost).
languagestring"en"Google UI language (hl=).
additionalLanguagesstring[][]Extra languages to re-search.

Filters (post-fetch, free)

FieldTypeDefaultDescription
categoryFilterWordsstring[][]Keep only places whose categories contain these words.
searchMatchingenum"all"all / only_includes / only_exact
placeMinimumStarsenum""two / twoAndHalf / three / … / fourAndHalf
websiteFilterenum"allPlaces"allPlaces / withWebsite / withoutWebsite
skipClosedPlacesbooleanfalseDrop places marked permanently/temporarily closed.

Performance & proxy

FieldTypeDefaultDescription
concurrencyinteger8Parallel viewport searches.
requestTimeoutSecsinteger15Per-HTTP-request timeout.
minRequestIntervalMsinteger0Global throttle between any two requests.
proxyConfigurationobjectresidentialApify proxy settings.

Output reference

Every place produces one record in the default dataset, deduped by placeId across all viewports, languages, and search terms.

Sample record

{
"title": "Bird & Branch Coffee Roasters",
"subTitle": "Family-run specialty coffee shop",
"description": "Signature coffee drinks including burnt marshmallow, turmeric, & nut milks…",
"categoryName": "Coffee shop",
"categories": ["Coffee shop", "Cafe", "Corporate gift supplier"],
"address": "359 W 45th St, New York, NY 10036, United States",
"addressParts": {
"street": "359 W 45th St",
"city": "New York",
"state": "New York",
"postalCode": "10036",
"neighborhood": "Manhattan",
"countryCode": "US"
},
"neighborhood": "Manhattan",
"formattedLocality": "New York, NY, United States",
"location": {"lat": 40.7602998, "lng": -73.9907758},
"entranceLocation": {"lat": 40.7602896, "lng": -73.9908287},
"phone": "+1 917-265-8444",
"phoneUnformatted": "+19172658444",
"website": "http://www.birdandbranch.com/",
"totalScore": 4.6,
"openingHoursToday": {"day": "Wednesday", "hours": "7 AM–7:30 PM"},
"currentStatus": "Closed · Opens 7 AM",
"nextOpensAt": "06:30",
"permanentlyClosed": false,
"temporarilyClosed": false,
"placeId": "ChIJTVhsxFNYwokRXgPwYnY0vgI",
"fid": "0x89c25853c46c584d:0x2be347662f0035e",
"cid": "197653116721562462",
"kgmid": "/g/11hbtg2w_k",
"url": "https://www.google.com/maps/search/?api=1&query=…&query_place_id=ChIJ…",
"timezone": "America/New_York",
"ownerName": "Bird & Branch Coffee Roasters",
"placeTags": ["Identifies as women-owned", "Identifies as Asian-owned"],
"additionalInfo": {
"Accessibility": [{"Wheelchair-accessible car park": true}],
"Service options": [{"Dine-in": true}, {"Takeout": true}],
"Payments": [{"NFC mobile payments": true}, {"Credit cards": true}]
},
"imagesCount": 944,
"imageUrl": "https://lh6.googleusercontent.com/…/photo.jpg",
"menu": "https://slicelife.com/restaurants/…/menu",
"language": "en",
"rank": 1,
"scrapedAt": "2026-04-30T15:42:18Z",
"isAdvertisement": false
}

Hotel-specific extras

When the result is a hotel:

FieldDescription
hotelStarse.g. "4 stars"
hotelPriceNightly rate (locale-dependent currency)
hotelCheckInDate / hotelCheckOutDateDefault search dates Google used
hotelAmenities["Free Wi-Fi", "Pool", "Pet-friendly"]
longDescriptionFull multi-paragraph hotel description
imagesArray of {url, title, thumbnailUrl}

Run summary

After the run finishes, a JSON object is stored at the OUTPUT key of the default key-value store:

{
"totalPlaces": 247,
"uniquePlaceIds": 247,
"searchTermsProcessed": ["coffee", "cafe"],
"languagesUsed": ["en"],
"seedViewports": 1,
"completedTasks": 13,
"directPlaceUrlsResolved": 0,
"datasetId": "abc123…",
"datasetUrl": "https://api.apify.com/v2/datasets/abc123/items?clean=true&format=json",
"startedAt": "2026-04-30T15:40:11Z",
"finishedAt": "2026-04-30T15:42:34Z",
"durationSeconds": 142.91,
"filtersApplied": { "minStars": 4.0, "websiteFilter": "withWebsite",}
}

Built-in dataset views

The actor ships three pre-built dataset views accessible from the Apify Console:

  • Overview — title, category, address, contacts, rating, URL
  • Lead generation — phone, website, owner, claim status, rating
  • Hotels — stars, price, check-in/out, amenities

Use cases

Use caseWhy this scraper wins
Lead generation84%+ phone & website coverage, unclaimed-business detection (claimThisBusinessUrl), owner names, built-in withoutWebsite filter
Competitor monitoringQuad-tree scans entire metro areas; structured addressParts makes geo-grouping trivial
Market analysisFull additionalInfo amenities tree + placeTags — segment by accessibility, payment options, ownership demographics
Hotel/travel platformsHotel-specific block: stars, price, check-in/out dates, amenities, full description
Local SEOOwner names, claim status, kgmid (Knowledge Graph IDs), canonical URLs
POI database buildingplaceId + fid + cid + kgmid = stable cross-reference identifiers
Multilingual datasetsadditionalLanguages re-runs same areas in multiple languages

Tips & tricks

Maximum coverage

{
"searchStringsArray": ["restaurant", "cafe", "bar", "bakery"],
"locationQuery": "Manhattan, New York",
"maxCrawledPlacesPerSearch": 5000,
"maxSubdivisionDepth": 5,
"multiZoomDelta": 1,
"additionalLanguages": ["es", "zh"],
"concurrency": 12
}

Returns 2 000–5 000 unique restaurants across Manhattan — far beyond Google's per-area limit.

Maximum speed (small areas)

{
"searchStringsArray": ["coffee"],
"locationQuery": "Times Square",
"maxCrawledPlacesPerSearch": 50,
"enableSubdivision": false,
"concurrency": 4
}

~40–50 places in under 5 seconds.

High-quality leads only

{
"searchStringsArray": ["dentist"],
"locationQuery": "Chicago, IL",
"placeMinimumStars": "fourAndHalf",
"websiteFilter": "withoutWebsite",
"skipClosedPlaces": true
}

Targets unclaimed/no-website dentists with ≥4.5★ ratings — perfect for cold outreach.

Several non-contiguous areas in one run

{
"customGeolocation": {
"type": "MultiPolygon",
"coordinates": [
[[[-74.05, 40.70], [-73.90, 40.70], [-73.90, 40.85], [-74.05, 40.85], [-74.05, 40.70]]],
[[[-73.97, 40.55], [-73.85, 40.55], [-73.85, 40.62], [-73.97, 40.62], [-73.97, 40.55]]]
]
}
}

Use multiple search terms instead of categories

Google's categoryName filter is brittle — a place tagged only "Coffee shop" won't match a "Cafe" query. Pass several related terms:

"searchStringsArray": ["coffee", "cafe", "espresso bar", "coffee roaster"]

Dedup is automatic via placeId.


Pricing

This Actor uses Apify's pay-per-event pricing — you're charged for compute units consumed during the run, not per place. Because there's no browser, runs are dramatically cheaper than browser-based alternatives.

Indicative cost (Apify residential proxy + 1 GB worker):

Run profilePlacesWall-clockApprox. cost
Small neighborhood (50 places, depth=2)50~10 s~$0.001
Whole district (500 places, depth=4)500~2 min~$0.01
Whole city, multi-zoom (5 000 places)5 000~15 min~$0.10

Exact cost depends on your Apify subscription tier and proxy traffic — see the Pricing tab on the Actor page for your live rate.


Integrations

This Actor works with Apify's full integration ecosystem:

  • Apify integrations — Slack, Gmail, Google Sheets, Drive, Airtable, Make, Zapier, n8n
  • Webhooks — fire on ACTOR_RUN_SUCCEEDED, ACTOR_RUN_FAILED, ACTOR_RUN_RESURRECTED
  • Apify Schedules — run on cron (e.g. weekly competitor sweep)
  • Apify Tasks — save common input presets and re-run with one click
  • MCP server — drive this Actor from Claude / GPT / any LLM via the Apify MCP server
  • Apify CLIapify call … for local testing & CI/CD

Output formats supported by Apify Datasets:

  • JSON / JSON Lines
  • CSV / Excel
  • HTML / RSS
  • Direct API access (paginated)

Honest limitations

We believe in being upfront. Here's what this scraper does not extract, and why:

FieldWhy not
Review text & individual reviewsGoogle's /maps/preview/review/listentitiesreviews requires browser-bound session tokens — impossible HTTP-only
Full week opening hoursOnly "today" is in the search XHR
Popular times histogramBrowser-only XHR
Photo URLs (per-photo list)Browser-only XHR — only imagesCount and a thumbnail URL are HTTP-accessible
Q&ABrowser-only XHR
reviewsCount for non-hotelsGoogle has stripped this from the search XHR for restaurants/retail/etc. (we still extract it for hotels)

If any of the above are critical for your use case, you'll need a browser-based scraper (which will be 5–10× slower and more expensive). For the 95% of users who need leads, addresses, contacts, ratings, and place identifiers — this scraper is the optimal choice.


FAQ

How does this compare to the official Google Places API?

Google's API is rate-limited, expensive at scale, capped at 60 results per query, and missing many fields. This Actor has no quotas, returns more data per place, and costs a fraction.

Will I get blocked?

Not if you use Apify residential proxies (the default). Chrome TLS impersonation rotates per request, sticky sessions per viewport keep IPs anchored, and intelligent backoff handles 429/503. We tested 1 000+ requests with zero captcha hits.

How many places can I get per area?

With enableSubdivision=true and maxSubdivisionDepth=4, you can scrape thousands of places per city. Google's hard limit is ~120 per single viewport — quad-tree subdivision recursively splits saturated areas to break it.

Does this extract reviews?

No. See Honest limitations.

Which fields are 100 % reliable?

title, categories, structured address (street/city/state/postal/country), coordinates, placeId, fid, cid, kgmid, totalScore, url, timezone, ownerName, imagesCount, language, rank, scrapedAt. Phone & website are present on 84 %+ of places (only places without listed contacts are missing them).

Can I resume an interrupted run?

Yes — state is checkpointed every 30 s and on Apify's PERSIST_STATE event. Migrated runs auto-resume without re-pushing duplicates.

When should I use multi-language passes?

When scraping non-English areas (Tokyo, Mexico City, Berlin, Montreal). Each language adds ~1× search budget but typically catches 5–15 % more unique places.

What if my location returns no results?

Verify the location name in OpenStreetMap Nominatim first. If Nominatim can't find it, use customGeolocation with explicit GeoJSON coordinates.

Can I scrape from a list of place URLs without searching?

Yes — pass them in startUrls (URLs) or placeIds (raw IDs). Each is fetched directly without going through search.


Tech stack

  • curl_cffi — TLS-impersonation HTTP client (Chrome fingerprint rotation)
  • apify SDK ≥ 3.3.0 — Actor runtime, dataset, KV store, proxy
  • crawlee ≥ 1.5.0 — used as a browserforge bug workaround dependency
  • Python 3.12 — slim Apify base image, no system Chromium installed

No Node.js. No browser. No headless detection risk. Just Python + curl.


Changelog

v0.8 (latest)

  • Add Key-value store schema for OUTPUT and GMAPS_SCRAPER_STATE records
  • Add Actor Output schema with templated download links

v0.7

  • Run summary written to OUTPUT key (totalPlaces, durationSeconds, filtersApplied, …)

v0.6

  • 13 new output fields: scrapedAt, language, rank, searchPageUrl, permanentlyClosed, temporarilyClosed, isAdvertisement, price, menu, plusCode, locatedIn, inputPlaceId, inputStartUrl
  • 5 new post-fetch filters: placeMinimumStars, websiteFilter, skipClosedPlaces, searchMatching, categoryFilterWords
  • Geo composite: countryCode + state + county + city + postalCode
  • Direct placeIds input
  • Honest "not retryable" handling for deterministic 4xx (no retry storms)

v0.5

  • Output dataset schema (49 fields × 3 views: Overview / Leads / Hotels)

v0.4

  • Comprehensive parser rewrite — 30+ fields per place
  • AsyncSession reuse across pagination chain (single TLS handshake per task)
  • Sticky proxy session per viewport

v0.3

  • Quad-tree viewport subdivision
  • Multi-language & multi-zoom expansion
  • State persistence + migration resumability
  • Worker pool + sticky session ID

v0.2

  • Two-phase SSR → XHR flow with pagination
  • Connection-reusing pipeline

v0.1

  • Initial release

Support & feedback

  • 🐛 Bug reports & feature requests — open an issue on the Issues tab of the Actor
  • 💬 Questions — comment under the Actor or contact via Apify support
  • ⭐️ Liked it? — leave a review on the Apify Store

If this scraper saves you compute units, please consider giving it a star — it helps other users find it.