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
/scrapeStart a scrape. Pass a query, states and optional filters; receive a job_id immediately.
/jobs/{job_id}Poll status, progress, cities completed and rows collected.
/jobs/{job_id}/downloadDownload finished results. Add ?fmt=csv, ?fmt=xlsx or ?fmt=json.
/scrape/{job_id}/stopStop a running job early. Rows already collected stay downloadable.
/jobsList your jobs with status and row counts.
/fieldsList every data field available on your plan.
/citiesList the cities the scraper will loop through for given states.
/api-keysCreate 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.
| Parameter | Type | Effect |
|---|---|---|
min_rating | float | Only businesses rated at or above this. 4.0 filters to well-reviewed operators. |
min_reviews | int | Skip businesses with fewer reviews than this — a proxy for how established they are. |
max_reviews | int | Skip businesses with more reviews than this. Useful for finding smaller, less-saturated targets. |
require_website | bool | Keep only businesses that have a website. |
exclude_website | bool | Keep only businesses with no website — the classic web-design pitch list. |
require_phone | bool | Keep only businesses with a phone number. Essential for dialer imports. |
exclude_phone | bool | Keep 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.
| Plan | API | Workers | Parallel jobs | Credits/mo |
|---|---|---|---|---|
| Free | — | 1 | 1 | 50 |
| Starter | — | 2 | 2 | 1,000 |
| Growth | Included | 4 | 3 | 5,000 |
| Scale | Included | 8 | 5 | 20,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.