Google Maps Scraper: Emails & Socials Included
Pricing
from $3.50 / 1,000 results
Google Maps Scraper: Emails & Socials Included
Extract businesses from Google Maps by search term and location: name, address, phone, website, emails, social_links, rating, review_count, hours and coordinates. Lead generation ready: emails and social media links cost nothing extra. Export JSON, CSV or Excel.
Pricing
from $3.50 / 1,000 results
Rating
0.0
(0)
Developer
herus13
Maintained by CommunityActor stats
2
Bookmarked
576
Total users
95
Monthly active users
3 days ago
Last modified
Categories
Share
The Google Maps Scraper extracts businesses from Google Maps by search term and location — name, address, phone, website, emails, social links, rating, review count, opening hours, coordinates, popular times and the full place detail, 42 fields in every row. Emails, social media links and the place detail are included in the result price.
What you get
One dataset row per business, ready to export as JSON, CSV or Excel.
{"place_id": "ChIJb5gBC-u0RIYRHkntaUcdJGs","name": "ATX Family Dental","address": "1700 S 1st St, Austin, TX 78704, United States","phone": "+1 512-717-3147","website": "https://www.atxfamilydental.com/","emails": ["info@atxfamilydental.com"],"rating": 4.9,"review_count": 802,"categories": ["Dentist", "Cosmetic dentist"],"latitude": 30.2482229,"longitude": -97.7559705,"_meta": {"author": "https://apify.com/herus13", "status": "ok", "message": null}}
_meta is run metadata, not place data. Rows are only ever ok here: failures are listed in the run log.
A full row also carries email_type, has_contact_form, hours, google_maps_url, social_links, reviews, images, neighborhood, timezone, country_code, business_photo, open_status, business_status, price_level, scraped_at, place_type, popular_times, data_groups and the 13 place detail groups below.
place_typeis Google's own category vertical for the place's first category that has one, unmapped: one ofSHOPPING,FOOD_AND_DRINK,SERVICE_PROVIDER,LEISURE,HEALTH,SERVICE_NONSKILLED,NONCONSUMER,LODGING,TRANSIT_STATION,EDUCATION,TRANSPORTorGEOPOLITICAL. It isnullwhen no category has a vertical, and a number string (such as"13") when Google sends a vertical this version does not know yet. The raw category keys stay incategories.price_levelis the price band Google shows, now also filled from the place detail when the search result left it blank.popular_timesis an object keyed by weekday (MondaytoSunday), each holding 24 hourly busyness percentages from 0 to 100, withnullfor hours Google shows nothing. A day with no data is left out, so there can be fewer than 7 keys. It is copied from thepopularitygroup and isnullwhen Google shows no popular times.data_groupslists the groups below that this row filled.
Place detail groups
Each group is a nested object, and every group is null when Google has none of it for that place.
| Group | What it holds | When it is filled |
|---|---|---|
popularity | Popular times (7 days × 24 hours, in percent), live busyness right now, wait times by hour | Places where Google shows popular times |
about | The About attributes (service options, amenities, payments and so on), accessibility, description, located_in, plus_code, typical time spent | Places Google shows About details, a description or a plus code for |
ratings | The 1 to 5 star histogram, review topics with mention counts, and price_histogram | Places with reviews; price_histogram only where Google shows spend buckets (restaurants, some services) |
menu | Menu link, menu or services price list, popular dishes, reservation links, booking providers | Restaurants and bookable services that publish them |
lodging | Star class, offers from booking sites (provider, price, nightly price, taxes, link), lowest price, cheaper comparable hotels, check-in and check-out times, amenities | Hotels and other lodging only. Prices are for Google's default dates, shown in check_in_date and check_out_date, not dates you choose |
ev_charging | Stations, their connectors (type, count, maximum kW, speed) and each port's status and updated_at | EV charging places only. Port status is Google's raw code; its meaning is not confirmed |
fuel | Fuel prices by grade, with unit, currency and updated_at | Gas stations in the US only |
transit | The station, its services and lines (headsign, agency, vehicle) and upcoming departures with platform and occupancy | Transit stations only. Departures are live, as of the group's fetched_at |
departments | Departments inside the place, each with its own weekly hours | Places with departments, such as a pharmacy inside a supermarket |
updates | Owner posts and events: title, text, date range, link and its label | Places whose owner posts updates |
media | Photo categories: label, cover photo and token | Places with categorised photos |
related | "People also search for" places: name, feature_id, rating, review count | Places where Google shows them |
localized | Name and address in the local script, and its language | Places Google gives a local-script name or address for |
What it costs
| Event | Free | Bronze | Silver | Gold+ |
|---|---|---|---|---|
result (apify-default-dataset-item) | $0.009 | $0.007 | $0.005 | $0.0035 |
Actor Start (apify-actor-start) | $0.01 | $0.01 | $0.01 | $0.01 |
You pay per business returned, and that one price already covers emails, social media links, reviews and photos — there is no add-on event and no subscription. A thousand businesses with emails is about $9.02 on the Free tier and about $3.52 on Gold, including the one-off start charge at the default 2 GB of memory. The residential proxy the run needs is included too.
Input
| Field | Type | Required | Default | What it does |
|---|---|---|---|---|
searchStringsArray | array | no | — | What to look for on Google Maps. Add one search term per entry, for example dentist, plumber or coffee shop. Every term is searched inside the place given in locationQuery, and every business found becomes one row. Leave empty only when you are naming the businesses yourself in startUrls or placeIds; a run must give at least one of the three, and one that gives none of them stops with an error. |
startUrls | array | no | — | Google Maps places, searches or saved lists to scrape directly, one per entry. Accepts a full place URL, a maps.app.goo.gl short link, a cid link, a link with a place id, a bare ChIJ… or 0x…:0x… id, a Maps search URL (runs that search from the location in the URL), or a shared saved-list link (every place in the list). Named places are returned as given; the search filters do not apply. Leave empty for a normal search run. |
placeIds | array | no | — | Places to scrape directly, one per entry: ChIJ… place IDs, 0x…:0x… feature IDs or cid numbers. Any format that works here also works in startUrls, and the other way round. Named places are returned as given; the search filters do not apply. An ID Google does not know is skipped with a warning and is not charged. Leave empty for a normal search run. |
locationQuery | string | no | — | Where to search, written the way you would type it into Google Maps: Austin, TX, New York, USA, London, UK, or a whole country. Leave empty to let each search term carry its own location. |
countryCode | string | no | — | Two-letter country code (ISO 3166-1), for example us, pe, de. Pins the search to that country: it is sent to Google with every search and keeps the location above from matching a same-named place elsewhere. Leave empty for no country. |
maxCrawledPlacesPerSearch | integer | no | 100 | Most businesses to return for each search term, from 1 to 500, counted after your filters. Default 100. The run keeps searching until it has this many matches or Google has no more results. Google shows about 120 businesses for a single map view, so a strict filter can return fewer — turn on geo_split to search a wider area. |
maxCrawledPlaces | integer | no | 0 | Most businesses the whole run returns across all search terms and place links together, counted after your filters. Default 0 means no ceiling. You pay per business returned, so this caps your bill: 20 terms at 100 results each is 2,000 rows. It is shared out across terms; a term that finds nothing hands its share back. Places you name count toward it. If it is lower than the number of terms, links and ids you give, it is raised to that count and the run log says so. |
language | string | no | "en" | Language of the Google Maps results and of the text inside each row. Default en. Supported codes: en, es, fr, de, it, pt, ja, ko, zh-CN, zh-TW, ar, hi, ru, nl, pl, tr, vi, th, id. |
scrapeContacts | boolean | no | true | Read each business's own website (homepage, contact and about pages, up to two social or community pages) and add the emails and social media links it publishes, as emails, email_type and social_links, plus has_contact_form when the site uses a form instead of an address. Links only: the run never visits Facebook, Instagram or any other social platform, so no followers, bios or posts. Default true. These fields are part of the result price, so leaving this on costs nothing extra. |
scrapeSocialMediaProfiles | object | no | {"facebooks": true, "instagrams": true, "youtubes": true, "tiktoks": true, "twitters": true, "linkedins": true} | Networks whose links to keep in social_links: facebooks, instagrams, twitters (X), linkedins, youtubes, tiktoks, discords, telegrams, whatsapps, pinterests, threads, snapchats, githubs, reddits, twitches. Set a key to false to drop it; a key left out is kept. Default {"facebooks": true, "instagrams": true, "youtubes": true, "tiktoks": true, "twitters": true, "linkedins": true}, which keeps all 15. With scrapeContacts off, only a social page Google lists as the website can appear. |
scrapePlaceDetailPage | boolean | no | false | No longer needed — every row now includes the full place detail. Kept so saved tasks keep working; removed in the next major version. Default false. |
maxReviews | integer | no | 0 | How many reviews to attach to each business, from 0 to 500. Default 0, which leaves reviews out. Each business gets up to that many reviews with text; star-only ratings are left out. For a full review history use the Google Maps Reviews Scraper instead. |
reviewsSort | string | no | "newest" | Which reviews you get when maxReviews is above 0: newest for the most recent first, mostRelevant for Google's own ranking, highestRating for the best first, lowestRating for the worst first. Default newest. |
maxImages | integer | no | 0 | How many photo URLs to attach to each business, from 0 to 50. Default 0, which leaves images out. |
dataGroups | array | no | ["popularity", "about", "ratings", "menu", "lodging", "ev_charging", "fuel", "transit", "departments", "updates", "media", "related", "localized"] | Extra data groups attached to each business, such as busy hours, menu, amenities, owner posts and related places. Default ["popularity", "about", "ratings", "menu", "lodging", "ev_charging", "fuel", "transit", "departments", "updates", "media", "related", "localized"], all 13. Remove any you do not need: they come back null and you pay only for what you keep. An empty list drops them all; name, address, phone, hours, website and rating stay. |
placeMinimumStars | string | no | "" | Keep only businesses rated at or above this many stars: 1, 2, 3, 4 or 4.5. Leave empty, the default, to keep every rating including businesses with no rating yet. Businesses this filter leaves out are not returned, not charged, and do not count toward your limits. |
skipClosedPlaces | boolean | no | true | Leave out businesses Google marks as permanently closed, so you do not pay for dead leads. Businesses this filter leaves out are not returned, not charged, and do not count toward your limits. Default true. |
website | string | no | "allPlaces" | Filter on whether the business has its own website: allPlaces keeps every business, withWebsite keeps only those that have one, withoutWebsite keeps only those that do not. A social or messaging page (Facebook, Instagram, WhatsApp and the like) is not a website: it moves to social_links, website comes back empty, and the business counts as having none. Businesses this filter leaves out are not returned, not charged, and do not count toward your limits. Default allPlaces. |
geo_split | boolean | no | false | Cover a large area by splitting it into a grid and searching each cell, which gets you past the roughly 120 businesses Google returns for one map view. Default false. Turn it on for anything wider than a single city. |
geo_split_max_cells | integer | no | 100 | Upper bound on how many grid cells geo_split may use, from 1 to 500. Default 100. A wider area uses bigger cells to stay inside this bound. |
max_requests_per_minute | integer | no | 400 | Ceiling on how many requests the run sends per minute, from 10 to 400. Default 400. Lower it to be gentler on a long run. |
detail_retries | integer | no | 3 | How many times a place's detail request is retried on a fresh proxy exit after a connection or TLS failure, before falling back to a lighter detail call, from 0 to 5. Default 3. |
max_concurrency | integer | no | 5 | How many searches and places are processed at the same time, up to 10. Default 5. A value below 1 is treated as 5. Lower it for a gentler run; max_requests_per_minute still caps how fast requests go out. |
request_delay | integer | no | 0 | Extra seconds to wait between requests, on top of the per-minute ceiling. Default 0, which adds no wait at all. |
cache_provider | string | no | "memory" | Where the run keeps the business data it has already collected, so the same place is not collected twice: memory for the run's own memory, file for the run's disk, apify for an Apify key-value store. Default memory. |
cache_ttl_seconds | integer | no | 86400 | How long kept business data stays usable before it is collected again, in seconds, from 60 to 604800 (seven days). Default 86400, which is 24 hours. |
proxyUrls | array | no | — | Leave empty and the run uses a residential proxy that is included in the price of the run. To route through your own account instead, add one gateway URL per entry, for example http://user:pass@host:port. Works with any provider that issues URLs. When set, the run uses these first and switches to the included proxy if they stop working, so a broken proxy never fails the run. |
How to run it
- Open the actor on Apify Console and click Try for free.
- Put your search terms into Search Queries and a city, state or country into Location.
- Run it. Results stream into the dataset while the run is still going; export them as JSON, CSV or Excel, or read them from the Apify API.
{"searchStringsArray": ["coffee shop"],"locationQuery": "California, USA","maxCrawledPlacesPerSearch": 500,"maxCrawledPlaces": 5000,"scrapeContacts": true,"maxReviews": 5,"geo_split": true}
Minimal input:
{"searchStringsArray": ["dentist"],"locationQuery": "Edinburgh, UK","maxCrawledPlaces": 5}
Available as the MCP tool herus13--google-maps-scraper on mcp.apify.com and through the Apify API; send the same JSON.
Why this scraper
- Contact data is included. Emails, the personal-or-generic classification in
email_type, and links to the business's Facebook, Instagram, X, LinkedIn, YouTube, TikTok, Discord, Telegram, WhatsApp, Pinterest, Threads, Snapchat, GitHub, Reddit and Twitch pages all arrive at the one result price. Most Google Maps scrapers bill those as extras on top of a lower headline price. The links are read from the business's own website, plus any social page Google lists as its website; the run never visits the social platforms themselves, so you get the link, not follower counts, bios or posts. - Filters and detail cost nothing extra. Search filters, the place detail groups, reviews and photos are all part of the one result price. Many Google Maps scrapers charge a separate fee for each filter, social profile or contact add-on, and on the Free plan those fees can add up to more than the headline price.
- Forty-two fields per business, including the ones people usually have to go back for: opening hours, open-now status, neighborhood, timezone and country code, plus popular times, menus, hotel prices, fuel prices, EV chargers and transit departures wherever Google has them.
- Whole regions, not one map view. Google itself stops at roughly 120 businesses for a single map view. Turn on
geo_splitand a state- or country-wide search is split into a grid and covered cell by cell. - Drop-in replacement. The input field names match the Google Maps actor most teams already use, so an existing configuration can be pasted in unchanged.
- No duplicates. Rows are keyed on the Google place ID, so the same business never appears twice in one run.
Use cases
- Local lead generation — a search term plus a location gives you a contactable list, with phone, site, emails and social media links already on the row, rather than a list of names you then have to enrich somewhere else.
- Sales prospecting with qualification built in — ratings, review counts and opening hours arrive in the same row as the contact details, so a list can be filtered down to businesses that are active and well reviewed before anyone picks up a phone.
- Local SEO auditing — compare how businesses show up for a term across areas and find the ones with no site or an incomplete listing, which are exactly the openings an agency sells against.
- Market research and territory mapping — every record carries coordinates, so results drop straight into a mapping or territory-planning tool.
- Competitor tracking — schedule the same search weekly and watch new entrants, closures and rating movements in a territory.
FAQ
Do I need a proxy? A residential proxy is included in the price of the run. To use your own, paste gateway URLs into Your own proxy URLs.
What happens if my input is wrong? The run stops before it scrapes anything, so no results are charged. Its status and log name each field that is wrong and say what to change — fix the input and run again.
How many results can I get for one search? Google returns about 120 businesses for a single map view. Set geo_split to true and the area is split into a grid, which returns thousands of businesses across a state or country in one run. maxCrawledPlacesPerSearch still caps each search term, across every cell of the grid.
Why did I get fewer results than expected? Google ran out of businesses that match your filters. Both limits count businesses that match, so the run keeps searching past the ones a filter leaves out, and you only get fewer when the area has no more. Strict filters get there fast: with website: "withoutWebsite" often only one plumber in ten qualifies, and a business whose only site is a Facebook, Instagram, WhatsApp or other social page counts as having no website (that page arrives in social_links instead). The run log shows, for each search term, how many businesses Google showed and how many matched. Turn on geo_split to search a wider area.
How do I get reviews? Set maxReviews above 0 and each row gains author, star rating, text, date and the owner's reply. Each business gets up to maxReviews reviews with text (star-only ratings are left out); for a full review history, including star-only ratings, use the Google Maps Reviews Scraper below.
Why are some emails missing? Not every business publishes one. Service businesses such as law firms, dentists and plumbers have far better email coverage than restaurants or retail.
Does it work well for you? A short rating on the actor page helps other people find it, and a note in the Issues tab gets a reply.
Is this legal? The actor collects publicly available business information only. You remain responsible for complying with Google's terms and with the law that applies to you, and you should not collect personal data without a lawful basis for it.
Related actors
- Google Maps Reviews Scraper — every review for a place: text and English translation, star rating, photos, owner replies and reviewer details.
- LinkedIn Profile Scraper — structured LinkedIn profiles with full experience history and optional email and phone enrichment.
- LinkedIn Jobs Scraper — LinkedIn job listings with company enrichment, salary and recruiter information.
- TikTok Shop Product Scraper — TikTok Shop products across 10 regions: variants, prices, seller information, ratings and sold counts.