The problem with existing B2B lead databases

If you've ever shopped around for a European B2B lead database, you know the drill: Apollo and ZoomInfo are US-centric and expensive. Kaspr and Lusha work great for LinkedIn B2B SaaS buyers — knowledge workers — but they are nearly useless the moment your ICP is a restaurant, a plumber, or a hair salon. Local SMBs don't tweet, don't publish on LinkedIn, don't open your enrichment tool's free trial. They mostly live on Google Maps.

That's the gap we wanted to fill. About two years ago we started building what became Prospya — a database of 2,501,944 French, Belgian and (recently) 13-other-country local businesses, each with phone, email, website, Instagram, and the raw Google Maps enrichment. This post is what we learned doing it, not what we sell.

Where the data comes from (yes, you have to crawl)

Our first mistake was shopping for a shortcut — buying partial lists on PhantomBuster, dumping them in Postgres, hoping for the best. It fell apart in week two. Lists had 40% stale phones, duplicate rows for the same business under two spellings, and emails that had bounced for six months without anyone noticing.

The lesson: you don't buy a local-SMB database, you build one, on a cadence, and you own the pipeline.

Our pipeline today, simplified:

  1. Google Maps crawler — seeded by postal codes, category pairs ("bakery in 69001", "plumber in 75014"). We rotate residential IPs and respect the throttle.
  2. Website visit — when a business has a site, we visit it and look for mailto: links, phone patterns, and og: metadata.
  3. Social link extraction — Instagram handle, Facebook page, sometimes TikTok. These help us dedup.
  4. Dedup — the hardest part, see below.
  5. Email verification — SMTP handshake, catch-all detection, domain MX check. No gray mail.
  6. GDPR tagging — opt-outs, right-to-erasure requests, suppression list cross-check.

This pipeline runs daily on a small cluster. The crawler alone is ~8K lines of Python. Nothing fancy, just lots of edge cases.

Dedup: the hardest problem nobody talks about

Imagine a bakery named "Au Bon Pain" in Lyon. Google Maps has it at 12 rue Sainte-Marie. Yelp has it at 12 r. Sainte Marie. Their own website says 12 r. Ste Marie. The owner also runs a second shop, same name, in Villeurbanne.

We tried the naïve approach first — Levenshtein distance on name + address. It collapsed the two Lyon-area shops into one entry. Not great.

What actually works:

  • Normalize address at the postal-code level first. If two rows share postal code + street (after r. → rue, ste → sainte, - → space), they're candidates.
  • Hash the phone number in E.164 format — +33478123456 — and treat that as a strong dedup key. Two rows with the same E.164 phone are the same business 95% of the time.
  • Instagram handle is the second-strongest key. Local businesses rarely share handles across physical locations.
  • Email is a weak key. Owners reuse contact@monrestaurant.fr across three brasseries.

We ended up with a composite score: phone hash (weight 5) + Instagram handle (weight 4) + normalized address (weight 2) + name similarity (weight 1). Threshold = 7. Precision on manual review: 98.4%.

Email verification is 60% of the real work

The list is worth nothing if the emails bounce. Deliverability tanks, your sending domain gets throttled, and your sales team stops trusting the tool. We spent more engineering time here than anywhere else.

Our verification layer, in order of trust:

  1. MX record exists — basic, free, kills a lot of typos.
  2. Catch-all detection — if the domain accepts everything, the email is unverifiable, tag it "catch-all" and let the user decide.
  3. SMTP handshake with graceful fallback — some providers (Google, Microsoft) refuse SMTP probes. We've learned which providers to trust on MX alone.
  4. Role-based filter — contact@, info@, hello@ are kept but tagged; admin@, webmaster@ are usually noise.
  5. Disposable-domain blocklist — yopmail, mailinator, etc.

Rule of thumb: a lead is "sendable" if it passes 1 and (2 or 3). In France, about 61% of extracted emails hit this bar.

GDPR: a feature, not a chore

This is where a lot of US-built databases fail in Europe. We built GDPR awareness in from day one, because it was faster than retrofitting:

  • Every record carries a legal basis column (legitimate_interest for B2B contacts of businesses, consent for anything B2C-adjacent).
  • A single opt-out endpoint accepts email OR phone and suppresses the lead across all tenants. We cross-check it before every export.
  • Data retention is 18 months, after which we re-verify or drop.
  • The crawler respects robots.txt and marks businesses with noai in their meta tags.

You can argue about the legal interpretation. We're not lawyers. But having the plumbing beats not having it when CNIL asks.

What we ship

If you want to try the database, Prospya is the product. 25 free searches, no subscription, CSV export. You pay per credit when you want to unlock contacts. Nothing novel about the business model — it's roughly what Kaspr does for LinkedIn, applied to local SMBs instead.

If you're building your own and want to compare notes, the comments are open.

Takeaways (if you're building something similar)

  • Own the crawl. Don't buy lists. Lists age in weeks.
  • Dedup is the moat. Everyone can scrape; few can tell apart the two "Au Bon Pain" shops.
  • Verify every email, every month. Sendable rate drops ~3% per month without re-verification.
  • GDPR plumbing is 5 days of work, not 5 weeks. Just do it before you have 100 customers.
  • Local-SMB data is still wide open. Everyone's chasing LinkedIn knowledge workers because the ACV looks better. The local long-tail is huge, boring, and underserved.

If this post was useful, the product that came out of it is at prospya.com. We're also sometimes on Hashnode / Dev.to.