Lead scraper API
$0.01 / lead
$10.00 / 1K · pay per delivered lead
The lead scraper API takes a trade and a city — "plumber", "Manchester, UK" — finds the businesses on Google Maps, then visits each business website to collect emails, phones and social profiles. One call, one enriched row per business, $0.01 per delivered lead, and rows without contacts can be dropped before you are billed.
$0.01 per delivered lead · $2 free every month · Failed runs never billed
What it does
What a lead scraper API does
A lead scraper API returns local businesses as contactable rows: who they are, and how to reach them. Maps gives you the business and its phone; the email almost never lives there. This collector does both steps — the local search, then the business’s own website — and hands back one merged record per business.
Per lead it loads the homepage and one contact or about page, and reads emails from mailto: links, JSON-LD and page text, phones from tel: links plus the Google number, and social profiles from the site’s own links. The pages it used are on the row in source_pages, so any value can be traced back to where it was published rather than trusted blindly.
The market around "local business lead scraper" is desktop software and monthly seats. This is an endpoint billed per delivered lead — and with only_with_contacts on, a business with no reachable contact is not delivered and not charged. Already have the domains? Use the email scraper API instead, at $0.02 per site.
Inputs
Inputs: the trade and the place
Set only_with_contacts when you only want rows you can act on — filtering happens before billing.
| Input | Type | Required | What it does |
|---|---|---|---|
query | string | yes | Business type — "plumber", "dentist", "officina meccanica". |
location | string | yes | City or area — "Manchester, UK", "Torino". |
only_with_contacts | boolean | no | Deliver only leads with at least one email or phone. Default false. |
country · lang | string | no | Exit geo and language — essential outside the US. |
country | string | no | ISO 3166-1 alpha-2 code — proxy exit geo and Google locale (gl). Omit for the default pool. |
lang | string | no | Interface language (hl), e.g. en, it, de. |
directories | array | no | Add businesses listed in these Italian directories that Google Maps did not return — the operators with no web presence. Off by default: it delivers, and bills, more rows. |
cross_check | boolean | no | Resolve the same business across the channels into one record instead of delivering it twice. Matching is on the phone number, on street+civic plus a distinctive word of the name, or on the name alone when it carries two distinctive words. Adds sources, sources_count, matched_by and address_confirmed to every row. Off by default: it changes the shape of the delivered rows. |
verify_emails | boolean | no | Add email_check to each row: syntax, whether the domain has a mail server that accepts delivery (MX), whether the address is a role mailbox (info@, segreteria@) and whether the same address appears on other rows of the run. |
deep_contacts | boolean | no | When the homepage shows no email, try up to three of the site's own pages instead of one — contatti, dove siamo, and the privacy notice, which in Italy has to name the data controller with an address. Stops at the first page that yields an email. |
serp_emails | boolean | no | For businesses whose site showed no email, run one web search on their domain and keep any address the search engine quotes in its snippets — only when it is on the business's own domain. One search per such business. |
professionals | boolean | no | Read MioDottore for the same category and place and attach the professionals who practise at each business — name, specialty, profile and published prices. Maps gives you the practice and its website; this gives you the person to address the letter to. Matched by phone or by street and civic number, never by name: a dentist is not called like the clinic. |
professional_phones | boolean | no | Open each professional's profile to read their phone numbers too. One extra request per professional; only meaningful with professionals. |
professionals_as_leads | boolean | no | With professionals: the practices MioDottore lists at addresses that Maps and the directories did not return become rows of their own (source: miodottore, sources_count 1). Set false to only attach professionals to the businesses already found. |
enrich_details | boolean | no | Look up the place card of every business the map listed without its weekly hours or its review count, and fill them in (it can also add a website or phone the list row lacked). One small extra lookup per such business; off by default. |
max_results | integer | no | How many leads to deliver at most (1–500). You pay only for delivered leads. |
Outputs — 38 fields, one row per lead
What comes back for every lead
The Maps record and the website enrichment merged into one row, with the provenance kept.
| Field | Type | What it holds |
|---|---|---|
name · category | string | Business name and Google category. |
rating · reviews | number · integer | Star rating and review count. |
address | string | Address as listed. |
phone · website | string | Phone and website from the Maps listing. |
emails | string[] | Emails found on the business site (mailto, JSON-LD, page text). |
phones | string[] | Phones found on the site (tel: links) plus the Google number. |
socials | object | Facebook, Instagram, LinkedIn, X, YouTube, TikTok URLs when found. |
source_pages | string[] | The pages actually scanned for this business. |
site_status | string | scanned · no_website · unreachable · blocked. |
rank | integer | 1-based position. |
name | string | Business name. |
category | string · nullable | Google category. |
rating | number · nullable | Star rating. |
reviews | integer · nullable | Review count. |
phone | string · nullable | Phone from Google. |
website | string · nullable | Website URL. |
maps_url | string · nullable | Google Maps link. |
place_id | string · nullable | Google place id. |
data_id | string · nullable | Feature id. |
email_source | string · nullable | With serp_emails: "search_snippet" when the address came from a search result rather than from the site itself. |
source | string | Which channel delivered the row: "google_maps" or the directory name. |
sources | string[] · nullable | With cross_check: every channel that listed this business. |
sources_count | integer · nullable | With cross_check: how many independent channels agreed on it. A buyer checking a sample checks this column first. |
matched_by | string[] · nullable | With cross_check: how the channels were tied together — "phone", "address" (same street and civic plus a distinctive word) or "name". |
address_confirmed | boolean · nullable | With cross_check: two channels printed the same street and civic number, not merely the same name. |
names | string[] · nullable | With cross_check: the other spellings the channels used — the legal name next to the signage. |
addresses | string[] · nullable | With cross_check: the addresses the channels printed, when they differ. |
professionals | object[] · nullable | With professionals: who practises at this address, as { name, specialty, url, phone, prices }. The business card says "Poliambulatorio X"; this says which fifteen doctors receive there. |
email_check | object[] · nullable | With verify_emails: per address { email, status: ok | no_mx | duplicate | invalid, mx, shared_with, role }. "duplicate" means the same address is on other rows — a chain's head office, not a practice. |
hours | string · nullable | Opening hours as the map shows them: today's line, or the whole week ("Monday: 9 AM–6 PM; …") when the weekly table is known. |
weekly_hours | object · nullable | Weekly opening hours as { day: hours }, when the map has them (always looked up with enrich_details). |
open_state | string · nullable | Open state as the map states it ("Open", "Closed", "Temporarily closed"…). |
latitude | number · nullable | Latitude of the place. |
longitude | number · nullable | Longitude of the place. |
price_level | string · nullable | Price level as shown on the map ($, $$, €€…). |
checked_at | string · nullable | Date (YYYY-MM-DD) the row was last checked: the end of this run. |
email_type | string · nullable | First email of the row: "generic" for a role mailbox (info@, segreteria@, the same rule as email_check.role), "personal" otherwise, null without an email. |
place_id · data_id · maps_url | string | Google ids and the listing link. |
Integration
One POST, typed rows
Base URL https://api.quanticdata.io/v1, Bearer auth, the same key as every other Data API. Endpoint: POST /v1/.
# 25 plumbers in Manchester, contacts required
curl https://api.quanticdata.io/v1/scraper/collectors/local_business_leads/run \
-H "Authorization: Bearer $QD_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "query": "plumber", "location": "Manchester, UK",
"country": "gb", "only_with_contacts": true,
"max_results": 25 }'
Example response
$ curl $QD/local_business_leads/run \
-H "Authorization: Bearer $QD_API_KEY" \
-d '{ "query": "plumber", "location": "Manchester, UK",
"only_with_contacts": true, "max_results": 25 }'
{ "status": "done", "count": 21,
"results": [
{ "name": "Northside Plumbing", "rating": 4.9,
"website": "https://…", "phone": "+44 161…",
"emails": ["info@…"], "phones": ["+44 161…"],
"socials": { "facebook": "https://…" },
"source_pages": ["https://…/contact"] } ],
"cost": 0.21 }
# 21 leads × $0.01 · the 4 without contacts were not billed
Try it
Local business leads, running now
Change the input and run it against the live collector — nothing to install, no sign-up.
Run it from your own code, on your own inputs
Same collector, same rows — $2 of free API credit every month, no card.
Pricing
What an enriched lead costs
A delivered lead is $0.01 — website visits, parsing and retries included, not billed separately. A thousand enriched leads is $10 at list price, against a market that sells desktop licences and monthly seats; the free $2 covers about 200 leads a month.
Pay as you go
- $2 free credit / month
- 60 requests / min
- List unit prices
Starter
- $15 free credit / month
- 300 requests / min
- 10% off unit prices
Growth
- $50 free credit / month
- 600 requests / min
- 20% off unit prices
Scale
- $250 free credit / month
- 1,200 requests / min
- 30% off unit prices
Same wallet, same key and same $2 monthly allowance as every other Data API. Prices are launch pricing read live from the billing config — GET /v1/scraper/collectors returns the price your key actually pays.
What people run it for
Local B2B outreach is the whole market around this keyword — these are the shapes it takes.
Agency prospecting
One run per trade and city gives a callable list with emails, phones and socials, plus rating and review count to qualify by size before anyone picks up the phone.
Territory mapping for field sales
Run the same trade across the towns in a rep’s patch and you have coverage: who exists, who has a website, who is reachable, who is not.
Marketplace and directory seeding
Populate a vertical directory with real businesses and verified-looking contact points, keeping source_pages so every value can be re-checked later.
CRM hygiene
Re-run a segment quarterly and diff it: closed businesses, changed numbers, new websites. Pair with the company data API when you want the full profile per domain.
Collector vs lead software vs doing it by hand
What the "local business lead scraper" market sells, and how an endpoint differs.
| Desktop lead software | Manual research | This collector | |
|---|---|---|---|
| Delivery | a licensed app on one machine | a person and a spreadsheet | an HTTP endpoint, any language |
| Enrichment | often a separate paid step | open every website yourself | included in the same run |
| Billing | monthly seat or licence | time | $0.01 per delivered lead |
| Empty results | seat is paid anyway | time is spent anyway | not delivered, not charged |
| Provenance | rarely shown | in your head | source_pages on every row |
What people search for
Live autocomplete demand around Local business leads, pulled with our own Keyword ideas collector.
Where a contact database stops and a website starts
Commercial B2B databases are strong at mapping named people to companies, and no amount of website reading substitutes for a verified direct dial. Their coverage skews to companies with a professional-network footprint, which means the dentist, the plumber and the independent restaurant are thin or absent — and their records age between verification passes.
This reads what the business publishes about itself today. That is a different consent posture from an inferred personal address, and for local businesses it is frequently the only contact route that exists. The two are complements: buy a database for named decision-makers at larger firms, collect local businesses in a category and city.
Limits, bounded crawling and the legal bit
Up to 500 leads per run, lower than the search collectors because each lead is a Maps result plus two website fetches. Enrichment is deliberately bounded — homepage plus one contact page — so a contact buried five clicks deep is missed rather than chased with an unbounded crawl. source_pages records where every contact came from, and site_status separates "no website" from "site failed to load". Throughput is your plan's rate limit rather than anything about the collector: 60 requests/minute on pay-as-you-go, up to 1,200 on the top tier.
Collection and use are governed separately, and this is the collector where that matters most. Collecting contacts a business publishes is generally lawful in most jurisdictions. Sending to them is governed by GDPR and PECR in Europe, CAN-SPAM in the US and CASL in Canada — and some of those require consent before the first message. A sole trader's address is personal data even on a business site. Get advice on the outreach, not just on the collection. None of this is legal advice — get some for your actual use case.
Sources and standards
The platform documentation and standards this collector is built against — check any claim on this page against the primary source:
FAQ
The practical and the legal questions people ask before scraping business contacts.
Something else? Ask usHow do you find business emails for free?
The $2 monthly allowance covers about 200 enriched leads with no card. Beyond that it is $0.01 per delivered lead — and with only_with_contacts enabled, businesses where no email or phone could be found are not delivered and not billed.
Can I scrape emails from Google Maps?
Not from Maps itself: Google shows a phone and a website, not an email. This collector takes the extra step for you, visiting each business website and reading emails from mailto links, JSON-LD and page text, then returns them on the same row as the Maps data.
Is scraping business contact details legal?
Business contact details published on a company’s own website are public, and collecting public data is generally lawful in most jurisdictions — but an address like [email protected] can still be personal data under the GDPR, and outreach is regulated separately. Have a lawful basis, honour opt-outs, and take proper advice.
How accurate are the emails?
They are the addresses actually published on the business’s own pages — not guessed patterns and not a bought database. The source_pages field lists the pages each row was built from, so anything questionable can be verified at the source. No deliverability verification is performed.
How long does a run take?
Small runs answer inline; anything above five leads goes asynchronous, returns a run_id immediately and is polled — each lead means real page loads. Rows are exportable as CSV from the run endpoint with ?format=csv.
What if a business has no website?
You still get the Maps record, with site_status: no_website and whatever phone Google shows. If those rows are not useful to you, set only_with_contacts and they will not be delivered — or billed — at all.
Why does it cost ten times the Maps collector?
Because each lead is three fetches rather than one: the Maps result, then the homepage and a contact page on the business's own site. If you do not need contacts beyond the listed phone number, the Maps collector is the cheaper and correct choice.
How do I avoid paying for businesses I cannot contact?
Set only_with_contacts. Rows with neither an email nor a phone are then suppressed and unbilled, which on most categories is a meaningful share of the result set.
Start with the Lead scraper API
$0.01 per delivered lead, $10 per 1,000 enriched leads. $2 of free credit every month, no card — and a run that delivers nothing is never billed.
Run in dashboard