Try a request
curl https://api.nativeport.ai/serper/maps \
-H "Authorization: Bearer $NATIVEPORT_API_KEY" \
-H "Content-Type: application/json" \
--data '{"q": "coffee roasters", "ll": "@37.7749,-122.4194,13z"}'{
"places": [
{
"title": "Ritual Coffee Roasters",
"address": "1026 Valencia St, San Francisco, CA 94110",
"latitude": 37.7561,
"longitude": -122.4213,
"phoneNumber": "+1 415-641-1011",
"website": "https://ritualroasters.com/",
"rating": 4.4,
"ratingCount": 1893,
"category": "Coffee shop"
}
]
}Search an area and save the results
Send a search term, such as a business category, with a map center. Each result contains the listing details available to the provider, which may include an address, phone number, website, and rating.
The Python example queries several nearby map centers and removes duplicates using the business name and address. It writes the remaining records to a CSV that you can review or import into your own tools.
A maps search does not guarantee every matching business in a region. If your project needs broader collection, compare a bulk tool such as an Apify Maps actor and check its limits. Keep coverage separate from the number of rows returned.
Listings can be incomplete. Treat phone numbers, websites, and ratings as optional, and check the returned matches before using them in a customer-facing directory. If you need email addresses, visiting the business websites is a separate step.
Export business results from several map areas
Searches several map centers, removes duplicate names and addresses, and writes a CSV.
import csv, json, os, urllib.request
QUERY = "coffee roasters"
# A maps query answers around one viewport, so cover a city with a few centres.
CENTRES = ["@37.7749,-122.4194,13z", "@37.7899,-122.4014,13z",
"@37.7599,-122.4348,13z"]
def maps(q, ll):
req = urllib.request.Request(
"https://api.nativeport.ai/serper/maps",
data=json.dumps({"q": q, "ll": ll}).encode(),
headers={
"Authorization": f"Bearer {os.environ['NATIVEPORT_API_KEY']}",
"Content-Type": "application/json",
},
)
with urllib.request.urlopen(req) as r:
return json.load(r).get("places") or []
seen, rows = set(), []
for ll in CENTRES:
for p in maps(QUERY, ll):
key = (p.get("title"), p.get("address"))
if key in seen:
continue
seen.add(key)
rows.append(p)
with open("leads.csv", "w", newline="") as fh:
w = csv.writer(fh)
w.writerow(["name", "address", "phone", "website", "rating", "reviews"])
for p in rows:
w.writerow([p.get("title"), p.get("address"), p.get("phoneNumber"),
p.get("website"), p.get("rating"), p.get("ratingCount")])
print(f"{len(rows)} unique places from {len(CENTRES)} queries → leads.csv")$ python leads.py 47 unique places from 3 queries → leads.csv
Consider another approach
Serper's maps endpoint returns a page of matching businesses as JSON. Use several queries when you need to cover more than one area.
Apify's Google Maps actors collect results as background jobs. Compare the actor's coverage, limits, and per-result cost for your project.
Use it with NativePort
Use your NativePort key for Maps searches and any website scraping you add afterwards. Both draw from the same balance.
Before you start
Does one request return every business in the area?
No. It returns a page of search results around the map location. Several queries can broaden coverage, and you should remove duplicates. Bulk collection tools can help, but check their limits before assuming a complete list.
How do I set the search area?
The ll parameter sets a map center and zoom, using @latitude,longitude,zoom. The example uses 13z. Adjust the center and zoom for the area you want to research.
What if a listing has no phone number or website?
Allow those fields to be empty. The example uses .get() so a missing value does not stop the export.
Can I collect the review text too?
The maps response includes ratings and review counts where available. Use a separate reviews request for the text, with the place identifier required by that endpoint.