Email Finder — Website Emails, Phones & Socials — $2/1k avatar

Email Finder — Website Emails, Phones & Socials — $2/1k

Pricing

from $2.00 / 1,000 contact rows

Go to Apify Store
Email Finder — Website Emails, Phones & Socials — $2/1k

Email Finder — Website Emails, Phones & Socials — $2/1k

Email finder for company websites: crawls contact, about, team and imprint pages for emails, phones, socials and addresses. Bulk domains from CSV or Google Sheets, deobfuscation, DNS MX check, empty domains not charged. No login or cookies. MCP-ready for AI agents. $2 per 1,000 records.

Pricing

from $2.00 / 1,000 contact rows

Rating

0.0

(0)

Developer

Khrystyna Skotte

Khrystyna Skotte

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

17 days ago

Last modified

Security

Limited permissions

Share

Email Finder — Website Emails, Phones & Socials

Give it a list of company websites and get back the email addresses, phone numbers, social profiles and postal addresses those sites publish, with the page each contact came from. It is an email finder for domains you already have — from Google Maps exports, directories, CRMs or a spreadsheet column — not a people database. No login, no cookies, no browser: plain HTTP, 512 MB of memory, about 5–10 seconds per website.

What makes it different from the other email finders in the Store:

  • You are not charged for domains that return nothing. A website with no email, phone or social profile is listed in the run's OUTPUT summary with the reason (blocked, timeout, no_contacts…) instead of producing a paid empty row.
  • Every email is auditable. Each address carries the sourceUrl it was found on and a context snippet of the surrounding text, so you can see why it was extracted.
  • Pages are crawled in the order that matters: home page → contact → imprint/legal notice → about/team/people → support → press → careers → privacy, plus footer links and sitemap.xml hints. Ten pages per site is usually enough to find everything.
  • Obfuscated addresses are decoded: name [at] domain [dot] com, HTML entities, Cloudflare email protection (__cf_email__), and mailto: links with subjects.
  • Deduplicated, lowercased, typed. Every email is tagged generic (info@, sales@, press@…) or personal (jason@, first.last@) so you can route role inboxes and named people differently.
  • DNS MX check (mxValid) tells you whether the email's domain can receive mail at all.

What you get

Per website (outputMode: perDomain, the default):

FieldExampleNotes
domainfsf.orgRegistered domain of the website
websiteUrlhttps://fsf.org/The URL you supplied, normalised
websiteTitleFront Page — Free Software Foundation — …<title> of the home page
redirectedTonullSet when the home page redirected to another domain
emails[]{ "email": "info@fsf.org", "type": "generic", "isOffDomain": false, "sourceUrl": "https://www.fsf.org/about/contact/", "context": "…please email info@fsf.org. Thank you…", "name": null, "title": null, "mxValid": true }One object per unique email; isOffDomain is true when the address is on another domain (gmail, agency, partner)
emailCount8
primaryEmailcampaigns@fsf.orgFirst generic inbox, else the first email found
phones[]["+16175425942"]From tel: links, JSON-LD and page text; duplicates in national and international form are merged
socials{}{ "linkedin": "https://www.linkedin.com/company/creative-commons", "github": "…" }facebook, instagram, linkedin, twitter, youtube, tiktok, github, pinterest, threads, telegram, whatsapp
addresses[]["31 Milk Street # 960789, Boston, MA, 02196, US"]JSON-LD PostalAddress and <address> blocks
people[][{ "name": "…", "title": "…", "email": "…" }]From JSON-LD Person markup (only when includeNames is on)
mxValidtrueMX record exists for the website's own domain
pagesCrawled10
statusokok, partial_timeout, no_contacts (only with includeEmptyDomains)
scrapedAt2026-10-21T16:16:05.950Z

Per email (outputMode: perEmail) you get one flat row per unique address: email, type, isOffDomain, domain, websiteUrl, websiteTitle, name, title, sourceUrl, context, mxValid, plus the site's phones, socials, addresses, pagesCrawled, status, scrapedAt. This is the shape to import straight into a CRM or an outreach tool.

What people use it for

  1. Enrich a Google Maps or directory export. Scrape businesses with any Google Maps actor, feed the website column in here, get emails for the ones that publish them.
  2. Cold outreach lists. Run a CSV of target domains, filter type = personal and mxValid = true, and you have named contacts with the page that proves the address is public.
  3. Press and partnership lists. emailFilter: generic returns only press@, partnerships@, info@ inboxes across hundreds of sites in one run.
  4. CRM hygiene. Re-run your account list monthly; compare emails[] with what is in the CRM to catch changed or removed addresses.
  5. Agency prospecting. Pull socials and phones together with the email to see which channels a business is active on before you reach out.
  6. Compliance and research. The imprint/legal-notice priority finds the legally required contact details on EU websites (Impressum, mentions légales, aviso legal).

Input

All fields are optional. With no input at all the actor runs a sample on ten public organisation websites so you can see the output shape.

One row per domain (default)

{
"startUrls": [{ "url": "https://www.fsf.org" }, { "url": "creativecommons.org" }],
"maxPagesPerDomain": 10,
"maxDepth": 2,
"includePhones": true,
"includeSocials": true,
"includeNames": true,
"verifyMx": true,
"maxItems": 100
}

One row per email, named people only, same-domain only

{
"domains": ["apify.com", "basecamp.com", "letsencrypt.org"],
"outputMode": "perEmail",
"emailFilter": "personal",
"onlySameDomain": true,
"maxItems": 500
}

Bulk list from a CSV or Google Sheet

{
"listUrl": "https://docs.google.com/spreadsheets/d/1AbC…/edit#gid=0",
"outputMode": "perDomain",
"maxItems": 2000,
"maxConcurrency": 10
}

The first column of the sheet or CSV is read (a header such as domain, website or url is skipped). Share the sheet as "anyone with the link". You can combine startUrls, domains and listUrl in one run; duplicates are removed.

All inputs

FieldDefaultWhat it does
startUrls—Websites as { "url": … } objects (the Apify URL list editor)
domains—Websites as plain strings; urls is accepted as an alias
listUrl—CSV, TXT, Google Sheet or Google Drive file with one website per line
outputModeperDomainperDomain or perEmail
maxItems10Rows to stop at (domains or emails depending on the mode)
maxPagesPerDomain10Pages fetched per site (maxPagesPerSite and maxRequestsPerStartUrl are accepted as aliases)
maxDepth2Link depth from the home page; 0 = home page only
emailFilterallall, generic (role inboxes) or personal (named people)
onlySameDomainfalseDrop emails on other domains (gmail, agencies, partners)
verifyMxtrueDNS MX lookup per email domain → mxValid
deobfuscatetrueDecode [at]/[dot], entities, Cloudflare protection
includePhones / includeSocials / includeNamestrueToggle the extra signals
includeEmptyDomainsfalseAlso save (and pay for) rows for domains with no contacts
perDomainTimeoutSecs60A slow site stops after this; what was found is kept
maxConcurrency5Websites crawled in parallel
proxyConfigurationoffApify proxy for sites that block datacenter IPs (status: blocked)

Output example

A real perDomain row from a run on 2026-10-21 (trimmed to three emails):

{
"domain": "fsf.org",
"websiteUrl": "https://fsf.org/",
"websiteTitle": "Front Page — Free Software Foundation — working together for free software",
"redirectedTo": null,
"emails": [
{ "email": "campaigns@fsf.org", "type": "generic", "isOffDomain": false, "name": null, "title": null, "sourceUrl": "https://www.fsf.org/", "context": "Send your feedback on our translations and new translations of pages to campaigns@fsf.org.", "mxValid": true },
{ "email": "info@fsf.org", "type": "generic", "isOffDomain": false, "name": null, "title": null, "sourceUrl": "https://www.fsf.org/about/contact/", "context": "olunteer opportunities, shop items, meeting staff, etc., please email info@fsf.org. Thank you for your interest", "mxValid": true },
{ "email": "membership@fsf.org", "type": "generic", "isOffDomain": false, "name": null, "title": null, "sourceUrl": "https://www.fsf.org/associate/contact.html", "context": "You can email us with any membership questions or support requests: membership@fsf.org or contact the Free Software Foundation.", "mxValid": true }
],
"emailCount": 8,
"primaryEmail": "campaigns@fsf.org",
"phones": ["+16175425942"],
"socials": {},
"addresses": ["31 Milk Street # 960789, Boston, MA, 02196, US"],
"people": [],
"mxValid": true,
"pagesCrawled": 10,
"status": "ok",
"error": null,
"scrapedAt": "2026-10-21T16:16:05.950Z"
}

And a perEmail row from the same day:

{
"email": "press@letsencrypt.org",
"type": "generic",
"isOffDomain": false,
"domain": "letsencrypt.org",
"websiteUrl": "https://letsencrypt.org/",
"websiteTitle": "Let's Encrypt",
"name": null,
"title": null,
"sourceUrl": "https://letsencrypt.org/contact/",
"context": "Email: press@letsencrypt.org",
"mxValid": true,
"phones": [],
"socials": { "github": "https://github.com/letsencrypt", "linkedin": "https://www.linkedin.com/company/lets-encrypt" },
"addresses": [],
"pagesCrawled": 10,
"status": "ok",
"scrapedAt": "2026-10-21T16:17:08.754Z"
}

The run's OUTPUT record (key-value store) summarises everything: rows saved, emails found, domains requested, and a failed[] list with a reason for every domain that produced no row.

Pricing

Pay per event, no subscription:

  • $0.001 per run start (per GB of memory; the actor runs at 512 MB, so one start event).
  • $0.002 per row saved — one website in perDomain mode (with all of its emails, phones and socials), or one email in perEmail mode.

So 1,000 websites cost about $2 in perDomain mode plus Apify platform usage (roughly $0.2 per 1,000 sites at 512 MB — the test run above processed 10 sites for $0.0017 all-in). Domains that return no contacts are not charged. For comparison, the per-page email extractors in the Store charge $0.001–0.002 per page crawled (so $0.01–0.02 per 10-page site), and the per-row ones $0.02 per site; the big "leads finder" databases charge $0.003 per lead and bill you for leads without emails.

Good to know

  • No SMTP verification, by design. Apify blocks outbound port 25, so no actor running on the platform can really talk to a mail server. mxValid is an honest DNS check: true means the domain has mail exchangers, false means mail to that domain will bounce, null means DNS did not answer. Treat "verified email" claims from other cloud actors accordingly.
  • Sites rendered only by JavaScript (and sites behind aggressive bot protection) may return status: blocked or no_contacts. Turn on proxyConfiguration with Apify residential proxy for the blocked ones; a browser-based crawler is the fallback for pure single-page apps.
  • Email coverage depends on the website. Many small businesses only publish a contact form. Those domains show up in the OUTPUT summary as no contacts found and are not charged — the dataset only contains sites that actually publish something.
  • Junk is filtered. Addresses on third-party infrastructure (mail-archive.com, sentry.io, wixpress.com, schema.org, googlegroups.com, CDNs, platforms…), noreply@/donotreply@ senders, image names like logo@2x.png, hash-like local parts and other sites' mailing lists (lists.*) are dropped. Off-domain addresses that survive are kept but flagged isOffDomain: true; set onlySameDomain: true to drop them too.
  • type is a heuristic. Known role words, hyphenated roles (license-violation@), plural or -ing/-tion nouns and list servers are generic; everything else is personal. Filter on it, but spot-check.
  • Names and titles are filled when a person's name sits next to their email on a page (staff or team pages, author boxes) or in JSON-LD Person markup. On fsf.org's staff page, for example, 12 of 13 emails came back with name and title (zoe@fsf.org → Zoë Kooyman, Executive Director). Contact pages with only role inboxes return null.
  • Politeness: one site at a time is crawled with a short random delay between pages, up to maxPagesPerDomain pages, inside perDomainTimeoutSecs. The crawl never leaves the website's own domain.
  • Legal: the actor only collects contact details a company publishes on its own website. You are responsible for using them in line with GDPR, CAN-SPAM and the laws that apply to your outreach.

Integrations

  • API: POST https://api.apify.com/v2/acts/chimerical_quicklime~website-email-finder/run-sync-get-dataset-items?token=… with the JSON input above returns the rows directly; for big lists start a run with /runs and read the dataset when it finishes.
  • Python / JavaScript: apify-client — client.actor("chimerical_quicklime/website-email-finder").call(run_input={...}) then client.dataset(run["defaultDatasetId"]).list_items().
  • Schedules + webhooks: schedule the actor on your account list and add a webhook on ACTOR.RUN.SUCCEEDED to push new rows into your CRM.
  • Make, Zapier, n8n: use the Apify module/node, choose this actor, map email, domain, sourceUrl and mxValid to your sheet or CRM fields. perEmail mode gives one record per row, which is what these tools expect.
  • MCP / AI agents: add the actor to your Apify MCP server; an agent can call it with a list of domains and read the OUTPUT summary plus the dataset.
  • Export: JSON, CSV, Excel, XML and HTML from the dataset tab or the API.

FAQ

Can it find an email for a specific person? No. It finds the emails a website publishes. For "first name + last name + domain" guessing use a pattern finder; for named decision-makers use a people database.

Why did a domain not appear in the dataset? It produced no email, phone or social within maxPagesPerDomain pages and perDomainTimeoutSecs, or it was blocked. The reason is in the OUTPUT record. Set includeEmptyDomains: true if you want a row for it anyway.

Does it crawl the whole site? No — only up to maxPagesPerDomain pages, chosen by relevance (contact and about pages first), never off-domain.

Can I pass full URLs instead of domains? Yes. A deep URL is crawled from that page; links on it are followed within the same domain.

How fast is it? About 5–10 seconds per website at the defaults; maxConcurrency crawls several websites at once. 1,000 websites take roughly 20–30 minutes at maxConcurrency: 10.