Contact Details Scraper: Website Emails, Phones and Socials avatar

Contact Details Scraper: Website Emails, Phones and Socials

Pricing

from $3.00 / 1,000 websites

Go to Apify Store
Contact Details Scraper: Website Emails, Phones and Socials

Contact Details Scraper: Website Emails, Phones and Socials

Turn a list of company websites into leads: business emails, formatted phone numbers, social profiles and contact page URLs. Scans the homepage plus contact, imprint and about pages, ranks the shared inbox first. Pay only for websites where contacts were found, the rest are free.

Pricing

from $3.00 / 1,000 websites

Rating

0.0

(0)

Developer

Joe Simo

Joe Simo

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

2

Monthly active users

5 days ago

Last modified

Security

Limited permissions

Share

Contact Details Scraper: website emails, phone numbers and social profiles

Paste a list of company websites, get back their public business contact details as a clean table: email addresses, formatted phone numbers, LinkedIn, Facebook, Instagram, X/Twitter, YouTube, TikTok and 8 more social profiles, the contact page and contact form URL, and the company name and address when the site publishes them.

  • Pay only for websites where contacts were found: $3 per 1,000 ($0.003 each). Dead domains, blocked sites and sites with no contacts are saved with a status and cost nothing, and extra pages per site are free.
  • Smarter than a homepage regex: it reads the homepage plus up to 3 contact, imprint, about, locations or support pages, ranks emails so the shared business inbox comes first, and validates every phone number.
  • Fast and light: plain HTTP, no browser, no proxy. 100 websites in about 35 seconds.

Quick start

  1. Click Try for free, keep the prefilled websites (or paste your own) and press Start.
  2. Or copy this input into the JSON tab. It is also what runs when you call the API with an empty input:
{
"websites": ["allbirds.com", "katzsdelicatessen.com", "flourandwater.com"]
}

This run took 3.3 seconds in the Apify cloud on Nov 1, 2026 and found contacts on all 3 sites, so it costs 3 x $0.003 = $0.009. One of the 3 rows, unchanged except for the 14 per-platform social lists and timing fields being cut:

{
"input": "flourandwater.com",
"domain": "flourandwater.com",
"url": "https://www.flourandwater.com/",
"status": "ok",
"title": "Flour + Water",
"companyName": "Flour + Water",
"primaryEmail": "info@flourandwater.com",
"primaryPhone": "+1 415 826 7000",
"emails": ["info@flourandwater.com"],
"phones": ["+1 415 826 7000"],
"facebook": "https://www.facebook.com/flourandwater",
"instagram": "https://www.instagram.com/flourandwatersf",
"linkedin": null,
"emailDetails": [
{ "email": "info@flourandwater.com", "isRole": true, "isSameDomain": true, "isFreeProvider": false,
"foundOn": ["https://www.flourandwater.com/", "https://www.flourandwater.com/contact/"], "foundVia": "mailto" }
],
"phoneDetails": [
{ "e164": "+14158267000", "international": "+1 415 826 7000", "national": "(415) 826-7000",
"country": "US", "type": "FIXED_LINE_OR_MOBILE", "foundVia": "tel_link" }
],
"contactPageUrl": "https://www.flourandwater.com/contact/",
"counts": { "emails": 1, "phones": 1, "socialProfiles": 2 },
"contactsFound": true,
"charged": true
}

Price: $0.003 per website with contacts found ($3 per 1,000), plus a $0.00005 run start fee. Websites with nothing found, blocked or dead sites, and extra pages are free.

What you get

Real results from the prefilled 6-website input on Nov 1, 2026 (shortened):

WebsitePrimary emailPrimary phoneSocial profilesContact page
allbirds.comhelp@allbirds.com+1 424 363 80646 (Instagram, Facebook...)/pages/contact-us
katzsdelicatessen.compress@katzsdelicatessen.com+1 212 254 22463 (Instagram, Facebook...)/contact
flourandwater.cominfo@flourandwater.com+1 415 826 70002/contact/
mailchimp.com(none published)+1 800 315 59396 (LinkedIn, Instagram...)/contact/
stripe.com(varies, see below)+1 888 926 22898 (LinkedIn, Instagram...)/contact/sales
dishoom.comall-ears@dishoom.com(UK numbers, set defaultCountry to GB)5 (LinkedIn, Instagram...)/group-feasts/enquiry/

All 6 have contacts, so this run costs 6 x $0.003 = $0.018. Each row also has every email and phone found (with the page and method it came from), one column per social network, companyName, address, and status. stripe.com A/B tests its contact page, so its sales address shows up in some runs and not others.

Fields for every website

  • Emails from mailto links, schema.org data and the page text, ranked so the best general business address comes first (primaryEmail). Each email is flagged as role (info@, sales@), same domain as the site, or free provider (Gmail, Outlook).
  • Phone numbers validated and formatted (E.164, international and national format, country, line type) with libphonenumber. Local numbers are read using the site's country (domain ending or page language) or your defaultCountry.
  • Social profiles for 14 platforms, with one flat column per major network for spreadsheets. Share buttons, intent links and the platforms' own pages are filtered out.
  • Contact page and contact form URL, so you can follow up by hand when a site has no email.
  • Company name and postal address when the site publishes them as schema.org data.
  • Evidence: every email and phone lists the pages it was found on and how (mailto, tel, structured data or text).

Use cases

  • Lead generation: turn a list of domains from Google Maps, a directory or a CRM export into contactable leads.
  • CRM enrichment: fill in missing emails, phones and LinkedIn company pages for your accounts.
  • Agencies and freelancers: find who to contact at local businesses you want to pitch.
  • Partnership, PR and supplier outreach: get the general inbox and the contact form in one pass.
  • Data cleaning: check which of your accounts still publish a working contact page.

Example inputs

Copy one of these into the JSON tab of the input form. Each was tested on Nov 1, 2026.

1. A list of company websites (domains or full URLs).

{
"websites": ["stripe.com", "allbirds.com", "katzsdelicatessen.com", "flourandwater.com", "dishoom.com", "mailchimp.com"]
}

2. Clean shared business inboxes only (info@, sales@, help@ on the company's own domain). Personal-looking and off-domain addresses are dropped.

{
"websites": ["mailchimp.com", "allbirds.com", "katzsdelicatessen.com", "flourandwater.com"],
"sameDomainEmailsOnly": true,
"roleEmailsOnly": true
}

3. Paste a column straight from a spreadsheet or CSV. One website per line or separated by commas. A header line such as website is ignored.

{
"websitesText": "website\nallbirds.com\nhttps://www.katzsdelicatessen.com/\nflourandwater.com, mailchimp.com"
}

4. Enrich the output of another Actor, for example a Google Maps scraper. Use the dataset ID from that run and the name of its website field (nested fields such as company.website work too).

{
"datasetId": "YOUR_DATASET_ID",
"datasetField": "website"
}

5. UK businesses, more pages per site. defaultCountry tells the Actor how to read local phone numbers when the domain does not reveal the country (dishoom.com returns 13 UK numbers with GB and none without it).

{
"websites": ["dishoom.com", "monmouthcoffee.co.uk", "pret.co.uk"],
"defaultCountry": "GB",
"maxPagesPerSite": 6
}

Input

FieldDescription
websitesDomains or URLs to scan, for example stripe.com or https://www.example.co.uk.
websitesTextBulk paste: one website per line, or separated by commas, spaces or semicolons. Header lines like website are ignored.
datasetId / datasetFieldRead websites from an Apify dataset, for example the output of a Google Maps or lead list Actor. The field can be nested (company.website).
maxPagesPerSitePages per website, homepage included (default 4, max 10).
includePhonesCollect and format phone numbers (on by default).
defaultCountryCountry for local phone numbers when the site does not reveal it (default US).
sameDomainEmailsOnlyKeep only addresses on the site's own domain.
roleEmailsOnlyKeep only generic business addresses such as info@ and sales@.
respectRobotsTxtSkip pages that robots.txt disallows (on by default).
dedupeScan each domain once (on by default).
maxItemsStop after this many websites (0 = no limit).
maxConcurrencyWebsites scanned in parallel. Automatic by default: 6 at 256 MB, 10 at 512 MB, 16 at 1024 MB.
timeoutSecsTimeout per page (default 20 seconds). A website gets at most 4 times this.
userAgentOptional custom User-Agent.

Output

One dataset row per website. Full field list, shown on a made-up UK site so the address and contactFormUrl fields are filled (see Quick start above for a real row):

{
"input": "examplebakery.co.uk",
"domain": "examplebakery.co.uk",
"url": "https://examplebakery.co.uk/",
"status": "ok",
"companyName": "Example Bakery",
"primaryEmail": "hello@examplebakery.co.uk",
"primaryPhone": "+44 117 496 0000",
"emails": ["hello@examplebakery.co.uk", "orders@examplebakery.co.uk"],
"phones": ["+44 117 496 0000"],
"facebook": "https://www.facebook.com/ExampleBakery",
"instagram": "https://www.instagram.com/examplebakery",
"linkedin": null,
"emailDetails": [
{ "email": "hello@examplebakery.co.uk", "isRole": true, "isSameDomain": true, "isFreeProvider": false,
"foundOn": ["https://examplebakery.co.uk/contact/"], "foundVia": "mailto" }
],
"phoneDetails": [
{ "e164": "+441174960000", "international": "+44 117 496 0000", "national": "0117 496 0000",
"country": "GB", "type": "FIXED_LINE", "foundVia": "tel" }
],
"contactPageUrl": "https://examplebakery.co.uk/contact/",
"contactFormUrl": "https://examplebakery.co.uk/contact/",
"address": { "street": "1 High Street", "city": "Bristol", "region": null, "postalCode": "BS1 1AA", "country": "GB" },
"counts": { "emails": 2, "phones": 1, "socialProfiles": 2 },
"contactsFound": true,
"pagesScanned": [
{ "url": "https://examplebakery.co.uk/", "kind": "home", "httpStatus": 200 },
{ "url": "https://examplebakery.co.uk/contact/", "kind": "contact", "httpStatus": 200 }
],
"charged": true,
"error": null
}

status is one of ok, http_error, unreachable, robots_disallowed or invalid_input. Only ok rows with contactsFound: true are charged, and charged tells you which ones were. The run's OUTPUT record in the key-value store has totals (websites, ok, with contacts, charged, emails, phones, social profiles).

Pricing

$3 per 1,000 websites with contacts found ($0.003 each), plus the tiny Apify run start fee. Nothing else: websites with no contacts, failed websites and invalid inputs are free, and so is the extra page loading. Set a Maximum cost per run and the Actor stops cleanly when it is reached.

RunWebsitesTypical cost
Prefilled input in the Console6$0.018
Empty input via the API (3 demo sites)3$0.009
100 brand websites (our test: 79 had contacts)100about $0.24
1,000 local businesses from Google Maps1,000at most $3, less for sites with no contacts

In our test on 100 well known brand websites, 79 had contacts (email 59%, phone 42%, social 88%). Small business sites usually publish more contact details than big brands. With Apify's free monthly credit you can scan well over a thousand websites before paying anything.

Integrations and API

  • API: run it and get the rows back in one call, for example POST https://api.apify.com/v2/acts/joesimo~contact-details-finder/run-sync-get-dataset-items?token=YOUR_TOKEN with the input as the JSON body. See the API tab for JavaScript, Python and cURL code.
  • No-code: connect it with Make, Zapier or n8n, or push results to Google Sheets or a webhook when a run finishes.
  • Chain Actors: point datasetId at the output of a Google Maps, directory or lead list Actor, then pass the emails to an email validator.
  • AI agents: callable as a tool through the Apify MCP server.
  • Export: CSV, Excel, JSON, XML or HTML. The flat columns (primaryEmail, primaryPhone, linkedin, facebook...) drop straight into a spreadsheet or CRM.

FAQ

Do I pay for websites where nothing was found? No. Only rows with status: ok and at least one email, phone or social profile are charged, and the charged field shows which ones were.

Does it find personal emails of employees? No. It only reads what the website publishes on its own contact-type pages. It does not guess email patterns, visit team or careers pages, or look people up.

Why is a site marked http_error? Usually bot protection (HTTP 403) or a server error. The Actor does not bypass protection, and these rows are free.

Can it read emails hidden behind JavaScript or "name [at] domain"? No, see the limits below. The contact page and contact form URL are always returned so you can follow up by hand.

How fast is it? About 100 websites in 35 seconds at the default 512 MB memory.

Honest limits

  • No JavaScript rendering. Details that only appear after scripts run (some Wix and single page app sites, chat widgets, map embeds) are not seen.
  • Hidden emails are not decoded. Addresses protected by Cloudflare email obfuscation or written as "name [at] domain" are skipped. protectedEmailsSkipped counts the Cloudflare ones so you know to check the contact page by hand.
  • No bot protection bypass. Sites behind bot protection answer 403 and are saved as http_error for free. About 13% of large brand sites did this in our tests; small business sites rarely do.
  • robots.txt is respected by default, and the Actor identifies itself with an honest User-Agent.
  • Public business contacts only. It reads what the website itself publishes. It does not guess email patterns, look up people, or collect names, job titles or personal profiles from team pages (team, careers and login pages are never visited, and schema.org Person data is ignored).
  • Same website only. Pages on other domains and subdomains (blogs, help centers, shops on other hosts) are not followed.

Responsible use

The data comes from public web pages, but emails and phone numbers can still be personal data under GDPR, CCPA and similar laws, for example a sole trader's own address. You are responsible for having a lawful basis to store and use it, and for following anti spam rules (CAN-SPAM, PECR) when you contact anyone. Do not use the output for unsolicited bulk email.

Tips

  • Feed it the output of a Google Maps or directory Actor with datasetId and datasetField set to the website field.
  • Turn on sameDomainEmailsOnly and roleEmailsOnly for clean, shared business inboxes only.
  • Raise maxPagesPerSite to 6 or 8 for large sites with many location pages. It costs a little more compute but not more per website.
  • Pair it with an email validator to check the addresses before outreach.

Support

Found a site where a published contact was missed, or a wrong result? Open an issue on the Actor's Issues tab with the domain and we will look at it. Contact: joesimo@mail.grokbot.com

More examples and the docs for all 6 of our Actors: github.com/Joe-Simo/apify-actors. Store page: https://apify.com/joesimo/contact-details-finder