Website Email & Contact Scraper - Scored Leads
Pricing
from $6.00 / 1,000 contact founds
Website Email & Contact Scraper - Scored Leads
Find the e-mail, phone and socials behind any list of websites - plus a technical profile (CMS, SSL, mobile, analytics, site age) and a lead score telling you who is worth contacting first. Pay only for contacts found.
Pricing
from $6.00 / 1,000 contact founds
Rating
0.0
(0)
Developer
Gezgin Data
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
6 days ago
Last modified
Categories
Share
Find the e-mail address, phone number and social profiles behind any list of websites — and, in the same run, learn which of those businesses are actually worth contacting. Paste in domains, get back contactable, scored leads. No API key, no browser, no LLM.
Most contact scrapers stop at the address. This one also reads what the website says about the business running it — which CMS it uses, whether it has SSL, whether it works on a phone, when it was last touched, whether anyone is measuring anything — and turns that into two auditable scores. Those few fields are the difference between an address list and a work list.
On fresh test batches it had never seen — roofing contractors in Essen, Germany and Austin, Texas — it found an e-mail address for 78% and 80% of them respectively. The measurement, and an honest list of what it gets wrong, are further down.
What it does
Give it example.com (or a full URL — both work) and for every site it will:
- Fetch the homepage and look for contact details in descending order of confidence:
mailto:links, Cloudflare-obfuscated addresses, schema.org structured data, the raw source, then the visible text. Addresses written asname [at] example [dot] comare decoded. - Follow the contact page when the homepage came up short — the discovered link plus the
paths most business sites have anyway (
/kontakt,/impressum,/contact,/contacto, …). - Profile the site from HTML it already downloaded — no extra requests, no extra time.
- Score the lead on two separate questions, and show its work.
Give it a link-in-bio hub instead — linktr.ee/name, Beacons, Stan, Taplink and a couple of
dozen others — and it opens the hub, finds the real website behind it and audits that. This matters
more than it sounds: pointed at a Linktree, a scraper that does not resolve reads the hub's own page
and returns whatever it finds there. On a live test that produced a Linktree advertiser's address as
the contact for a Berlin tattoo studio. Resolved, the same input returns the studio's own address on
its own domain. Businesses whose entire web presence turns out to be a hub come back tagged
linktree_only — for anyone selling web work, those are the best rows in the file.
How the scoring works
Two scores, deliberately not merged. A flawless website that answers every channel is a poor lead for a web agency; a neglected one you can barely reach is a good one. One number would hide exactly that.
contactabilityScore — can you reach them?
| Signal | Points |
|---|---|
E-mail, personal (jan.meier@…) | 50 |
E-mail, role (info@, kontakt@, office@, hello@) | 40 |
E-mail, department (press@, jobs@, support@, datenschutz@) | 15 |
E-mail, noreply@ | 0 |
Phone from a tel: link | 25 |
| Phone from labelled text ("Tel: …") | 20 |
| Contact form | 15 |
| Any social profile | 10 |
E-mail points are multiplied by how much the source can be trusted: 1.0 for a mailto: link,
structured data, a Cloudflare-obfuscated address or a contact page — these were published as
contact points on purpose. 0.75 for a regex hit in the raw source or page text, which could be
anything. The result is reported as emailConfidence: high | medium.
Capped at 100.
opportunityScore — do they visibly need help?
| Finding | Points | |
|---|---|---|
site_unreachable — the website did not respond | 40 | |
stale_site_severe — copyright 6+ years old | 35 | |
no_ssl — still on http | 28 | |
not_mobile_friendly — no viewport meta tag | 25 | |
stale_site — copyright 3–5 years old | 20 | |
outdated_cms_hint — Wix or Squarespace | 12 | |
no_analytics — no GA, Meta Pixel, Hotjar or LinkedIn Insight | 10 | |
no_social_presence — no social links found | 8 | |
no_contact_form — only ever reported if a contact page was actually opened | 7 |
Capped at 100. Every finding that fired is listed in opportunityTags.
leadPriority
contactabilityScore == 0 → cold (no way to act on it)contactability ≥ 50 and opportunity ≥ 25 → hotcontactability ≥ 50 and opportunity ≥ 10 → warmcontactability ≥ 50 or opportunity ≥ 25 → warmotherwise → cold
It shows its work
Every row carries a scoreBreakdown naming each contribution, so the ranking can be audited
rather than believed:
{"website": "https://www.maler-stefanbeckmann.de/","email": "hallo@malermeister-stefanbeckmann.de","emailType": "role","emailConfidence": "high","contactabilityScore": 85,"opportunityScore": 57,"leadPriority": "hot","opportunityTags": ["stale_site_severe", "outdated_cms_hint", "no_analytics"],"scoreBreakdown": {"email:role": 40, "phone": 25, "social_profiles": 10,"opportunity:stale_site_severe": 35,"opportunity:outdated_cms_hint": 12,"opportunity:no_analytics": 10}}
Read plainly: reachable by e-mail, phone and social, on a Wix site last touched six years ago with no analytics installed. That is a conversation waiting to happen.
These weights are reasoned judgements, not learned values, and they assume you sell websites,
hosting or marketing. If you sell something else, ignore opportunityScore and sort by
contactabilityScore and emailType instead — the raw fields are all there.
Who it is for
Agencies and freelancers building a prospect list: the tags say who needs a new website, who runs no tracking, and who is invisible on a phone.
Sales teams turning a list of company domains into something they can mail or call.
Anyone holding the output of another scraper. Google Maps, directories, marketplaces — nearly every scraper returns websites but no e-mail addresses. This is the step that comes after, and it takes that output directly.
AI agents and automations. One required field, everything else defaulted, a flat JSON row per
website and a machine-readable RUN_STATUS record. An empty result always states its reason, so a
failed run can never be mistaken for "this business has no contact details".
How to use it
- Paste your websites into Websites, one per line. Plain domains are fine.
- Leave Also profile the website on unless you only want raw contacts.
- Run it, then sort the output by
leadPriorityand start at the top.
Duplicates pointing at the same host are removed, so you are never billed twice for one business.
Input
| Field | Default | What it does |
|---|---|---|
startUrls | — | Websites to process. Domains, full URLs, or link-in-bio hubs. Required. |
resolveLinkHubs | true | Open a Linktree, Beacons, Stan or Taplink URL and audit the real website behind it instead of the hub itself |
enrichSite | true | Profile the site (CMS, SSL, mobile, age, analytics, socials) |
maxContactPages | 5 | How hard to look when the homepage yields nothing. 0 = homepage only |
onlyWithContact | false | Drop rows where nothing was found |
maxConcurrency | 10 | Sites fetched in parallel |
maxRunTimeSecs | 3000 | Stops cleanly before this and keeps everything found |
Output
One row per website, whether or not something was found. Download as JSON, CSV, Excel or HTML, or pull it through the API.
| Field | Meaning |
|---|---|
inputUrl, website | What you supplied, and what was actually audited. They differ only when the input was a link hub and the real site behind it was found |
websiteSource | input or link_hub — how the audited site was arrived at |
statusNote | One plain sentence explaining a row that looks empty: a hub with no site behind it, a hub that rate-limited us, a dead domain, or a host that refused us |
hub, hubUrl, hubStatus, hubFetchStatus, hubLinks | Which hub was opened, what came of it, and every link it carried |
finalUrl | Where the audited site ended up after redirects |
siteReachable, fetchStatus | ok, http_403, timeout, dns_error, connect_error. Only a genuine non-answer counts as a sales signal — a 403 means the host refused us, which says nothing about the business |
email, emailSource, emailType, emailConfidence | Address, where it was found, who is behind it, how much to trust it |
phone, phoneSource | Normalised number, from a tel: link or a labelled line |
contactPageUrl, contactPageChecked | Which contact page was opened, if any |
socialLinks | Facebook, Instagram, LinkedIn, X, TikTok, YouTube |
cms | Detected from structural evidence only, never a brand name mentioned in text |
copyrightYear | Latest year in the footer; ranges like "© 2004–2026" handled correctly |
hasSsl, mobileFriendly | From the final URL after redirects, and the viewport meta tag |
hasTracking, trackingTools | Google Analytics, Meta Pixel, Hotjar, LinkedIn Insight |
hasContactForm | A form carrying an e-mail field or a textarea |
contactabilityScore, opportunityScore, opportunityTags, leadPriority, scoreBreakdown | The scoring above |
The key-value store also holds RUN_STATUS with the outcome, how many websites were processed and
the e-mail hit rate for the run.
Pricing
You pay per contact found and per site profiled. A website that yields nothing costs nothing — charging for a miss would be charging for our own failure. Any single run can be capped from the Apify console.
What it does well, and where it falls short
Every scraper listing claims to be accurate. Here is what was actually measured, and what is genuinely wrong with this one — you will find out either way, and it is cheaper for both of us if you find out before you pay.
Measured on samples it had never seen
Both test batches were pulled fresh from Google Maps after development finished, so none of them influenced the code. Nine roofing companies in Essen, Germany, and ten in Austin, Texas:
| Germany | USA | |
|---|---|---|
| E-mail found | 78% | 80% |
| Phone found | 78% | 90% |
Refused entry (403) | 0 | 1 |
A sample of records was then checked by hand against the live sites. That check found one real
defect — a phone number mangled by a URL-encoded space in a tel: link — which has been fixed and
re-verified. Everything else held, including the cases where "nothing found" turned out to be the
correct answer rather than a miss.
What it does better than the alternatives
It ranks leads, and shows why. Every other contact scraper hands you addresses. This one tells
you which businesses are worth the call and prints its arithmetic in scoreBreakdown, so you can
disagree with it on the evidence rather than on faith.
It declares what it does not know. emailConfidence separates an address published in a
mailto: link from a regex hit in body text. fetchStatus distinguishes "their site is down"
from "their host refused us". likelyJsRendered marks pages we could not really read. An empty
result always carries a reason in RUN_STATUS.
It costs almost nothing to run — around two seconds per website, no browser, no proxy required, comfortably inside the free tier.
Where it falls short
About 5% of hosts refuse it outright. The Actor already retries with several browser
fingerprints, which cleared two thirds of the refusals seen in testing, but some WAFs check for
JavaScript execution and cannot be talked around. Those rows say fetchStatus: http_403 and
deliberately carry no opportunity signal — the Actor will not tell you a business has a broken
website when the truth is it would not let us in. A residential proxy usually gets through them.
Sites that build themselves in the browser come back empty. Being browser-free is what makes
this fast and cheap; the cost is that a single-page app hands us a shell. Those rows are flagged
likelyJsRendered, and the "no social presence" and "no contact form" findings are suppressed for
them, because we never actually saw the page.
Link hubs throttle, and there is no way around it. Linktree serves roughly ten to eleven
requests per run before answering HTTP 429. Measured: fifteen hub URLs in one run left four
unresolved; a longer backoff changed nothing except the runtime, and routing through Apify's shared
datacenter proxy made it worse, not better. Those rows come back hubStatus: fetch_failed with
hubFetchStatus: http_429, carry no opportunity signal, and cost you nothing — you are billed for
contacts found and sites profiled, never for a hub we could not open. If your list is unusually
hub-heavy, split it across runs. On ordinary lead lists, where hubs are a small minority of rows,
you will not meet this limit.
no_analytics can still misfire. Twelve analytics products are detected, including Matomo,
Plausible and Cloudflare Insights. Server-side tracking leaves no trace in the HTML and is
undetectable by anyone, including this Actor.
The scoring weights are reasoned judgements, not learned values. They were set by argument, not
by measuring which leads actually converted — nobody has that data yet. They also assume you sell
websites, hosting or marketing. If you sell something else, the opportunity signals mean little to
you; sort by contactabilityScore and emailType instead.
Phone extraction is deliberately conservative. It reads tel: links and numbers sitting behind
a "Tel:"-style label, and ignores unlabelled digits on a page. That loses a few real numbers rather
than inventing wrong ones, because you are billed per contact found.
Results are a snapshot. A host that times out today may answer tomorrow. And the verification above rests on two batches of around ten sites, with a handful checked by hand — enough to find the error classes, not enough to put a confidence interval on the hit rate.
It is new. No usage history, no ratings, no track record. Judge it on the run, not on the listing.
Legal note and support
The Actor reads publicly available pages, the way a browser does. Business contact details published in an imprint or on a contact page are public information, but what you may do with them afterwards is regulated — under GDPR in the EU, and in Germany unsolicited B2B e-mail advertising generally requires prior consent under the UWG. Please make sure your intended use is lawful where you operate.
Found a bug, or need another signal in the output? Open an issue on the Issues tab.

