Website Contact Details Crawler avatar

Website Contact Details Crawler

Pricing

from $0.005 / actor start

Go to Apify Store
Website Contact Details Crawler

Website Contact Details Crawler

Crawl any list of websites and extract every email address, phone number (E.164) and social media profile, deduplicated into one clean record per domain. Fast HTTP-only crawler with pay-per-result pricing.

Pricing

from $0.005 / actor start

Rating

0.0

(0)

Developer

Eonix Pvt Ltd

Eonix Pvt Ltd

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Website Contact Scraper — Extract Emails, Phone Numbers & Social Media Links from Any Website

Give this Actor a list of websites and get back one clean row per website with every email address, phone number and social media profile it could find. It's the cheapest contact scraper on Apify: you pay a tenth of a cent per page, and the per-website fee applies only when an email or phone number was actually found.

What you get

For every website you give it, the scraper visits the pages most likely to list contact details first: Contact, About, Team, Impressum. It then returns:

  • 📧 Emails: including addresses hidden with Cloudflare email protection, HTML entities, or written as name [at] domain [dot] com
  • 📞 Phone numbers: validated, in international E.164 format (+12125550123) plus the original text as written on the site
  • 🔗 Social profiles: Facebook, Instagram, LinkedIn (company and personal), X/Twitter, YouTube, TikTok, Pinterest, GitHub, Threads, Bluesky
  • 🏢 Business name and address: from the site's structured schema.org data when available
  • 🔍 Sources: the exact page each email and phone number was found on, so you can verify any result

Use cases

  • Lead generation: turn a list of company websites into emails and phone numbers for outreach or your CRM.
  • Enrich Google Maps results: Google Maps listings have websites but rarely emails. Feed the websites in here (see below).
  • Market research: map which competitors or suppliers are active on which social networks.
  • AI agents and RAG pipelines: give your agent a reliable "find the contact details for this company" tool through the API or MCP.
  • Data hygiene and monitoring: re-check the contact details you store against what's live on each company's website, on a schedule.

Sample output

These are the first 3 records from a real run with the default input on 26 Sep 2026. The phone lists and sources are shortened here: Levain Bakery has 21 phone numbers and Voodoo Doughnut 24, one per shop location.

[
{
"domain": "russanddaughters.com",
"startUrl": "https://russanddaughters.com/",
"pagesCrawled": 2,
"hasContacts": true,
"emails": ["info@russanddaughters.com"],
"phones": [{ "e164": "+12124754880", "raw": "212-475-4880", "country": "US" }],
"socials": { "instagram": ["https://instagram.com/russanddaughters"] },
"organizationName": null,
"address": null,
"sources": {
"emails": {
"info@russanddaughters.com": [
"https://russanddaughters.com/",
"https://www.russanddaughters.com/accessibility/"
]
},
"phones": {
"+12124754880": ["https://russanddaughters.com/", "https://www.russanddaughters.com/accessibility/"]
}
},
"crawledAt": "2026-09-26T14:28:19.419Z"
},
{
"domain": "levainbakery.com",
"startUrl": "https://levainbakery.com/",
"pagesCrawled": 16,
"hasContacts": true,
"emails": [
"corporategifts@levainbakery.com",
"events@levainbakery.com",
"info@levainbakery.com",
"myorder@levainbakery.com"
],
"phones": [
{ "e164": "+18004882085", "raw": "1-800-488-2085", "country": "US" },
{ "e164": "+19174643769", "raw": "+1917.464.3769", "country": "US" },
{ "e164": "+16469745901", "raw": "+1646-974-5901", "country": "US" }
],
"socials": {
"facebook": ["https://facebook.com/LevainBakery"],
"instagram": ["https://instagram.com/levainbakery"],
"linkedinCompany": ["https://linkedin.com/company/levain-bakery"],
"tiktok": ["https://tiktok.com/@levainbakery"]
},
"organizationName": "Levain Bakery",
"address": null,
"sources": {
"emails": {
"events@levainbakery.com": [
"https://levainbakery.com/pages/weddings",
"https://levainbakery.com/pages/events"
]
},
"phones": { "+18004882085": ["https://levainbakery.com/pages/catering"] }
},
"crawledAt": "2026-09-26T14:28:34.727Z"
},
{
"domain": "voodoodoughnut.com",
"startUrl": "https://voodoodoughnut.com/",
"pagesCrawled": 16,
"hasContacts": true,
"emails": ["legal@voodoodoughnut.com", "llegal@voodoodoughnut.com", "marketing@voodoodoughnut.com"],
"phones": [
{ "e164": "+15032352666", "raw": "5032352666", "country": "US" },
{ "e164": "+17206495666", "raw": "+17206495666", "country": "US" },
{ "e164": "+14072676897", "raw": "4072676897", "country": "US" }
],
"socials": {
"facebook": ["https://facebook.com/Voodoo-Doughnut-119262244761342"],
"instagram": ["https://instagram.com/voodoodoughnut"],
"linkedinCompany": ["https://linkedin.com/company/voodoo-doughnut"],
"tiktok": ["https://tiktok.com/@voodoodoughnut"]
},
"organizationName": "Voodoo Doughnut",
"address": "7101 Melrose Ave, Los Angeles, California (CA) 90046, US",
"sources": {
"emails": {
"legal@voodoodoughnut.com": [
"https://voodoodoughnut.com/privacy-policy/",
"https://voodoodoughnut.com/terms-and-conditions/"
]
},
"phones": {
"+15032352666": ["https://voodoodoughnut.com/locations/", "https://voodoodoughnut.com/event-catering/"]
}
},
"crawledAt": "2026-09-26T14:28:35.385Z"
}
]

Every row has the same fields. Empty lists stay [] and missing values are null (never ""). Every social network key is always present in socials; empty networks are omitted above to keep the sample short.

Pricing: pay only for what you get

This Actor uses pay-per-event pricing. There is no monthly fee, and platform usage is included.

EventPriceWhen it's charged
Actor start$0.005Once per run
Page crawled$0.001Each page successfully downloaded and scanned. Failed, blocked, 404 and off-site pages are free.
Website with contacts$0.01Once per website where at least one email or phone number was found. Websites with nothing found don't incur this charge.

Worked example: 1,000 company websites

  • A typical small-business site needs 5–15 pages (the demo run above averaged 11). Say 8 pages: 1,000 × 8 × $0.001 = $8
  • If all 1,000 websites have an email or phone: 1,000 × $0.01 = $10. If only 700 do, it's $7.
  • Total: about $15–18 for 1,000 websites, or less than 2 cents per website.

You stay in control:

  • Max pages per website caps the per-page cost of each site. The default is 20; contact pages are always visited first.
  • Max websites caps how many results you receive.
  • Maximum charge per run (set in the Apify Console run options) is a hard budget. The Actor stops cleanly before going over it, and websites already in progress are still delivered. The run statistics record budgetReached: true when this happens.

Input parameters

ParameterTypeDefaultWhat it does
startUrlslist of URLs3 demo websitesWebsites to scan. Full URLs (https://acme.com/contact) or bare domains (acme.com). Upload a file or link a Google Sheet for big lists. Duplicates of the same website are merged.
maxPagesPerDomainnumber20Most pages scanned per website.
maxDepthnumber2How many clicks away from the start page to go. 0 = start page only.
maxResultsnumber50Stop after this many websites have been delivered.
prioritizePathslist/contact, /contact-us, /about, /about-us, /team, /impressum, /kontaktPages scanned before anything else.
sameDomainOnlyyes/noyesTurn off to also scan subdomains such as shop.acme.com. Other websites are never followed.
extractPhonesyes/noyesFind and validate phone numbers.
extractSocialsyes/noyesFind social media profile links.
phoneCountryHinttextUSCountry used to read numbers written without +country (e.g. (212) 555-0123). Use GB, DE, AU… for sites in other countries.
respectRobotsTxtyes/noyesSkip pages a website asks crawlers not to visit.
maxRequestRetriesnumber3Retries for failed or blocked pages, each with a fresh IP and a longer wait.
proxyConfigurationproxyApify ProxyDatacenter proxy works for most sites. Switch to residential if many sites block you.

How to use it

From the API (cURL)

curl -X POST "https://api.apify.com/v2/acts/yasaslive~contact-info-crawler/run-sync-get-dataset-items?token=YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "startUrls": [{ "url": "https://russanddaughters.com" }], "maxPagesPerDomain": 10 }'

Python

from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("yasaslive/contact-info-crawler").call(run_input={
"startUrls": [{"url": "https://levainbakery.com"}, {"url": "voodoodoughnut.com"}],
"maxPagesPerDomain": 15,
})
for site in client.dataset(run["defaultDatasetId"]).iterate_items():
print(site["domain"], site["emails"], [p["e164"] for p in site["phones"]])

Node.js

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('yasaslive/contact-info-crawler').call({
startUrls: [{ url: 'https://levainbakery.com' }],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Make (Integromat)

Add the Apify → Run an Actor module and choose contact-info-crawler. Turn on Run synchronously, then add Apify → Get Dataset Items with the run's defaultDatasetId. Map emails and phones[].e164 into your CRM or Google Sheets module.

n8n

Use the Apify node (community node @apify/n8n-nodes-apify), set Operation: Run Actor and get dataset, Actor: yasaslive/contact-info-crawler, and pass the input JSON. You can also use a plain HTTP Request node with the cURL URL above.

MCP (Claude, Cursor and other AI agents)

Add the Apify MCP server with this Actor as a tool:

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?actors=yasaslive/contact-info-crawler",
"headers": { "Authorization": "Bearer YOUR_API_TOKEN" }
}
}
}

Your agent can then call it with prompts like "find the contact email and phone for acme-bakery.com".

Pair with Google Maps Scraper output

Google Maps gives you business websites but almost never email addresses. Chain the two:

  1. Run a Google Maps scraper (e.g. compass/crawler-google-places) for your search, like "bakeries in Brooklyn".
  2. Take the website field of each place and feed it into this Actor.
  3. Join the results back on the domain.
from urllib.parse import urlparse
from apify_client import ApifyClient
client = ApifyClient("YOUR_API_TOKEN")
# 1. Places from Google Maps
maps_run = client.actor("compass/crawler-google-places").call(run_input={
"searchStringsArray": ["bakery"],
"locationQuery": "Brooklyn, New York",
"maxCrawledPlacesPerSearch": 100,
})
places = list(client.dataset(maps_run["defaultDatasetId"]).iterate_items())
# 2. Contact details for every place that has a website
websites = sorted({p["website"] for p in places if p.get("website")})
contacts_run = client.actor("yasaslive/contact-info-crawler").call(run_input={
"startUrls": [{"url": url} for url in websites],
"maxPagesPerDomain": 10,
"maxResults": len(websites),
})
contacts = {c["domain"]: c for c in client.dataset(contacts_run["defaultDatasetId"]).iterate_items()}
# 3. Join on domain
def domain_of(url):
return urlparse(url).hostname.removeprefix("www.")
for place in places:
site = contacts.get(domain_of(place["website"])) if place.get("website") else None
print(place["title"], "|", ", ".join(site["emails"]) if site else "—")

FAQ

Why didn't I get a row for some websites? Websites where no page could be loaded (offline, blocked by a bot wall, or disallowed by robots.txt) are listed with the reason in the run's key-value store under FAILED_DOMAINS. You are not charged for them. Websites that loaded but had no contacts do appear in the results with "hasContacts": false; you pay only for the pages scanned there.

Does it work on JavaScript-heavy websites? It reads the HTML the server sends, which covers the large majority of small-business sites (WordPress, Wix, Squarespace, Shopify, Webflow). Websites that build their whole page in the browser can come back empty. That's the trade-off for being fast and cheap.

Does it find emails hidden from bots? Yes, for the common techniques: Cloudflare email protection, HTML-entity encoding, URL-encoded mailto: links and name [at] domain [dot] com style text. It won't solve CAPTCHAs or run JavaScript to reveal an email.

Can it crawl a whole website? It's built to find contact details, not to archive sites. Contact-style pages are scanned first and each website is capped at maxPagesPerDomain (up to 1,000).

Where are the run statistics? In the key-value store record STATS. It holds pages crawled, websites finished, errors by category (blocked / rate-limited / proxy / network / parse / other), budgetReached, and how many events were charged. It is updated every 30 seconds while the run is going.

Limitations

  • No JavaScript rendering: content injected by client-side scripts is invisible to this crawler.
  • Phone numbers written without a country prefix are read using phoneCountryHint, so a site with numbers from several countries written in national format may get some misread. Numbers written with + are always read correctly.
  • Unformatted digit runs (2125550123 in running text) are ignored on purpose, because they are usually order numbers or IDs. Numbers in tel: links and structured data are always kept.
  • At most 10 source pages are listed per email or phone.
  • Websites behind aggressive bot protection may fail even with retries. Try residential proxies.

This Actor only reads publicly available web pages, the same ones any visitor can open without logging in. It respects robots.txt by default and paces requests to each website (at most about one per second).

You are responsible for how you use the data. Personal data, such as named employees' emails or LinkedIn profiles, is protected by laws including the GDPR (EU/UK) and CCPA (California). Make sure you have a legitimate basis for processing it, honour opt-outs, and follow anti-spam laws such as CAN-SPAM and PECR when contacting anyone. Check each website's Terms of Service. If you're unsure, ask a lawyer before using scraped personal data.