Website Contact Finder: Emails, Phones & Socials
Pricing
$3.00 / 1,000 domain with contacts
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
Maintained by CommunityActor 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:
| domain | type | primaryEmail | primaryPhone | contactPageUrl |
|---|---|---|---|---|
| acmeplumbing.com | contacts | info@acmeplumbing.com | (614) 555-0142 | https://acmeplumbing.com/contact |
| bobsbakery.com | contacts | hello@bobsbakery.com | 503-555-0187 | https://bobsbakery.com/visit-us |
| smile-dental.com | contacts | (none) | +1 512-555-0119 | https://smile-dental.com/contact-us |
| riverside-cafe.com | no-contacts | (none) | (none) | (none) |
| oldsite.com | error | (blocked: HTTP 403) |
(Example data.)
Where the websites come from
- A list. Paste domains or URLs, one per line:
acme.com,www.acme.comorhttps://acme.com/contactall 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
websiteand keeps the place's name in thenamecolumn, 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
| Field | What it does | Default |
|---|---|---|
| Websites or domains | Domains or URLs, one per line. Duplicates are dropped. | none |
| Dataset from a Google Maps Actor | A dataset whose items have a website field. | none |
| Only role emails | Keep info@, sales@ and the like; leave out addresses that name a person. | off |
| Maximum domains | Stops after this many unique domains. Your hard ceiling on cost. | 100 |
| Contact pages per domain | Pages read after the homepage, 0 to 5. | 5 |
| Website field in the dataset | Where the website is in each dataset item. Dots reach into nested fields. | website |
| Domains in flight at once | Domains 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.
| Field | What it holds |
|---|---|
type | contacts (at least one email or phone; charged), no-contacts (read, nothing found; free) or error (not read; free). |
status | ok, or why the site wasn't read: blocked, unreachable, robots-disallowed, http-error, parked, not-a-website, invalid, stopped. |
domain, input, name | The domain searched, what you gave for it, and the place's name from a Google Maps dataset. |
url | The homepage, after redirects. |
primaryEmail | The best email for a first contact: one on the site's own domain, a role address first. |
primaryPhone | The first phone number, preferring a clickable tel: link. |
emails | Every email: email, kind (role or personal), sameDomain (on the website's own domain) and sourceUrl (the page it was on). |
phones | Every phone number: phone as written, digits, from (tel-link or page-text) and sourceUrl. |
socials | Every 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, socialsText | The same lists as one line each, for spreadsheets. |
contactPageUrl | The site's contact page, if it has one. |
emailHidden | true 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. |
personalEmailsLeftOut | With Only role emails on, how many personal addresses were left out. |
https, httpRedirectsToHttps | Whether the homepage is served over HTTPS, and whether http:// sends visitors there. |
statusCode, responseTimeMs | The homepage's HTTP status and how long it took to answer. |
hasTitle, title, hasMetaDescription, metaDescription | The homepage's title and meta description, and whether each is there. |
hasViewport | Whether the homepage has a mobile viewport tag. |
generator, cms | The generator tag, and the CMS or site builder it or the page's files point to (WordPress, Wix, Squarespace, Shopify and others). |
copyrightYear | The latest year in the copyright notice. An old year often means a site nobody updates. |
hasSitemap, sitemapUrl | Whether the site has a sitemap (from robots.txt, or /sitemap.xml). |
pagesRead | Every page read for this domain. |
note | Anything worth knowing about a row that was read, such as a page cut off at 3 MB. |
error | Why 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 it | The 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
blockedand 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 likelogo@2x.pngand placeholders likeyou@example.comare 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-websiteand 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-contactsand 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
- Site Audit: an SEO score from 0 to 100 for every page, with a fix for each issue.
- Bulk PageSpeed Insights for a Sitemap: performance scores and Core Web Vitals for every page, mobile and desktop.
- Broken Link Checker from Sitemap: every broken link on every page in a sitemap, with the page it's on.
- Sitemap URL Extractor & Status Checker: the full URL list of a site, with lastmod and status codes.
- Website Screenshot API: a clean full-page screenshot of every URL, with cookie banners and pop-ups hidden.
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.