Scrape businesses from Google Maps and get their emails, phones and social profiles from their websites in one run. Includes address, rating, reviews, hours and coordinates. Replaces a Maps scraper plus an email extractor. Pay only per result.
Decisions and deviations (documented per the project conventions)
Node 22 instead of 20 (apify/actor-node:22). Node 20 reached end-of-life on 2026-04-30. Dev tooling (vitest 5) also requires ≥ 22.12.
Default Google proxy is RESIDENTIAL, not plain { useApifyProxy: true }. Google blocks datacenter IPs. The exit country is matched per query: inferred from the text ("Austin, TX" → US), or taken from countryCode.
Websites use a separate enrichmentProxyConfiguration (datacenter by default). About 750 KB of HTML per enriched place over residential proxy (~$8/GB) would cost more than the $0.005 place-enriched fee. Decided with the owner.
Review counts need a cookie. Google omits review counts from about 7 in 8 cookieless responses. Sessions persist cookies, and a response with no counts is retried up to 2 times on a warmed session.
Plus codes are computed locally (Open Location Code, verified against Google-issued codes), because search results don't include them.
maxResults (default 50) is a total cap across all queries, next to the requested maxPlacesPerQuery (default 50). The user conventions require maxResults with default 50; the input description tells users to raise it when adding queries.
Website retries are capped at 2, and session rotations at 1. Crawlee otherwise retries connection errors up to 10 times regardless of maxRequestRetries, and one dead website held a whole run for about 2 minutes in testing.
Budget stops cancel only the Google crawler. Website crawls always hold a budget reservation, so work that is already paid for finishes.
Individual reviews and reviewer names are never collected (GDPR data minimization). The details fixture was stripped of review texts for the same reason.
charge() after pushData(), as the conventions require, rather than Actor.pushData(item, eventName). The Actor bills two events per item and needs per-item control over the enrichment event.
Known limitations
Google Maps returns at most about 120 places per query; split big areas into several queries.
Place URLs (/maps/place/...) aren't accepted as start URLs.
Websites that render contacts only with JavaScript (SPA contact widgets) or behind forms yield no emails.
personal email classification means "not a recognized role address". It isn't identity verification.