APIREST · JSON · Bearer auth

Google Maps Scraper API

Extract Google Maps business listings from your own code — names, phone numbers, websites, addresses, ratings and hours. Three calls: start a job, poll it, download the results. No headless browsers, no proxy rotation, no HTML parsing.

Start a scrape in one call

Every request authenticates with a Bearer token in the Authorization header. Keys look like mh_live_… and are created from the Integrations tab in your dashboard.

curl -X POST https://api.mapsharvest.com/scrape \
  -H "Authorization: Bearer mh_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "query": "dentist",
    "states": "Florida,Georgia",
    "country": "us",
    "max_total_results": 500,
    "min_rating": 4.0,
    "exclude_website": true
  }'

# → {"job_id":"a7f3c2d1e8b94f56","status":"queued", ... }

That single request scrapes every city in Florida and Georgia for dentists rated 4.0+ with no website — the exact shape of a web-design prospect list.

Endpoints

POST/scrape

Start a scrape. Pass a query, states and optional filters; receive a job_id immediately.

GET/jobs/{job_id}

Poll status, progress, cities completed and rows collected.

GET/jobs/{job_id}/download

Download finished results. Add ?fmt=csv, ?fmt=xlsx or ?fmt=json.

POST/scrape/{job_id}/stop

Stop a running job early. Rows already collected stay downloadable.

GET/jobs

List your jobs with status and row counts.

GET/fields

List every data field available on your plan.

GET/cities

List the cities the scraper will loop through for given states.

POST/api-keys

Create a new API key. Returns the raw key once — store it immediately.

A complete workflow

Start, poll, download — in Python:

import time, requests

API  = "https://api.mapsharvest.com"
HDRS = {"Authorization": "Bearer mh_live_..."}

# 1. Start
job = requests.post(f"{API}/scrape", headers=HDRS, json={
    "query": "roofing contractor",
    "states": "Texas",
    "max_results_per_city": 60,
    "require_phone": True,
}).json()

# 2. Poll
while True:
    status = requests.get(f"{API}/jobs/{job['job_id']}", headers=HDRS).json()
    if status["status"] in ("completed", "failed", "stopped"):
        break
    time.sleep(5)

# 3. Download
csv = requests.get(
    f"{API}/jobs/{job['job_id']}/download",
    headers=HDRS, params={"fmt": "csv"},
).content
open("leads.csv", "wb").write(csv)

Prefer not to poll? Pass webhook_url on POST /scrape and the finished rows are posted to you — works with Zapier, Make and n8n.

Filter before you spend credits

Filters are applied during the scrape, not after. A business that fails a filter is never written and never billed — so a tightly-filtered job costs far less than scraping broadly and cleaning up afterwards.

ParameterTypeEffect
min_ratingfloatOnly businesses rated at or above this. 4.0 filters to well-reviewed operators.
min_reviewsintSkip businesses with fewer reviews than this — a proxy for how established they are.
max_reviewsintSkip businesses with more reviews than this. Useful for finding smaller, less-saturated targets.
require_websiteboolKeep only businesses that have a website.
exclude_websiteboolKeep only businesses with no website — the classic web-design pitch list.
require_phoneboolKeep only businesses with a phone number. Essential for dialer imports.
exclude_phoneboolKeep only businesses without a listed phone number.

Plans and concurrency

One credit equals one lead. Concurrency is capped per plan — both the workers inside a single job and the number of jobs you can run at once.

PlanAPIWorkersParallel jobsCredits/mo
Free1150
Starter221,000
GrowthIncluded435,000
ScaleIncluded8520,000

Exceeding your parallel-job cap returns 429; running out of credits returns 402. See full pricing.

Frequently asked questions

Is there a free Google Maps scraper API?+

You can create an account and get 50 credits free with no credit card. API key access is included on the Growth plan and above, so the API itself is a paid feature — but you can test the underlying scraper on the free plan through the dashboard before committing.

How is this different from running my own scraper?+

Running your own means operating headless browsers, rotating proxies to avoid blocks, and repairing selectors every time Google changes its markup. This API handles the browser fleet, the proxies and the parsing. You send JSON describing what you want and receive structured, deduplicated business records.

What data fields does the API return?+

Up to 18 fields per business, including name, category, phone, website, full address, city, state, Google rating, review count, opening hours, price level, Google Maps URL, Plus Code and permanently/temporarily closed status. Call GET /fields to see the live list for your plan.

Which countries are supported?+

Six: United States, United Kingdom, Canada, Australia, Germany and India. Pass the country parameter on POST /scrape; it defaults to us.

Is scraping Google Maps legal?+

Scraping publicly available business listing data has been repeatedly upheld in US courts, including hiQ v. LinkedIn. Business names, phone numbers and addresses are public commercial information rather than personal data. You are still responsible for how you use the data — particularly for GDPR compliance and cold-outreach rules in your jurisdiction.

How many results can one job return?+

Up to 500 results per city and up to 1,000,000 per job via max_total_results. Throughput depends on your plan's concurrent worker cap: 1 on Free, 2 on Starter, 4 on Growth and 8 on Scale.

Build on the Maps Harvest API

Start free with 50 credits — no credit card required.