Contact Details Scraper
Get emails, phones and addresses from any list of websites. Also contact forms and 10 social profiles. $1.50 per 1,000 sites, flat rate.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
websites,respectRobotsTxt,defaultCountry(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.0015 per website = $1.5 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Website | One successfully crawled website with extracted contact details. | $0.0015 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-07-25, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
websites | Domain names or full website URLs, one per line. Values without a scheme use HTTPS. | array |
respectRobotsTxt | When enabled, pages disallowed for this Actor's user agent are not crawled. | boolean |
defaultCountry | Optional ISO 3166-1 alpha-2 country code used to normalize local phone numbers, for example US, GB, or CA. | string |
startUrls | Alternative URL input compatible with Apify request-list sources. You can combine it with Websites. | array |
maxPagesPerSite | Maximum same-site HTML pages to fetch for each website. Contact, about, team, and legal pages are prioritized. | integer |
maxConcurrency | How many websites to process in parallel. Each website is crawled sequentially to stay polite and predictable. | integer |
requestTimeoutSecs | Maximum time for an individual HTTP request, in seconds. | integer |
maxResponseSizeKb | Maximum HTML response body size per page in KiB. Oversized pages are skipped without charging. | integer |
What you get
A structured dataset — each result includes fields like:
domaintitleemailCountphoneCountsocialLinkCountaddressCountcontactFormCountpagesCrawledsiteUrlok_sampledescriptionemailsphonessocialLinksaddressescontactFormsjsonLdOrganizationsjsonLdPeoplesourcePagescrawledPageserrorCodeerrorExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
Related tools in B2B Leads & Contact Data
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
Email Verifier
Verify emails in bulk: syntax, MX records, disposable domains, role accounts, optional SMTP check. No mail is sent. No API key, no login.
Shopify Store Leads
Check domains for Shopify, then get public emails, phones, socials, currency, theme and tech. $4.50 per 1,000 confirmed stores.
Thomasnet Suppliers Scraper
Scrape Thomasnet suppliers by product and US location. Get name, phone, website, address, year founded, employees, sales, ISO certs. $0.85 per 1,000.
LinkedIn Profiles Scraper
Get public LinkedIn profile data from URLs you supply. You get name, headline, description, image link and public identifier. $0.90 per 1,000 profiles.
LinkedIn Companies Scraper
Get public LinkedIn company data from company URLs. You get name, description, followers, employee count, HQ, website and logo. $0.90 per 1,000, flat rate.
YouTube Channel Email Scraper
Find the business emails creators publish in their YouTube channel description, plus their linked site's contact pages. $1.50 per 1,000 channels.
Where this tool sits
- Categories
- B2B Leads & Contact Data
Contact Details Scraper: emails, phones, addresses and socials from a list of websites
Paste a list of domains and get one row per site holding whatever contact details that site publishes in public. Email addresses, phone numbers, postal addresses, social profiles, and the contact forms themselves, down to the field names each form expects. Every finding says which page it came from.
It does not stop at the home page, because contact details rarely live there. Each site gets a short crawl weighted towards contact, about, team, legal and the German imprint page. And plenty of businesses publish no email address at all any more, so a row with social links and a form on it, and emails: [], is a normal result rather than a failure.
| Input | Domains or website URLs, one per line |
| Output | One row per website |
| Ceiling | 20 pages crawled per site |
| Account needed | None |
| Price | $1.50 per 1,000 websites, flat on every plan |
🔍 What Contact Details Scraper does
For each site it fetches the home page, picks the links most likely to carry contact details, and reads up to maxPagesPerSite of them. Everything it finds is merged into one record for that domain, deduplicated, with the source page recorded against each item.
Obfuscated addresses are decoded, so hello [at] example [dot] com comes back as a real address. An email that only exists as an image does not, because that would need character recognition, and it is the one dodge that still works against this.
Ten social platforms are recognised by name: LinkedIn, Facebook, Instagram, X, YouTube, TikTok, Pinterest, GitHub, Threads and Bluesky. Anything else stays a plain link and is not classified.
📥 What you give it
{
"websites": ["apify.com", "https://stripe.com", "example.co.uk"],
"maxPagesPerSite": 8,
"defaultCountry": "US"
}
| Field | Default | What it is |
|---|---|---|
websites | none | Domains or full URLs, one per line. A value with no scheme is treated as HTTPS. The Console box starts with one example; an API call has to send its own. |
startUrls | none | The Apify request-list format, if that is what you already have. Combine it with websites freely. |
maxPagesPerSite | 6 | 1 to 20. More pages finds more and takes longer, and it does not change what you pay. |
defaultCountry | none | A two-letter code like US, GB or CA, used to make sense of phone numbers written without a country code. |
maxConcurrency | 5 | 1 to 20 sites at once. Each site is still crawled one page at a time. |
respectRobotsTxt | on | Skips pages the site asks crawlers not to read. |
requestTimeoutSecs | 12 | 3 to 45 seconds per page. |
maxResponseSizeKb | 1536 | 128 to 5120. A page bigger than this is skipped. |
proxyConfiguration | off | Optional network settings, off because most business sites answer a direct request fine. |
startUrls wants actual URL entries. A requestsFromUrl pointing at a text file of links is not picked up, so paste those URLs in rather than linking them.
📤 What you get back
A real row from a recent run, with the repeated source-page lists cut short:
{
"ok": true,
"siteUrl": "https://www.python.org/about/quotes/",
"requestedUrl": "https://www.python.org/",
"domain": "python.org",
"title": "Welcome to Python.org",
"description": "The official home of the Python Programming Language",
"emails": [],
"phones": [],
"socialLinks": [
{ "platform": "linkedin", "url": "https://www.linkedin.com/company/python-software-foundation/",
"sourcePages": ["https://www.python.org/", "..."] },
{ "platform": "x", "url": "https://twitter.com/ThePSF", "sourcePages": ["..."] },
{ "platform": "github", "url": "https://github.com/python/cpython/issues", "sourcePages": ["..."] }
],
"addresses": [],
"contactForms": [],
"jsonLdOrganizations": [],
"jsonLdPeople": [],
"crawledPages": [
{ "url": "https://www.python.org/", "status": 200, "title": "Welcome to Python.org", "contactsFound": 4 }
],
"pagesCrawled": 4,
"pagesAttempted": 4,
"emailCount": 0,
"phoneCount": 0,
"socialLinkCount": 5,
"robotsTxtRespected": true,
"pageErrors": []
}
| Field | What it is |
|---|---|
sourcePages | On every finding. When someone asks where an address came from, you point at the page instead of checking it again by hand. |
emails | Each entry is the address plus the pages it appeared on. |
phones | The number as written, plus e164 and country once it has been normalised. That normalisation leans on defaultCountry for locally written numbers. |
contactForms | The form's action URL, method and field names, and whether it has message, email and phone fields. Worth reading when a site publishes no address at all. |
jsonLdOrganizations, jsonLdPeople | Pulled from the site's own structured data. Named people with job titles turn up here more often than you would expect. |
crawledPages | One entry per page fetched, with its status, title and how many findings came off it. |
pageErrors | Pages that could not be read, each with its own code, such as a page the site asked crawlers to skip. |
domain | The site key, without www. Two inputs that resolve to the same site collapse into one row. |
The preview table shows the counts rather than the addresses themselves. Download the JSON or CSV to get the actual emails, phones and links.
🧾 Reading the output
Three kinds of row can land in your dataset.
| Row | How to spot it | Charged |
|---|---|---|
| A site | ok: true and a domain | yes |
| The sample row | _sample: true | no |
| A diagnostic | ok: false and an errorCode | no |
| Code | What it means |
|---|---|
BAD_INPUT | Nothing usable in websites or startUrls. |
NO_CONTACTS | The site loaded fine and published nothing this actor recognises. |
NO_RESULTS | Nothing on that site could be read. Often a domain that redirects somewhere else, or a site that asks crawlers to stay out. |
UNSAFE_URL | The hostname resolves to a private address, so it was not fetched. |
TIMEOUT | The site was too slow inside requestTimeoutSecs. |
BLOCKED | The site refused the request. |
INTERNAL_ERROR | Something went wrong in the run itself. Send us the run ID. |
One bad site never stops the others.
▶️ How to run it
1. Open Contact Details Scraper and click Try for free. 2. Paste your domains into Websites, one per line. 3. Set Default phone country if your list is mostly one country. It makes the phone numbers usable. 4. Raise Maximum pages per site if you want a deeper look, then click Start. 5. Download the dataset as JSON, CSV or Excel, or read it from the Apify API.
💰 How much does it cost?
$1.50 per 1,000 websites. Flat on every Apify plan, no volume tiers.
You pay per website, not per page. A site where 20 pages get read costs exactly the same as one where a single page does, so raising maxPagesPerSite buys you more findings for the same money. The only thing it costs is time.
Sites that failed to load, sites with nothing to find, pages skipped for size, and duplicate entries that collapsed into one row are all free, and a run where no site turned anything up costs you nothing.
💡 What people use it for
- Turning a list of company domains into a contact sheet, with the source page recorded beside each
finding so nothing has to be re-checked.
- Finding the form when there is no email. The field names are what you need to reach a company
programmatically.
- Pulling the ten social profiles for a set of brands in one pass, instead of hunting footers.
- Checking a supplier list still has working, published contact details on it.
- Reading named people and roles out of a site's structured data.
🚧 What it does not do
- No JavaScript. Details injected by a script after the page loads are not seen. Most business
sites publish them in the HTML, but a footer fetched from an API is a genuine miss.
- No logins. Public pages only, nothing behind a sign-in, a paywall or a form.
- No emails inside images. That needs character recognition, which this does not do.
- Same site only. Subdomains and a domain that redirects somewhere else are not followed.
- 20 pages per site is the ceiling. This is a targeted crawl of the likely pages, not a full
spider.
- It respects robots.txt by default, so a site that asks crawlers to stay out returns little.
That is deliberate.
- It finds what is published, not what is true. A stale address on an old page still comes back.
- No verification. It does not check whether an address accepts mail.
🧭 Which contact scraper do you need?
| If you want | Use |
|---|---|
| Emails, phones and socials from a list of websites | This one |
| Contact details off a Facebook Page | Facebook Page Contact Info Scraper |
| The people at a company | LinkedIn Company Employees Scraper |
| Local businesses with phone and address | Google Maps Scraper |
| To check a list of addresses is deliverable | Email Verifier |
❓ Questions people ask
Does reading more pages cost more? No. The charge is per website. Deeper crawls cost time, not money.
A site came back with no emails. Is that a bug? Usually not. A lot of companies publish a form instead of an address now. Check contactForms and socialLinks on that row.
Why is one of my phone numbers formatted oddly? A locally written number needs defaultCountry to be read correctly. Set it to match your list.
Can it read a page that needs a login? No. It sees what any visitor sees.
Can I schedule it? Yes, like any Apify actor. A saved list of domains makes it repeatable.
Is collecting contact details legal? These are details a business chose to publish. They are still personal data under GDPR and similar laws, and marketing to them has its own rules, so have a lawful basis and honour opt-outs. Apify's write-up on scraping and the law is a good place to start, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the website and the run ID. The errorCode on the diagnostic row, and pageErrors on a real row, usually name the problem between them.