Documentation Python quickstart Blog Free tools Enterprise solutions hello@quanticdata.ioLog in
All collectors

Lead scraper API

Lead generation · v1.6.0 · local_business_leads

$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.

InputTypeRequiredWhat it does
querystringyesBusiness type — "plumber", "dentist", "officina meccanica".
locationstringyesCity or area — "Manchester, UK", "Torino".
only_with_contactsbooleannoDeliver only leads with at least one email or phone. Default false.
country · langstringnoExit geo and language — essential outside the US.
countrystringnoISO 3166-1 alpha-2 code — proxy exit geo and Google locale (gl). Omit for the default pool.
langstringnoInterface language (hl), e.g. en, it, de.
directoriesarraynoAdd 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_checkbooleannoResolve 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_emailsbooleannoAdd 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_contactsbooleannoWhen 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_emailsbooleannoFor 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.
professionalsbooleannoRead 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_phonesbooleannoOpen each professional's profile to read their phone numbers too. One extra request per professional; only meaningful with professionals.
professionals_as_leadsbooleannoWith 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_detailsbooleannoLook 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_resultsintegernoHow 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.

FieldTypeWhat it holds
name · categorystringBusiness name and Google category.
rating · reviewsnumber · integerStar rating and review count.
addressstringAddress as listed.
phone · websitestringPhone and website from the Maps listing.
emailsstring[]Emails found on the business site (mailto, JSON-LD, page text).
phonesstring[]Phones found on the site (tel: links) plus the Google number.
socialsobjectFacebook, Instagram, LinkedIn, X, YouTube, TikTok URLs when found.
source_pagesstring[]The pages actually scanned for this business.
site_statusstringscanned · no_website · unreachable · blocked.
rankinteger1-based position.
namestringBusiness name.
categorystring · nullableGoogle category.
ratingnumber · nullableStar rating.
reviewsinteger · nullableReview count.
phonestring · nullablePhone from Google.
websitestring · nullableWebsite URL.
maps_urlstring · nullableGoogle Maps link.
place_idstring · nullableGoogle place id.
data_idstring · nullableFeature id.
email_sourcestring · nullableWith serp_emails: "search_snippet" when the address came from a search result rather than from the site itself.
sourcestringWhich channel delivered the row: "google_maps" or the directory name.
sourcesstring[] · nullableWith cross_check: every channel that listed this business.
sources_countinteger · nullableWith cross_check: how many independent channels agreed on it. A buyer checking a sample checks this column first.
matched_bystring[] · nullableWith cross_check: how the channels were tied together — "phone", "address" (same street and civic plus a distinctive word) or "name".
address_confirmedboolean · nullableWith cross_check: two channels printed the same street and civic number, not merely the same name.
namesstring[] · nullableWith cross_check: the other spellings the channels used — the legal name next to the signage.
addressesstring[] · nullableWith cross_check: the addresses the channels printed, when they differ.
professionalsobject[] · nullableWith 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_checkobject[] · nullableWith 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.
hoursstring · nullableOpening 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_hoursobject · nullableWeekly opening hours as { day: hours }, when the map has them (always looked up with enrich_details).
open_statestring · nullableOpen state as the map states it ("Open", "Closed", "Temporarily closed"…).
latitudenumber · nullableLatitude of the place.
longitudenumber · nullableLongitude of the place.
price_levelstring · nullablePrice level as shown on the map ($, $$, €€…).
checked_atstring · nullableDate (YYYY-MM-DD) the row was last checked: the end of this run.
email_typestring · nullableFirst 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_urlstringGoogle 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/scraper/collectors/local_business_leads/run.

# 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

POST /v1/scraper/collectors/local_business_leads/run
$ 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.

Get my free API key
Lead scraper API: from query, location and only_with_contacts, QuanticData reads the maps listing and website and returns one row per lead with name, category and rating, at $0.01 per delivered lead.
You send query and location; the run goes out through a residential exit and comes back as leads with rank, name and category — 16 fields on every row — and you are billed $0.01 for each lead actually delivered, nothing for a run that delivers none.
$0.01 / lead200 leads on the free $2 every month
Trade + citydiscovery and enrichment in a single call
Up to 500 leadsper run, bounded per website
only_with_contactsdrop rows with no email or phone before billing

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.

$0.01per delivered lead$10 per 1,000 enriched leads
200 leadson the free allowance$2 every month, no card
Zero rowszero chargeblocks, captchas and retries are on us
−30%on volume tiersthe catalog returns your key's price

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 softwareManual researchThis collector
Deliverya licensed app on one machinea person and a spreadsheetan HTTP endpoint, any language
Enrichmentoften a separate paid stepopen every website yourselfincluded in the same run
Billingmonthly seat or licencetime$0.01 per delivered lead
Empty resultsseat is paid anywaytime is spent anywaynot delivered, not charged
Provenancerarely shownin your headsource_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.

Lead scraper API: the POST to the local_business_leads collector, 25 leads delivered and the bill, 25 × $0.01 = $0.25 in usage.cost_usd; zero leads would cost $0.
The same call you would paste into a terminal: a Bearer key, query, location and only_with_contacts in the body, and back the envelope every QuanticData endpoint returns — type, message, payload — where count is how many leads arrived and usage.cost_usd is $0.25, which is 25 × $0.01. A run that delivers nothing costs nothing. The key is good for 60 req/min on the free tier.

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 us

How 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
Illustration: three coloured zones of the page that is read (Maps listing and website) turn into clean JSON with the fields name, category and rating.