SFOLN

Catalogue / Local & maps

Google Maps Leads Scraper + Emails

sfoln/google-maps-business-leads · Lead generation, Travel, SEO tools On request

Scrape Google Maps business leads with emails: name, category, address, phone, rating and website of each place, the emails, phones and socials on its site, website signals and a 0–100 lead score with reasons. Optional email verification. $4 per 1,000 leads.

About

What it does

Turn a Google Maps search into a ready-to-use lead list: for every business found ("roofing contractors Philadelphia", "coffee roasters in Portland") the Actor takes the Google Maps data (name, category, address, phone, rating, website), visits the business website (homepage, plus one contact page if needed) and extracts emails, phone numbers and social profiles (Facebook, Instagram, LinkedIn, X/Twitter, YouTube, TikTok, Pinterest). Every lead is also qualified: website signals (HTTPS and certificate days left, mobile viewport, speed, CMS, booking and chat widgets, ad pixels, LocalBusiness data, how recently the site was updated), the listing's claimed status and photo count, phones in E.164, the e-mail domain's MX / SPF / DMARC setup and a 0–100 lead score with the reasons behind it (no website, outdated or insecure site, unclaimed listing, few reviews, not running ads). Optionally it verifies up to two emails per business at mailbox level, after a free local pre-check that drops dead domains, addresses that cannot receive mail and throw-away addresses without spending a verification. Built for agencies, B2B sales teams and AI agents that need contactable, qualified local businesses, not just map pins.

Price

Price per delivered record

EventPricePer 1,000Charged for
Business lead
lead-business
$0.004$4 / 1,000Charged once per business processed: Google Maps place data plus emails, phones and social links extracted from its website.
Verified lead email
lead-email-verified
paid plans only
$0.004$4 / 1,000Charged once per email address verified at mailbox level (only when verifyEmails is on; at most 2 per business). Addresses the free local pre-check settles (invalid syntax, no such domain, no mail server, disposable) are not sent to the verifier and not charged.

Apify free plan: up to 1 item per run. Paid plans have no per-run cap; set maxTotalChargeUsd to cap spend.

Run

Call it from code, an agent or the Console

This API is private on Apify for now. Email us and we will publish it for you, usually within two working days. The calls below work once it is public. contact@sfoln.com

curl · synchronous run, rows in the response
curl -X POST "https://api.apify.com/v2/actors/sfoln~google-maps-business-leads/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries":["coffee roasters in Portland"],"location":"Portland,Oregon,United States","maxPlaces":5}'
mcp.json · hosted Apify MCP server
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=sfoln/google-maps-business-leads"
    }
  }
}
asynchronous run · for large batches
POST https://api.apify.com/v2/actors/sfoln~google-maps-business-leads/runs?maxTotalChargeUsd=1
GET  https://api.apify.com/v2/actor-runs/{runId}            # until status is SUCCEEDED
GET  https://api.apify.com/v2/datasets/{defaultDatasetId}/items?format=json

Authenticate with an Apify API token. MCP clients can instead sign in with OAuth when prompted. Example prompt for an agent: Find 10 coffee roasters in Portland, Oregon on Google Maps with their websites, emails and phone numbers, and list the ones that have an email address.

Input

Input fields

Search Google Maps, then visit each business website to collect emails, phones and social links, audit the site and score the lead. One dataset record per business.

FieldTypeDefaultMeaning
queries *arrayrequiredSearch queries
Google Maps searches, one per line (e.g. "roofing contractors"). Override the location for a single query with "query | location". Accounts on the Apify free plan can process up to 1 query per run, limited to 10 businesses.
locationstring—Location
Location name ("Portland,Oregon,United States"), numeric location code (2840 = United States) or "latitude,longitude[,zoom]". Leave empty for the whole United States.
maxPlacesinteger20Max businesses per query
How many businesses to process (and pay for) per query, 1–100. Range 1–100.
verifyEmailsbooleanfalseVerify emails
Verify up to 2 found emails per business with a mailbox-level check (charged per verification as lead-email-verified), addresses on the business's own domain first. Stops at the first valid address. Paid plans only (turned off on the Apify free plan).
followContactPagebooleantrueAlso check the contact page
If the homepage shows no email, fetch one contact/about page on the same site.
auditWebsitebooleantrueAudit each website
Add website signals to every lead (HTTPS and certificate days left, mobile viewport, speed, title and meta description, CMS, booking and chat widgets, ad pixels, LocalBusiness data, last-updated hints), the MX / SPF / DMARC setup of its domain, and use them in the lead score. Included in the lead price.
languageCodestring"en"Language code
Language of the Google Maps results (ISO code such as en, de, es).
maxQueriesinteger20Max queries
Safety cap on the number of queries processed in this run. Range 1–1000.
concurrencyinteger5Website concurrency
How many business websites are fetched in parallel. Range 1–10.
itemTimeoutSecsinteger1800Per-query timeout (seconds)
Time limit per query. No new business is started in its last 90 seconds. Range 120–3600.
includeRawbooleanfalseInclude raw upstream response
Attach the unmodified Google Maps item to each record (larger output).
Example input
{
  "queries": [
    "coffee roasters in Portland"
  ],
  "location": "Portland,Oregon,United States",
  "maxPlaces": 5
}

Output

One record per input item

Records land in the run's dataset; a synchronous call returns them directly. Each has a status (ok is charged; everything else is free) and a charged flag. The run's OUTPUT record totals items and charges.

FieldTypeMeaning
recordTypestringRecord type
business = one lead (charged lead-business); query = per-query summary (not charged).
querystringQuery
Search query.
locationstringLocation
Location used for the search.
rankinteger | nullRank
Position in Google Maps results.
titlestring | nullBusiness name
Name on Google Maps.
categorystring | nullCategory
Primary Google category.
addressstring | nullAddress
Formatted address.
addressInfoobject | nullAddress parts
street, borough, city, zip, region, countryCode.
phonestring | nullPhone
Google Maps phone (falls back to the first website phone).
phoneE164string | nullPhone (E.164)
The listing phone (else the first website phone) in E.164, e.g. +15035550141.
phoneTypestring | nullPhone type
MOBILE, FIXED_LINE, FIXED_LINE_OR_MOBILE, TOLL_FREE, VOIP, … (libphonenumber metadata).
phonesE164arrayPhones (E.164)
Every phone of the listing and the website in E.164, de-duplicated.
websitestring | nullWebsite
Website URL (final URL after redirects when fetched).
domainstring | nullDomain
Website domain without www.
emailstring | nullEmail
Best email: first verified-valid (else catch-all) address, else the first address found (own domain first) that was not verified as invalid or disposable.
emailStatusstring | nullEmail status
valid | invalid | catch_all | disposable | unknown | error | not_verified (null when no email).
emailsarrayAll emails
All emails found on the website, own-domain first.
phonesarrayAll phones
Google Maps phone plus phones found on the website.
socialsobjectSocial profiles
facebook, instagram, linkedin, twitter, youtube, tiktok, pinterest URLs found on the website.
emailVerificationsarrayVerifications
{ email, status, method, reason? } per checked address: method precheck = settled by the free local pre-check (status invalid or disposable, reason invalid_syntax | domain_not_found | no_mail_server | disposable; never sent to the verifier, not charged), method mailbox = verified at mailbox level (charged lead-email-verified).
ratingobject | nullRating
{ value, votesCount }
isClaimedboolean | nullClaimed
The Google Business Profile is claimed by the owner.
totalPhotosinteger | nullPhotos
Photos on the listing.
currentStatusstring | nullStatus on Google
open, closed (right now), temporarily_closed or closed_forever.
websiteSignalsobject | nullWebsite signals
With auditWebsite: { reachable, status, finalUrl, error, https, sslError, sslDaysLeft, sslIssuer, mobileFriendly, title, hasMetaDescription, speed (fast | average | slow), ttfbMs, loadMs, htmlKb, cms, ecommercePlatform, technologies[], bookingWidgets[], chatWidgets[], adPixels[], runsAds, analytics[], hasLocalBusinessSchema, copyrightYear, lastModified, outdated }; null without a website.
emailAuthobject | nullE-mail domain setup
With auditWebsite: { domain, mailProvider, hasMailServer, spf, dmarcPolicy, spfDmarcLookup } of the website's domain; spfDmarcLookup failed = the SPF / DMARC lookup failed (spf null, dmarcPolicy unknown); null for a site on a shared platform domain (wixsite.com, myshopify.com …).
leadScoreinteger | nullLead score
0–100: gaps an agency can fix (no or weak website, unclaimed listing, few reviews, no ads) plus reachability (e-mail, phone). Higher = more promising.
leadTagsarrayLead tags
Segment tags behind the score, highest-scoring first: no-website, no-own-website, broken-website, ssl-error, no-https, not-mobile-friendly, unclaimed-listing, outdated-website, few-reviews, has-email, slow-website, not-running-ads, low-rating, verified-email, has-phone, temporarily-closed, permanently-closed.
leadReasonsarrayLead reasons
One sentence per tag, same order.
placeIdstring | nullPlace ID
Google place_id.
cidstring | nullCID
Google customer id.
latitudenumber | nullLatitude
WGS84 latitude.
longitudenumber | nullLongitude
WGS84 longitude.
googleMapsUrlstring | nullGoogle Maps URL
Link to the place.
sourcesarraySources
google_maps plus each website page fetched.
warningsarrayWarnings
E.g. no website, website unreachable, budget or time limit reached, duplicates skipped, verification off on the free plan.
placesFoundintegerPlaces found
Query records only.
businessesDeliveredintegerBusinesses delivered
Query records only.
businessesWithEmailintegerWith email
Query records only.
emailsVerifiedintegerEmails verified
Query records only: paid mailbox-level verifications.
emailsPrecheckedintegerEmails pre-checked
Query records only: addresses the free local pre-check settled (never sent to the verifier, not charged).
leadsScoring50PlusintegerLeads scoring 50+
Query records only: businesses with a lead score of 50 or more.
statusstringStatus
ok | not_found | error | skipped_budget | skipped_free_plan | skipped_trial
chargedbooleanCharged
Whether this record incurred a lead-business charge.
chargedEventstringCharged event
lead-business
sponsoredbooleanSponsored
true when a promotional trial paid for this record instead of you: delivered with charged false and never billed (present only then).
promotionIdstringPromotion
Id of the promotional trial that sponsored this record (present only with sponsored).
trialUnitsAppliedintegerTrial events
Events of this record the trial paid for (present only with sponsored).
retailValueWaivedUsdnumberValue waived (USD)
What those events cost at the listed prices, in USD: what you did not pay (present only with sponsored).
emailVerificationsChargedintegerVerifications charged
Number of lead-email-verified events charged for this business.
sourcestringSource
Upstream data source.
fetchedAtstringFetched at
ISO timestamp.
Example record
Example record
{
  "recordType": "business",
  "query": "roofing contractors",
  "location": "Philadelphia,Pennsylvania,United States",
  "rank": 3,
  "title": "Acme Roofing",
  "category": "Roofing contractor",
  "address": "1200 Market St, Philadelphia, PA 19107",
  "addressInfo": {
    "street": "1200 Market St",
    "borough": null,
    "city": "Philadelphia",
    "zip": "19107",
    "region": "Pennsylvania",
    "countryCode": "US"
  },
  "phone": "+1 215-555-0100",
  "phoneE164": "+12155550100",
  "phoneType": "FIXED_LINE_OR_MOBILE",
  "phonesE164": [
    "+12155550100",
    "+12155550199"
  ],
  "website": "https://www.acmeroofing.com/",
  "domain": "acmeroofing.com",
  "email": "office@acmeroofing.com",
  "emailStatus": "valid",
  "emails": [
    "office@acmeroofing.com",
    "jobs@acmeroofing.com"
  ],
  "phones": [
    "+1 215-555-0100",
    "+12155550199"
  ],
  "socials": {
    "facebook": "https://www.facebook.com/AcmeRoofingPhilly",
    "instagram": "https://instagram.com/acme.roofing"
  },
  "emailVerifications": [
    {
      "email": "office@acmeroofing.com",
      "status": "valid",
      "method": "mailbox"
    }
  ],
  "rating": {
    "value": 4.8,
    "votesCount": 212
  },
  "isClaimed": false,
  "totalPhotos": 14,
  "currentStatus": "open",
  "websiteSignals": {
    "reachable": true,
    "status": 200,
    "finalUrl": "https://www.acmeroofing.com/",
    "error": null,
    "https": true,
    "sslError": false,
    "sslDaysLeft": 41,
    "sslIssuer": "Let's Encrypt",
    "mobileFriendly": false,
    "title": "Acme Roofing | Philadelphia Roofers",
    "hasMetaDescription": true,
    "speed": "average",
    "ttfbMs": 940,
    "loadMs": 1310,
    "htmlKb": 212.4,
    "cms": "WordPress",
    "ecommercePlatform": null,
    "technologies": [
      "WordPress",
      "PHP",
      "MySQL",
      "jQuery"
    ],
    "bookingWidgets": [],
    "chatWidgets": [],
    "adPixels": [],
    "runsAds": false,
    "analytics": [
      "Google Analytics"
    ],
    "hasLocalBusinessSchema": false,
    "copyrightYear": 2019,
    "lastModified": null,
    "outdated": true
  },
  "emailAuth": {
    "domain": "acmeroofing.com",
    "mailProvider": "Google Workspace",
    "hasMailServer": true,
    "spf": true,
    "dmarcPolicy": null,
    "spfDmarcLookup": "ok"
  },
  "leadScore": 65,
  "leadTags": [
    "not-mobile-friendly",
    "unclaimed-listing",
    "outdated-website",
    "has-email",
    "not-running-ads",
    "verified-email",
    "has-phone"
  ],
  "leadReasons": [
    "The website has no mobile viewport: it is not set up for phones.",
    "The Google Business Profile is not claimed by the owner.",
    "The website looks outdated (newest copyright year 2019).",
    "An e-mail address was found on the website.",
    "No advertising pixels (Google Ads, Meta, TikTok, …) on the website: the business does not appear to buy online ads.",
    "The e-mail address passed a mailbox verification.",
    "A phone number is listed."
  ],
  "placeId": "ChIJxxxxxxxxxxxxxxxx",
  "cid": "12345678901234567890",
  "latitude": 39.9516,
  "longitude": -75.1605,
  "googleMapsUrl": "https://www.google.com/maps?cid=12345678901234567890",
  "sources": [
    "google_maps",
    "https://www.acmeroofing.com/",
    "https://www.acmeroofing.com/contact-us/"
  ],
  "status": "ok",
  "charged": true,
  "chargedEvent": "lead-business",
  "emailVerificationsCharged": 1,
  "source": "dataforseo",
  "fetchedAt": "2026-10-14T10:00:00.000Z"
}

FAQ

Questions

What does the lead score measure?
How promising a business is as a prospect for web, local-SEO and marketing services, from 0 to 100: points for each gap you could fix (no website +35, a social page instead of a website +30, a website that does not load +25, no HTTPS or a broken certificate +15, not mobile-friendly +15, an unclaimed Google listing +15, an outdated site +10, fewer than 10 reviews +10, a slow site +5, no ad pixels +5, a rating under 4 +5) and for reachability (e-mail found +10, verified +5, phone +5). Every point comes with a tag such as no-website or unclaimed-listing and a sentence in leadReasons, so you can filter and personalise outreach.
Which emails are verified, and what does a verification cost?
With verifyEmails on (paid plans), up to 2 addresses per business are verified at mailbox level, addresses on the business's own domain first, for $0.004 each. Every candidate first goes through a free local pre-check: an address whose domain does not exist or accepts no mail, a disposable address or one with invalid syntax is marked invalid or disposable right away (method precheck), is never sent to the verifier and is not charged.

Machine-readable

This page for agents