Website Contact Finder: Emails, Phones & Socials avatar

Website Contact Finder: Emails, Phones & Socials

Pricing

$3.00 / 1,000 domain with contacts

Go to Apify Store
Website Contact Finder: Emails, Phones & Socials

Website Contact Finder: Emails, Phones & Socials

Find emails, phone numbers and social profiles on business websites, from a list of domains or a Google Maps dataset. One row per domain, with the page each contact came from. Flat price per domain with contacts found; domains with none are free.

Pricing

$3.00 / 1,000 domain with contacts

Rating

0.0

(0)

Developer

Brian Gomes

Brian Gomes

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 hours ago

Last modified

Categories

Share

Website Contact Finder reads business websites and returns their emails, phone numbers and social profiles, one row per domain, with the page each one came from. You pay a flat $0.003 for each domain where it finds an email or a phone. Domains where it finds nothing are free.

What it does

Give it a list of domains, or the dataset from a Google Maps scraper run. For each domain it reads the homepage and up to 5 likely contact pages: contact, impressum, about, team and legal pages, picked from the homepage's links. It pulls out every email address, every phone number and every social profile it finds, and tells you the page each one was on.

Each email is tagged role (info@, sales@, office@) or personal (jane@, john.smith@). Turn on Only role emails and the personal ones are left out of the results.

The same homepage visit also gives you a few website checks for free: HTTPS, whether http:// redirects to https://, status code, response time, title and meta description, mobile viewport, CMS, the footer's copyright year and whether there's a sitemap.

A site it can't read doesn't fail the run. A site that's down, blocks bots or turns out to be a parked domain gets a row that says so, and isn't charged.

Here's what five rows look like:

domaintypeprimaryEmailprimaryPhonecontactPageUrl
acmeplumbing.comcontactsinfo@acmeplumbing.com(614) 555-0142https://acmeplumbing.com/contact
bobsbakery.comcontactshello@bobsbakery.com503-555-0187https://bobsbakery.com/visit-us
smile-dental.comcontacts(none)+1 512-555-0119https://smile-dental.com/contact-us
riverside-cafe.comno-contacts(none)(none)(none)
oldsite.comerror(blocked: HTTP 403)

(Example data.)

Where the websites come from

  • A list. Paste domains or URLs, one per line: acme.com, www.acme.com or https://acme.com/contact all mean the same domain, which is searched once.
  • A Google Maps dataset. Run any Google Maps scraper first, then pick its dataset in Dataset from a Google Maps Actor. This Actor reads each place's website and keeps the place's name in the name column, so you can match rows back. Places without a website are skipped and cost nothing. This Actor never reads Google Maps itself.

A link to a Facebook, Instagram or Yelp page in the website column isn't the business's own site, so it's reported and not searched.

Who it's for

  • Agencies and freelancers. Turn a list of local businesses into a list you can contact, with the website checks to start the conversation.
  • Google Maps lead lists. Add emails to places that only came with a phone number and a website.
  • Sales teams. Fill in the contact page and general inbox for accounts you already know.
  • Researchers. Check which businesses in a list have a working website at all.

Input

FieldWhat it doesDefault
Websites or domainsDomains or URLs, one per line. Duplicates are dropped.none
Dataset from a Google Maps ActorA dataset whose items have a website field.none
Only role emailsKeep info@, sales@ and the like; leave out addresses that name a person.off
Maximum domainsStops after this many unique domains. Your hard ceiling on cost.100
Contact pages per domainPages read after the homepage, 0 to 5.5
Website field in the datasetWhere the website is in each dataset item. Dots reach into nested fields.website
Domains in flight at onceDomains searched in parallel. Each domain still gets one request at a time.10
Request timeout (seconds)The longest one request may take.15

Give at least one website or a dataset. Input field names in the API: websites, datasetId, onlyRoleEmails, maxDomains, maxContactPages, datasetField, maxConcurrency, requestTimeoutSecs.

The form starts with 2 domains, which costs at most $0.006.

Example input:

{
"websites": ["acmeplumbing.com", "https://www.bobsbakery.com/"],
"datasetId": "YOUR_GOOGLE_MAPS_DATASET_ID",
"onlyRoleEmails": true,
"maxDomains": 1000
}

Output

One row per domain. Export it from the Console as CSV, JSON, Excel, XML or HTML, or read it through the Apify API. The Contacts view shows the contact columns; the Website signals view shows the checks.

FieldWhat it holds
typecontacts (at least one email or phone; charged), no-contacts (read, nothing found; free) or error (not read; free).
statusok, or why the site wasn't read: blocked, unreachable, robots-disallowed, http-error, parked, not-a-website, invalid, stopped.
domain, input, nameThe domain searched, what you gave for it, and the place's name from a Google Maps dataset.
urlThe homepage, after redirects.
primaryEmailThe best email for a first contact: one on the site's own domain, a role address first.
primaryPhoneThe first phone number, preferring a clickable tel: link.
emailsEvery email: email, kind (role or personal), sameDomain (on the website's own domain) and sourceUrl (the page it was on).
phonesEvery phone number: phone as written, digits, from (tel-link or page-text) and sourceUrl.
socialsEvery social profile: network (facebook, instagram, linkedin, x, youtube, tiktok, pinterest, threads, whatsapp), url and sourceUrl. Share buttons and single posts are left out.
emailsText, phonesText, socialsTextThe same lists as one line each, for spreadsheets.
contactPageUrlThe site's contact page, if it has one.
emailHiddentrue when the site hides an email from bots (Cloudflare's email protection, or "name (at) domain"). It isn't decoded; look it up by hand on the contact page.
personalEmailsLeftOutWith Only role emails on, how many personal addresses were left out.
https, httpRedirectsToHttpsWhether the homepage is served over HTTPS, and whether http:// sends visitors there.
statusCode, responseTimeMsThe homepage's HTTP status and how long it took to answer.
hasTitle, title, hasMetaDescription, metaDescriptionThe homepage's title and meta description, and whether each is there.
hasViewportWhether the homepage has a mobile viewport tag.
generator, cmsThe generator tag, and the CMS or site builder it or the page's files point to (WordPress, Wix, Squarespace, Shopify and others).
copyrightYearThe latest year in the copyright notice. An old year often means a site nobody updates.
hasSitemap, sitemapUrlWhether the site has a sitemap (from robots.txt, or /sitemap.xml).
pagesReadEvery page read for this domain.
noteAnything worth knowing about a row that was read, such as a page cut off at 3 MB.
errorWhy the site wasn't read, in words. Empty when it was.

Example row (JSON):

{
"type": "contacts",
"status": "ok",
"domain": "acmeplumbing.com",
"name": "Acme Plumbing",
"url": "https://www.acmeplumbing.com/",
"primaryEmail": "info@acmeplumbing.com",
"primaryPhone": "(614) 555-0142",
"contactPageUrl": "https://www.acmeplumbing.com/contact",
"emails": [
{ "email": "info@acmeplumbing.com", "kind": "role", "sameDomain": true, "sourceUrl": "https://www.acmeplumbing.com/" },
{ "email": "jane@acmeplumbing.com", "kind": "personal", "sameDomain": true, "sourceUrl": "https://www.acmeplumbing.com/team" }
],
"phones": [
{ "phone": "(614) 555-0142", "digits": "6145550142", "from": "tel-link", "sourceUrl": "https://www.acmeplumbing.com/" }
],
"socials": [
{ "network": "facebook", "url": "https://www.facebook.com/acmeplumbing", "sourceUrl": "https://www.acmeplumbing.com/" }
],
"https": true,
"httpRedirectsToHttps": true,
"statusCode": 200,
"responseTimeMs": 640,
"hasMetaDescription": false,
"hasViewport": true,
"cms": "WordPress",
"copyrightYear": 2019,
"hasSitemap": true,
"error": null
}

Each signal is a first look. For the full check, run Site Audit (every page's SEO issues, with fixes), Broken Link Checker from Sitemap or Bulk PageSpeed Insights on the same site.

Pricing

One price, per domain, with nothing on top.

  • Each domain where it finds at least one email or phone: $0.003, so $3 per 1,000.
  • Free: domains where it finds no email or phone, sites that are down, blocked, parked or disallowed by robots.txt, places without a website, duplicates, and anything it never got to.
  • No start fee, no per-page charge, no add-ons. Reading 6 pages of a domain costs the same as reading 1. Social profiles and the website checks come with the row.
Domains you give itThe most it can cost
100$0.30
1,000$3.00
10,000$30.00

1,000 domains never cost more than $3. If only 600 of them have contacts, you pay $1.80.

Set Maximum domains, or a maximum cost per run, for a hard ceiling. A domain is only started when your maximum cost still covers it (as if it will find contacts), so the run never finds contacts it can't give you. When the next domain wouldn't fit, the run stops and its last row says how many domains weren't checked.

How it handles the hard cases

  • Bot protection. A site that answers 403, 401 or 429, or shows a CAPTCHA or "checking your browser" page, is reported as blocked and left alone. It isn't retried through proxies or a browser. Free.
  • Emails hidden from bots. Cloudflare's email protection and "name (at) domain" are a site's way of saying no to email collectors, so they aren't decoded. The row says emailHidden: true.
  • Text that only looks like an email. Some sites scramble their text against copying and unscramble it with JavaScript, which turns into strings like ntr@icspspo.eos. An address is kept only if its top-level domain exists, and, when it's on another domain than the site's, if that domain has a DNS record. File names like logo@2x.png and placeholders like you@example.com are left out too.
  • Sites that don't answer. It tries https, then http, then the www. host if the bare domain doesn't resolve. A site that still doesn't answer is unreachable, with the reason: no DNS record, connection refused, timed out or a TLS error. Free.
  • Parked and for-sale domains. Recognised by the parking service they redirect to, or by "this domain is for sale" on the page. Reported as parked, so you don't pay for a domain marketplace's contact details. Free.
  • A Facebook page in the website column. Reported as not-a-website and not searched.
  • Single-page sites and soft 404s. When the homepage links to no contact page, it tries /contact and /contact-us. A page that turns out to be the homepage again, or a "not found" page answered with status 200, isn't counted.
  • JavaScript-only sites. It reads the HTML the server sends, without a browser. Contact details that only appear after JavaScript runs (some Wix, GoDaddy and Squarespace templates) aren't seen. Those rows come back as no-contacts and aren't charged.
  • Big pages. It reads up to 3 MB of HTML per page, and notes it when a page is longer.
  • Time limit. Near the run's timeout it stops starting domains, finishes the ones in flight and ends normally, with a row saying how many weren't checked.

robots.txt and good manners

  • It respects robots.txt (RFC 9309). If robots.txt disallows the homepage, or can't be read because the server errors, nothing on that site is fetched and the row says why.
  • It honours Crawl-delay up to 10 seconds. A site that asks for more gets one page read, the homepage.
  • It sends one request at a time to a site, and reads at most 6 pages of it.
  • It identifies itself honestly as WebsiteContactFinder/0.1. No proxies, no browser, no logins.
  • Addresses on private networks, loopback and cloud metadata ranges are refused, including when a public site redirects to one.

Using the contacts lawfully

This Actor finds contact details that businesses publish on their own websites. What you do with them is up to you, and so is following the law where you and your recipients are. This isn't legal advice; check with counsel for your case.

  • GDPR (EU and UK). An email that names a person, such as jane@acme.de, is personal data even when it's published on a company website. You're the controller for what you collect, so you need a lawful basis and must tell people where you got their data. Under Apify's terms, the user is the controller and the Actor's developer is a processor for personal data in inputs and outputs. To keep personal data out entirely, turn on Only role emails.
  • Nothing is kept. Each run's results go to your own dataset and nowhere else. The Actor keeps no database, caches nothing between runs and never shares one buyer's results with another.
  • CAN-SPAM (US). B2B cold email is legal without prior consent if each message has a real sender, a subject line that isn't misleading, a physical postal address and a working way to opt out, and opt-outs are honoured within 10 business days. Penalties can exceed $50,000 per email that breaks the rules. See the FTC's compliance guide.
  • France allows B2B email to professional addresses on an opt-out basis, if the message relates to the recipient's job.
  • Germany is stricter: B2B email generally needs prior consent (UWG §7).

Compared with other contact finders

Other contact scrapers in the Store charge per page crawled, per proxy request or per add-on, so the bill depends on how big each site is and which boxes were ticked. Users report paying $71 for 1,105 rows because a run crawled 18,011 pages, and $154 for 51 places once enrichment add-ons were counted.

This Actor charges once per domain where it finds an email or phone, and the price doesn't change with how many pages it reads. It doesn't use a browser or residential proxies, so it's cheaper to run, and it doesn't work around bot protection. The trade-off is that it misses contacts that only appear after JavaScript runs.

Not made by or affiliated with Google, Apify's Google Maps Actors or any social network.

FAQ

How do I find emails for a list of websites? Paste the domains into Websites or domains and run it. You get one row per domain with its emails, phones and social profiles. Export it as CSV.

How do I add emails to my Google Maps results? Run your Google Maps scraper, then pick its dataset in Dataset from a Google Maps Actor. Each row keeps the place's name, so you can join the two.

How often does it find something? On a sample of 20 small-business websites (plumbers, bakeries, dentists and carpenters in the US and Germany, October 2026), 3 refused it with a 403. Of the 17 it could read, it found an email or phone on 16 (94%), an email on 14 (82%), a phone on 16 and the contact page on 15. Across all 20, that's contacts for 16 (80%). It read about 4 pages per site. Sites whose contact details only appear after JavaScript runs find less, and rows with nothing found aren't charged.

What's the difference between role and personal emails? A role address belongs to a function (info@, sales@, office@, bookings@). A personal one names someone (jane@, j.smith@). Anything it can't tell is treated as personal, the cautious choice.

Why is a site blocked? The site refused the request or showed a bot check. This Actor doesn't get around that, by design. Visit the site yourself to find its contact details.

Why are there emails on other domains? Many small businesses use a Gmail or Outlook address, and some sites show their web designer's address in the footer. sameDomain tells them apart.

Does it verify the emails? No. It reports what the site publishes. An address on a site can still bounce.

Can I run it on a schedule? Yes, but each run searches the sites again and charges again for domains with contacts. It doesn't keep results between runs.

Can I call it from my own code? Yes. Start it and read the results through the Apify API or the Python and JavaScript clients. It also works with webhooks, Make, Zapier and Google Sheets.

Limits

  • Plain HTTP, no browser: contact details added by JavaScript aren't seen.
  • At most 6 pages per domain: the homepage and 5 contact pages.
  • Sites behind bot protection, a login or a robots.txt that disallows it aren't read.
  • Emails hidden from bots aren't decoded.
  • Phone numbers are reported as written. Numbers without a country code aren't converted to international format.
  • It runs in 256 MB by default.

Integrations

This Actor runs on Apify, so everything the platform does works with it.

  • API. Start a run and read the results from your own code, in any language. Apify API
  • Schedules. Run it again when your list changes. Schedules
  • Tasks. Save your input once as a task and run it again with one click. Tasks
  • Webhooks. Get a call to your own URL when a run succeeds or fails. Webhooks
  • Google Sheets and Drive. Download the results as CSV or Excel and open them in Sheets, or add a Google Sheets step after this Actor in Make or Zapier. Datasets and exports, Google Drive
  • Zapier, Make and n8n. Start a run from another app and send the results on to your CRM. Zapier, Make, n8n
  • AI agents (MCP). Claude, ChatGPT and other MCP clients can find and run this Actor through the Apify MCP server. Apify MCP server
  • Other Actors. Feed it the dataset of a Google Maps scraper when that run finishes. Actor-to-Actor

Works with

Support

Found a bug or need a feature? Open an issue on this Actor's Issues tab. Include the run ID and the domain it got wrong.