Google Maps Place Details Scraper – Bulk Place ID Lookup
Pricing
from $1.20 / 1,000 results
Google Maps Place Details Scraper – Bulk Place ID Lookup
Google Maps place details scraper: paste place IDs or place links and get the full record for each, with address, phone, website, rating, weekly hours, role emails, social profiles and WhatsApp. For lead generation and CRM enrichment.
Pricing
from $1.20 / 1,000 results
Rating
0.0
(0)
Developer
Locomint
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
This Google Maps place details scraper takes the place IDs or place-page links you already have and returns the full record for each one: address, phone, website, rating, all seven days of opening hours, and the role mailboxes, social profiles and WhatsApp number published on the business's own website.
{"placeIds": ["ChIJPy04-ZkzGQ0RvdLuGmOMygg"]}
What it does
There is no search step. Each reference is read directly, so every row in the dataset is a place you asked for and nothing is spent on places you did not.
Three forms of reference are accepted, and each is converted to the same place ID:
| You paste | Example |
|---|---|
| A place ID | ChIJPy04-ZkzGQ0RvdLuGmOMygg |
| A feature ID | 0xd193399f9382d3f:0x8ca8c631aeed2bd |
| A place-page link | https://www.google.com/maps/place/CDL+-+Dental+Clinic+Lisbon/data=!4m2!3m1!1s0xd193399f9382d3f:0x8ca8c631aeed2bd |
All three rows above point at the same clinic, and the actor would read it once: references are deduplicated after conversion. A link is read for its !1s0x…:0x… part, or for a ChIJ… ID in a place_id or q parameter. Short share links (maps.app.goo.gl/…) are not expanded, so open the link in a browser and paste the full address from the address bar.
Each place then gets:
- The full listing: name, categories, the address split into street, city, region, postal code and country, coordinates, the phone as displayed and in E.164 form, website, rating, review count, open or closed status, description, opening hours for all seven days, timezone, plus code, photo count with up to five photo URLs, and attributes such as delivery or dine-in.
- The business website (
includeEnrichment, on by default): the homepage, plus one hop to the contact page when the homepage is missing an email address or a WhatsApp number. It returns role mailboxes, social profile links (Facebook, Instagram, LinkedIn, X, YouTube, TikTok), a WhatsApp number from click-to-chat links, the contact page URL, the technologies the site runs on (about 35 signatures) and awebsite_status.
A reference that is not recognised, or a place that no longer exists, produces no row and no charge. If a listing cannot be read at that moment, the place is skipped rather than delivered half-empty. The last log line says how many of your IDs were delivered, so you can re-run the rest.
What each row contains
| Group | Columns |
|---|---|
| Identity | place_id, cid, name, primary_category, categories, description |
| Location | address, street, city, region, postal_code, country_code, lat, lng, plus_code, timezone, service_area_business |
| Listing contact | phone (as displayed), phone_e164, website |
| Reputation | rating, review_count, price_level |
| Status and hours | status, open_now, hours, hours_status |
| Media and attributes | photos_count, photo_urls, attributes |
| From the website | emails, socials, whatsapp, contact_form_url, tech_stack, website_status, enriched_at |
| Provenance | source, fetched_at |
hours is keyed by weekday. Each day is a list of {"open": "09:00", "close": "18:00"} periods in local 24-hour time; an empty list means closed that day, null means unknown, and 00:00 to 24:00 means open all day. hours_status is ok when the full week was read, not_published when the listing gives no hours, and unavailable when the listing has hours but the read did not return the whole week.
website_status is one of ok, unreachable (the site was down or refused the request), parked (a domain-for-sale page), redirect_social (the "website" is a Facebook or Instagram page, kept in socials) or no_website.
Who it is for
- CRM enrichment. Refresh phone, website, hours and status for the accounts you already hold, keyed on
place_id, and add the role mailbox and WhatsApp line where the record has none. - Lead generation. Complete a list from another tool that has place IDs but no contacts. Each row comes back with the business's own role mailboxes, social profiles and WhatsApp.
- Sales prospecting. Re-read a call list before a campaign, so reps dial the number on today's listing rather than the one captured months ago.
- Agencies. Check client listings every week for changed hours, phone numbers, websites or categories.
- Local SEO. Track
ratingandreview_countfor a fixed panel of competitors over time. - Market research. Re-read the same sample of places at intervals;
place_iddoes not change, so rows join cleanly across runs.
How to use it
- Open the actor in Apify Console and click Try for free.
- Paste place IDs or feature IDs into Place IDs, one per line, or full place-page links into Place page links. Up to 1,000 per run across both fields.
- Leave Enrich from the business website on for contacts, or turn it off for listing data only. The price is the same.
- Click Start and export the dataset to CSV, Excel or JSON, or read it through the API.
The synchronous endpoint runs the actor and returns the rows in one request:
curl -X POST "https://api.apify.com/v2/acts/locomint~google-maps-place-details-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"placeIds": ["ChIJPy04-ZkzGQ0RvdLuGmOMygg"]}'
That endpoint waits at most 300 seconds, which is about 100 records. For longer lists use the Python client (pip install apify-client), which starts the run and waits for it to finish:
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")ids = [line.strip() for line in open("place_ids.txt") if line.strip()]run = client.actor("locomint/google-maps-place-details-scraper").call(run_input={"placeIds": ids})for record in client.dataset(run.default_dataset_id).iterate_items():print(record["place_id"], record["phone_e164"], record["emails"], record["hours_status"])
Input example
{"placeIds": ["ChIJPy04-ZkzGQ0RvdLuGmOMygg","0x3e5f43fb0778138f:0xec413d37c36bb02e"],"placeUrls": [{ "url": "https://www.google.com/maps/place/CDL+-+Dental+Clinic+Lisbon/data=!4m2!3m1!1s0xd193399f9382d3f:0x8ca8c631aeed2bd" }],"includeEnrichment": true,"language": "en"}
The link points at the same clinic as the first ID, so this input produces two records, not three, and is charged for two.
| Field | Default | What it does |
|---|---|---|
placeIds | – | ChIJ… place IDs or 0x…:0x… feature IDs, one per line. |
placeUrls | – | Full place-page links; the ID is read from the link. |
includeEnrichment | true | Visit each business website for contacts and tech stack. Same price either way. |
language | en | Language for names and categories (en, de, ar, ja, …). |
Give at least one ID or link. Both fields together are capped at 1,000 references per run after duplicates are removed.
Output example
The Lisbon clinic from the input above, trimmed to the columns from a captured run. The full row carries every column listed under What it does, including emails, hours and hours_status.
{"place_id": "ChIJPy04-ZkzGQ0RvdLuGmOMygg","cid": "633473054880486077","name": "CDL - Dental Clinic Lisbon","primary_category": "Dental implants provider","phone_e164": "+351213540059","website": "https://dentistalisboa.com/","rating": 4.8,"review_count": 272,"status": "open","address": "R. Ferreira da Silva 9B, 1900-228 Lisboa, Portugal","street": "R. Ferreira da Silva 9B","city": "Lisbon","country_code": "PT","socials": {"facebook": "https://www.facebook.com/…","instagram": "https://instagram.com/clinicadentarialisboa","linkedin": "https://www.linkedin.com/…"},"whatsapp": "+351916423353","contact_form_url": "https://dentistalisboa.com/contactos/","tech_stack": ["wordpress", "cloudflare"],"website_status": "ok"}
Missing values are null or an empty list, never guessed.
Pricing
This actor is pay-per-event. You pay for two events and nothing else; Apify platform usage and proxy traffic are not billed to you separately.
| Event | Price | Charged |
|---|---|---|
| Record delivered | $0.0015 ($1.50 per 1,000) until 26 September 2026, then $0.0025 ($2.50 per 1,000) | once per row in the dataset |
| Actor start | $0.00005 per GB of run memory | once per run ($0.00005 at 1 GB) |
Worked example. 1,000 place IDs exported from your CRM: 1,000 x $0.0015 = $1.50, plus $0.00005 for the start. From 26 September 2026 the same run is $2.50.
You are not charged for references that are not recognised, for places that no longer exist or could not be read, or for duplicates within one run. Set a maximum cost per run in the run options and the actor stops before the next row would pass it. Apify's free plan includes $5 of usage a month with no card.
FAQ
Where do I get place IDs?
Most Google Maps scrapers export a place_id or placeId column in the ChIJ… form, and the official Places API uses the same IDs. You can also open a business on the map and copy the link from the address bar. Numeric CIDs are not accepted.
What happens to an ID that no longer resolves? It produces no row and no charge. The log counts references that were not recognised, and the last line says how many of your IDs were delivered.
Why do some records have no email? The business has no website, the site did not answer, or it publishes no role mailbox on its homepage or contact page. A 403 or a challenge page counts as a refusal, and the actor does not retry it through another IP. Mailboxes that name a person are dropped on purpose.
Does it include reviews?
No. Every record carries rating and review_count, but not review text. The reviews_summary column exists for compatibility and is empty in this actor.
Are the opening hours for the whole week?
Yes, when the listing publishes them: hours carries all seven days and hours_status is ok. The source sometimes answers with today's hours only; the actor then reads the listing once more, and a record that still lacks the full week says hours_status: "unavailable", so you can put that ID in your next run.
How fresh is the data?
Every run reads the listing and the website live, at the time of the run; nothing comes from a stored database. Each record carries fetched_at for the listing read and enriched_at for the website read.
Is it legal to scrape Google Maps? The actor reads publicly available listing pages and business websites while logged out. It never signs in, never solves a CAPTCHA, and backs off when a site refuses it rather than retrying through another IP. Whether a particular use is lawful depends on your jurisdiction and on what you do with the data, and that part is your responsibility.
Can I run the same list every week?
Yes. Schedule the run in Apify; each run charges for the rows it delivers. Comparing phone, website, hours, rating and review_count between two runs shows what changed.
Limits
- Run size. 1,000 references per run. There is no search and there are no filters in this form; to find places, use one of the two search actors below.
- Speed. Listing reads are paced at about 20 a minute, so 1,000 records take close to an hour.
- References. Short share links are not expanded and numeric CIDs are not accepted.
- Reviews. No review text.
reviews_summary,snapshot_idandfirst_seen_atare always empty in actor runs. - Websites. Pages are read as served, without running JavaScript, so a contact page that only appears after scripts load is missed. The actor reads the homepage and at most one contact page. A site that takes longer than 20 seconds is abandoned: that row keeps its
websitebut showswebsite_status: "no_website"withenriched_at: null, meaning the site was not read. - Emails. Role mailboxes only, such as info@, sales@ and bookings@. An address on another domain, a Gmail account for example, is kept only when its name is a business function.
- Phones.
phoneandphone_e164come from the listing, not from the website.phone_e164is empty when only a national number was offered and the calling code cannot be settled safely (+1 and +7 are each shared by several countries). - Fields not yet seen filled.
price_levelhas not been populated in any record we have captured, and closed markers have not appeared in our captures either. - Addresses. Service-area businesses with no storefront have an empty
addressandservice_area_business: true;latandlngare still set.street,regionandpostal_codeare filled only when the listing's structured address carries them.
Compliance
Business contact points only: role mailboxes published on the business's own website. Mailboxes that name a person are dropped and owner names are never collected. You are responsible for using the data lawfully (for example GDPR, CAN-SPAM and PECR for outreach).
Questions, bug reports and feature requests go on this actor's Issues tab. Business owners can send data-removal requests to info@locomint.io; that address is for removal requests only. This actor keeps no copy of what it reads between runs, so each run returns what the public pages show at that moment.
Not affiliated with or endorsed by Google.
Other Locomint actors
- Google Maps Scraper & Email Extractor – Business Leads: Search terms and a city in, business records with website contacts out.
- Google Maps Scraper – Multi-City Lead Lists with Emails: Many categories across many cities in one deduplicated run.
- Website Email Scraper – Contact Details, Socials & WhatsApp: Contact points from website URLs you supply.
- Website Content Crawler – Markdown for AI, Emails & Contacts: A whole site as Markdown, with its contact points.
- Bulk Email Verifier & Validator: Checks whether addresses can receive mail.
- Company Enrichment API – Domain to Emails, Socials & Tech: A domain in, its contacts and technologies out.
- AI Crawler Checker – robots.txt Rules for GPTBot & ClaudeBot: Which AI crawlers a site's robots.txt allows.
- Schema Markup Validator & Generator – JSON-LD Checker: Checks and generates schema.org markup.