Website Contact & Email Crawler
Pricing
$19.99/month + usage
Website Contact & Email Crawler
ππ Extract phone numbers, emails, contact details & social media links from any website in seconds. β‘οΈ Scrapes tel, mailto, WhatsApp, LinkedIn, X/Twitter, Instagram & more; dedupes & validates. π Export CSV/JSON, API-ready. π Ideal for lead gen, sales & CRM enrichment.
Pricing
$19.99/month + usage
Rating
0.0
(0)
Developer
Scrapio
Maintained by CommunityActor stats
0
Bookmarked
31
Total users
4
Monthly active users
2 days ago
Last modified
Categories
Share
Extract Phone Numbers, Contacts & Socials from Any Website π
Give this actor a list of website URLs. It visits each site, finds the pages that actually carry contact details (/contact, /contact-us, /about, /impressum, /team, /support, footer links, sitemap.xml), and returns every phone number, email address and social-media profile it can find β with the exact page each item was found on.
It is built for lead generation: one clean row per website, ready to export to CSV/Excel and drop straight into a CRM.
A second, legacy keyword-search mode is preserved for existing users: it searches public search-engine results across 80+ platforms (Instagram, LinkedIn, Yelp, TikTok, Zillowβ¦) for profiles that publish a phone number.
Two modes π§
| Mode | Input | Output |
|---|---|---|
| π Website crawl (default) | startUrls β any website URLs | Phones + emails + social profiles per website |
| π Keyword search (legacy) | keywords + platform + country | Phone numbers found in public search results |
Pick the mode with the mode input. If you leave mode out entirely, the actor infers it: URLs present β website crawl, keywords present β keyword search. Existing tasks keep working unchanged.
What the website crawler actually does π¬
- Fetches the homepage over plain HTTP (fast and cheap).
- Scores every internal link by how likely it is to hold contact data β
contact,contact-us,kontakt,contacto,contatti,impressum,imprint,mentions-legales,about,team,support,locations,find-us,legal, β¦ β and visits the best ones first, breadth-first, up to your crawl depth and max pages per site. - Peeks at
/sitemap.xml(one extra request, optional) to catch contact pages that aren't linked from the homepage. - Extracts contacts from every page it visits.
- Falls back to a headless Chromium browser only when a site returned no phone and no email over plain HTTP and the HTML looks like an empty JavaScript shell (React/Next/Vue/Angular). Browsers are slow and expensive, so they are never used for pages that already produced data.
Phone numbers βοΈ
tel:/callto:links, JSON-LDtelephonefields, WhatsAppwa.melinks, and visible page text.- Normalised to international E.164 (
+441614960123). When the country can't be established the number is returned exactly as the site printed it, so nothing useful is lost. - Country is resolved from your
phoneCountrysetting, or auto-detected per site from the domain's country code (.co.ukβ +44,.deβ +49,.inβ +91 β¦). - Per-country length validation rejects garbage that merely looks like a phone number: NANP (
+1) must be exactly 11 digits, India (+91) exactly 12, plus fixed-length checks for+7,+33,+34,+61,+65,+48,+351,+30,+420,+421,+386,+372. - Bare digit runs in body text must earn a confidence score before they are reported (explicit
+prefix, an adjacent phone label likeTel:/Call us/(fax), human digit grouping, or being on a contact page). VAT numbers, company registration numbers, order/invoice numbers, prices, ZIP+4, dates and year ranges are filtered out.
Email addresses βοΈ
mailto:links and plain page text.- Cloudflare email protection (
data-cfemail="β¦"//cdn-cgi/l/email-protection#β¦) is decoded properly β the hex payload's first byte is the XOR key for every following byte. - Text obfuscation β
name [at] domain [dot] com,(at),{at},[.],@,., and bareinfo at example dot com. - Filtered: asset filenames (
logo@2x.png), placeholder addresses (you@example.com), Sentry/Wix telemetry keys, and addresses that ran into the following word (info@acme.comwho we are).
Social media profiles π
Facebook, Instagram, X and Twitter, LinkedIn (company and personal /in/), YouTube (@handle, /channel/, /c/, /user/), TikTok, Threads (threads.net + threads.com), Pinterest (incl. country domains), GitHub, Telegram (t.me), WhatsApp (wa.me, api.whatsapp.com, chat.whatsapp.com), Discord, Snapchat, Reddit, Twitch, Vimeo, SoundCloud, Spotify, Bluesky, Medium, Behance, Dribbble, Xing, VK, Yelp, Trustpilot.
Found in anchors, raw markup, page text, og:/twitter: meta tags and JSON-LD sameAs. Each is normalised to handle + canonical URL.
Share/intent links are filtered out. twitter.com/intent/tweet?url=β¦, facebook.com/sharer/sharer.php?u=β¦, linkedin.com/sharing/share-offsite/?url=β¦, pinterest.com/pin/create/button/?url=β¦ and friends are "share this page" widgets, not the site's own profile β a classic false positive that this actor does not make. Platform infrastructure hosts (connect.facebook.net, platform.twitter.com, β¦) and reserved paths (/login, /help, /hashtag, /explore, /p/, /watch) are rejected too.
Bonus π
JSON-LD Organization / LocalBusiness data also yields the company name and postal address when the site publishes it.
Input Parameters π§©
Website-crawl mode
| Field | Type | Default | Description |
|---|---|---|---|
mode | string | website | website or search |
startUrls | array | β | The websites to crawl. Standard Apify URL list β in the Console just paste one URL per row (bulk paste, link lists and Google Sheets all work); over the API it takes {"url": "β¦"} objects |
websiteUrls | array | β | Hidden API-only alias that takes plain URL strings (["https://example.com"]) for callers who prefer them. Merged with startUrls. Not shown in the Console form |
maxPagesPerSite | integer | 12 | Page budget per website (1β200) |
maxCrawlDepth | integer | 2 | Link hops from the start URL (0β5) |
phoneCountry | string | Auto-detect | Pin a country for phone normalisation, or auto-detect per site |
renderJavaScript | string | auto | auto / always / never headless-browser rendering |
useSitemap | boolean | true | Probe /sitemap.xml for contact pages |
includeSubdomains | boolean | true | Follow links to other subdomains of the same site |
concurrency | integer | 5 | Websites crawled in parallel |
requestDelaySecs | integer | 0 | Politeness delay between page requests |
maxBrowserPagesPerSite | integer | 2 | Cap on headless-browser renders per site |
proxyConfiguration | object | Apify Proxy | Network routing (see below) |
Keyword-search mode (legacy)
| Field | Type | Default | Description |
|---|---|---|---|
keywords | array | β | Keywords / usernames to search for |
platform | string | Instagram | One of 80+ supported platforms |
country | string | United Kingdom (+44) | Dial code used to build and filter the search |
maxPhoneNumbers | integer | 10 | Phone numbers to collect per keyword |
engine | string | legacy | Processing engine |
π¦ Example input β website mode
{"mode": "website","startUrls": [{ "url": "https://www.zingermans.com" },{ "url": "https://www.pizzapilgrims.co.uk" }],"maxPagesPerSite": 12,"maxCrawlDepth": 2,"phoneCountry": "Auto-detect (recommended)","renderJavaScript": "auto","useSitemap": true}
π¦ Example input β legacy keyword-search mode
{"mode": "search","keywords": ["marketing"],"platform": "Instagram","country": "United Kingdom (+44)","maxPhoneNumbers": 10,"engine": "legacy"}
Output Format π€
Website mode produces one row per website (not per page). Every extracted item records the page it came from in foundOn.
{"mode": "website","inputUrl": "https://www.zingermans.com","finalUrl": "https://www.zingermans.com","domain": "zingermans.com","companyName": "Zingerman's","siteTitle": "Zingerman's: Online Shopping for Food and Gifts","phones": ["+18662606169", "+18886368162", "+17344362006"],"emails": ["service@zingermans.com", "bizgifts@zingermans.com"],"socialLinks": ["https://facebook.com/Zingermans","https://instagram.com/zingermansmailorder","https://twitter.com/zingermans"],"phoneDetails": [{"phone": "+18662606169","e164": "+18662606169","raw": "+18662606169","source": "tel_link","foundOn": "https://www.zingermans.com"}],"emailDetails": [{"email": "service@zingermans.com","source": "mailto","foundOn": "https://www.zingermans.com"}],"socialDetails": [{"platform": "facebook","handle": "Zingermans","url": "https://facebook.com/Zingermans","foundOn": "https://www.zingermans.com"}],"socialsByPlatform": {"facebook": "https://facebook.com/Zingermans","instagram": "https://instagram.com/zingermansmailorder"},"addresses": ["3711 Plaza Drive, Ann Arbor, MI, 48108"],"phoneCount": 3,"emailCount": 2,"socialCount": 3,"hasContacts": true,"pagesCrawled": 8,"pages": [{ "url": "https://www.zingermans.com", "status": 200, "depth": 0, "phones": 2, "emails": 2, "socials": 4, "jsShell": false }],"dialCodeUsed": "","browserRenderUsed": false,"errors": [],"status": "ok"}
Output fields
| Field | Description |
|---|---|
inputUrl / finalUrl | The URL you supplied / the URL after redirects |
domain | Registrable domain of the site |
companyName | Organisation name from JSON-LD, else the page title |
phones / emails / socialLinks | Flat de-duplicated lists β the columns you export |
phoneDetails | Per phone: phone, e164, raw (as printed), source (tel_link / json_ld / whatsapp / text), foundOn |
emailDetails | Per email: email, source (mailto / cloudflare / obfuscated / text / json_ld), foundOn |
socialDetails | Per profile: platform, handle, url, foundOn |
socialsByPlatform | Quick map, one best URL per platform |
addresses | Postal addresses from JSON-LD |
pages | Every page visited, with per-page hit counts and whether it was a JS shell |
browserRenderUsed | Whether the headless-browser fallback was needed |
hasContacts / status / errors | Row-level diagnostics β failed sites still produce a row |
Legacy keyword-search mode keeps its original row shape unchanged: platform, keyword, title, description, url, phone_number, country, dial_code.
Proxy & reliability π‘οΈ
- Website mode routes through Apify Proxy (datacenter) by default and automatically retries a failed or blocked request directly, which recovers a large share of sites that block datacenter IPs. Choose the RESIDENTIAL group in
proxyConfigurationfor stubborn WAF-protected sites. - Keyword-search mode always forces Apify's
GOOGLE_SERPgroup β search requests fail without it. - Bad TLS certificates, exotic character encodings,
http://fallbacks andwww.variants are all handled; a single broken page never kills the run.
Use Cases π―
- Lead generation β turn a list of company domains into a contact sheet with phone, email and social handles.
- Sales enrichment β fill in missing contact fields for accounts already in your CRM.
- Agency prospecting β find which businesses have (or lack) an Instagram/TikTok presence, plus how to reach them.
- Market research β map contactability and social presence across a whole industry vertical.
- Data hygiene β re-verify that the phone numbers and emails you hold are still published on the site.
Limitations & honest notes β οΈ
- The actor only reads publicly published contact data. It does not solve CAPTCHAs, log in, or read anything behind a form.
- Sites protected by an aggressive WAF may return
403to both the proxy and the direct retry. Those rows come back withstatus: "ok"/"failed"and the error recorded inerrorsβ the run does not silently pretend it found nothing. - Phone numbers written locally on a
.comdomain with no country signal anywhere on the page are returned in the site's own national format rather than E.164 (except unmistakable US/Canada(NNN) NNN-NNNNshapes, which are converted to+1). - Contact details rendered only inside a
<canvas>, an image, or behind an interactive widget click are not extracted. - The headless-browser fallback deliberately runs on at most a couple of pages per site; set
renderJavaScript: "always"if you need every page rendered. robots.txtis not consulted. Use the actor responsibly and in line with the target site's terms.
Legal & ethical guidelines βοΈ
Extracting publicly available business contact information is generally lawful, but you remain responsible for how you use it:
- Comply with GDPR, CAN-SPAM, PECR and any local marketing/privacy rules that apply to you.
- Prefer role addresses (
info@,sales@) over personal ones for cold outreach, and honour opt-outs. - Do not use the output for spam, harassment, or any unsolicited contact that breaks local law.
- Respect each website's terms of service.
FAQ β
Does it really visit the website, or just search engines? Website mode genuinely fetches the site: the homepage plus the contact-bearing pages it discovers. Search-engine results are only used by the optional legacy keyword mode.
Do I get emails and social links, or just phone numbers? All three. Phones, emails and social profiles, each with the page it was found on.
Can it read emails hidden by Cloudflare?
Yes β data-cfemail / /cdn-cgi/l/email-protection payloads are decoded, as are [at] / [dot] text obfuscations.
Does it handle JavaScript-only sites? Yes, via an automatic headless-Chromium fallback, used only when plain HTTP found nothing and the page looks like an empty JS shell.
Will it report a "share on Twitter" button as the company's Twitter? No. Share/intent/sharer links are explicitly filtered out.
How many pages does it crawl per site?
maxPagesPerSite (default 12), visited in contact-likelihood order, limited by maxCrawlDepth (default 2).
Is my existing task/integration broken by this update?
No. The legacy keyword-search mode is unchanged and is selected automatically when the input has keywords and no URLs.
Support and feedback π¬
- Bug reports / feature requests: dev.scraperengine@gmail.com
- Please include the run ID and the input you used β it makes diagnosis much faster.