Domain List Email Extractor: Emails & Phones from Websites
Pricing
from $1.28 / 1,000 domains
Domain List Email Extractor: Emails & Phones from Websites
Domain List Email Extractor API: extract emails from websites in bulk. An email extractor from domains: reads the homepage, contact, about and team pages and returns emails (role or personal), E.164 phones, contact page and social links. One row per domain; pay per domain with contacts.
Pricing
from $1.28 / 1,000 domains
Rating
0.0
(0)
Developer
Data Done Right
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
This Domain List Email Extractor takes a list of domains or website URLs and returns the emails from websites they publish, plus phone numbers, the contact page and social profile links. It is an email extractor from domains: for each site it reads the homepage and a few contact, about, team, careers or imprint pages (found through the site's own links and common paths such as /contact), and gives you one row per domain, in the same order as your list. No browser, no login, no API key.
It reads what a site publishes in its HTML and nothing else. It does not guess addresses, does not verify mailboxes and does not send email. See Responsible use and Honest limits.
How to use the domain list email extractor
- Paste your domains or URLs into Domains or website URLs, one per line (
acme.com,https://www.example.org/contact). URLs are cut back to the site root. - Choose how many pages to read per domain (default 5) and whether you want phone numbers, role emails (
info@) and personal emails. - Run it. Download one row per domain as JSON, CSV or Excel, or read it through the Apify API.
Every input gets a row, even when nothing is found, so your list stays aligned (the one exception: if a spending limit stops the run early, domains still waiting are not read and get no row). Use inputIndex or the input field to join the result back to your sheet.
Extract emails from websites: what you get
| Field | Meaning |
|---|---|
status | found, not_found, blocked, unreachable or invalid (see below) |
emails | {address, type, sourceUrl, onDomain}: type is role (info@, sales@, support@, hello@, press@...) or personal (jane.doe@), sourceUrl is the page it was published on |
phones | {e164, raw, sourceUrl}: valid numbers only, normalised offline to E.164 (+14155552671), duplicates merged |
contactPageUrl | the domain's contact page, when there is one |
socialLinks | profile links by platform (facebook, linkedin, twitter, instagram, youtube, tiktok, github...); share buttons are ignored |
pagesChecked | pages requested on the domain |
emailAddresses, phoneNumbers, emailCount, phoneCount | flat versions of the above for CSV and spreadsheets |
reason | plain-language explanation of the status |
| Status | Meaning | Charged |
|---|---|---|
found | At least one email or phone number was found. | yes |
not_found | The site was read, but its HTML publishes no email or phone number (the reason says when it looks JavaScript-rendered). | no |
blocked | robots.txt forbids reading, the site refuses bots (HTTP 401/403/429/503, bot-check page) or the domain points to an internal address. | no |
unreachable | No usable answer: DNS failure, timeout, connection error, HTTP 404/5xx. | no |
invalid | Not read: free-mail (gmail.com), social network or large platform, internal name or IP, not a domain, a duplicate of an earlier input, or beyond your maxDomains cap. | no |
Email extractor from domains: what it reads
- Pages: the homepage, then links that look like contact, about, team, people, careers, press or imprint pages (also
kontakt,contacto,impressum,mentions-legales), then common paths (/contact,/about,/team,/impressum...). Blog, shop and docs pages are skipped. Guessed paths stop after two 404s. - Where emails come from: visible text,
mailto:links (including percent-encoded ones), JSON-LD data in the page. These are always read. - Hidden addresses (Decode hidden addresses, on by default):
name [at] site [dot] com,(at)/(dot),{at}, HTML entities such as@, full-width@, and Cloudflare email protection (data-cfemailand/cdn-cgi/l/email-protectionlinks). - Placeholders are dropped:
you@example.com,name@domain.com, image file names such aslogo@2x.png, tracking addresses. - Phones:
tel:links and numbers in the text, parsed with the offlinephonenumberslibrary. Numbers written without+country codeare read in the country of the domain's ending (.de,.co.uk) or the Default phone country you set, otherwise US. Order numbers, dates and IDs are not returned. - Roles vs people: a mailbox such as
info,sales,support,hello,press,careers,billingorteamisrole; everything else ispersonal. The check is by name, so a shared mailbox with an unusual name shows up aspersonal. - Limits per domain: up to 50 emails and 20 phone numbers.
Emails from a list of domains: input example
{"domains": ["apify.com", "https://www.python.org/about/", "example.com", "gmail.com"],"pagesPerDomain": 5,"extractPhones": true,"includeRoleEmails": true,"includePersonalEmails": true,"decodeObfuscated": true,"concurrency": 10}
Besides the options above: maxDomains (hard cap, default 1000; domains beyond it get a free invalid row), onlyOwnDomainEmails (drop gmail.com and partner addresses), defaultPhoneCountry ("DE"), delaySecs (default 1), timeoutSecs (default 10) and an optional proxyConfiguration.
Output example
A trimmed row from a real run on the example input (sites change their pages, so your result will differ):
{"inputIndex": 0, "input": "apify.com", "domain": "apify.com", "status": "found","reason": "Found contact details on 5 page(s).","emails": [{"address": "support@apify.com", "type": "role", "sourceUrl": "https://apify.com/contact", "onDomain": true},{"address": "hello@apify.com", "type": "role", "sourceUrl": "https://apify.com/contact", "onDomain": true}],"phones": [],"emailAddresses": ["support@apify.com", "hello@apify.com"], "phoneNumbers": [], "emailCount": 2, "phoneCount": 0,"pagesChecked": 5, "contactPageUrl": "https://apify.com/contact","socialLinks": {"github": "https://github.com/apify/crawlee", "linkedin": "https://linkedin.com/company/apify","twitter": "https://x.com/apify", "youtube": "https://youtube.com/apify", "tiktok": "https://tiktok.com/@apifytech"},"charged": true}
A SUMMARY record in the key-value store counts domains by status, charged domains and whether a spending limit stopped the run.
Domain List Email Extractor API
Call it from the Apify API, Python, JavaScript, Make, Zapier or n8n. Example with the Apify Python client:
from apify_client import ApifyClientclient = ApifyClient("<APIFY_TOKEN>")run = client.actor("data-done-right/domain-email-extractor").call(run_input={"domains": ["acme.com", "https://www.example.org/contact"], "pagesPerDomain": 5})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row["domain"], row["status"], row["emailAddresses"], row["phoneNumbers"])
Join the rows back to your list with inputIndex. Rows with status other than found are free and tell you why in reason.
Use it in Claude, ChatGPT and Cursor
Connect Apify's MCP server (mcp.apify.com) and your AI assistant can pull contact details from a list of sites itself. For example: "extract emails and phone numbers from these 20 company domains and show me which ones are role mailboxes." The only required input is domains.
How much does it cost
Pay per event, with no per-run start fee: $0.0016 per domain with contact details (domain event), charged only when a domain's status is found, so a domain with at least one email or phone number. Domains with not_found, blocked, unreachable or invalid status are free. 1,000 domains with contacts cost about $1.60.
Paid Apify plans get 10% (Silver) to 20% (Gold and up) off. For comparison, the most-used page-based contact scraper on Apify charges $0.002 per scraped page (about $0.01 for a 5-page domain) and one website email scraper $0.02 per website with emails found. maxDomains caps the bill, and if you set a maximum spend per run the Actor stops cleanly when it is reached and keeps the rows already delivered (rows still in progress are not delivered or charged).
Responsible use
Public does not mean free to use. This Actor reads pages that are public and respects robots.txt, but what you do with the addresses is your responsibility.
- No spam. Do not send unsolicited bulk email. Personal addresses (
type: personal) are personal data under GDPR, UK GDPR and similar laws. Turn Include personal emails off if you only need company mailboxes. - EU and UK: B2B outreach needs a documented legitimate interest (GDPR Art. 6(1)(f)), an easy way to object and an information notice. Some countries require prior consent. US: CAN-SPAM requires honest headers, a physical address and a working opt-out. Canada (CASL) and others are stricter.
- Respect opt-outs. Keep a suppression list, honour unsubscribe requests and "do not contact" notes on the page.
- Store only what you need, for as long as you need it, and delete data when asked.
- Polite by design.
robots.txtis obeyed (aDisallowfor the bot is respected; a Crawl-delay slows it down, up to 10 s; 5xx on robots.txt means the site is skipped), requests to one site are spaced out, only a few pages are read, and bot-check pages are not bypassed. - Safe by design. The Actor refuses localhost, private networks, link-local and cloud-metadata addresses, also through DNS answers and redirects, and never follows a redirect to another domain. With a proxy, every URL and redirect is still checked, but the connection is not pinned to the checked IP address.
- Free-mail, social-network and large-platform domains (gmail.com, facebook.com, linkedin.com, github.com, google.com, amazon.com, wikipedia.org and similar) are skipped, so it does not harvest private mailboxes or profile pages.
Honest limits
- Static HTML only. Contact details that appear only after JavaScript runs (single-page apps, widgets, contact forms that load addresses on click) are not seen. Those domains come back as
not_foundwith a note when the homepage looks script-rendered. - Bot protection wins. Sites behind Cloudflare challenges, CAPTCHAs or aggressive WAFs return
blocked. The Actor does not try to get around them. - Not verified. Emails are what the site publishes. Nothing is sent and no mail server is contacted, so deliverability is unknown. Run your own verification before you send.
- No pattern guessing. If a site publishes no address you get no address. Use the Work Email Finder for pattern-based likely addresses of named people.
- Hidden addresses: simple obfuscation is decoded. Emails built by JavaScript, images of addresses, PDFs and contact forms are not.
- Role vs personal is a name check, not a verdict about who reads the mailbox. Mailing-list addresses can show as
personal. - Phone numbers: only numbers that are valid for their country are returned; a national-format number in an unusual region needs the Default phone country set.
- Sites differ. A few pages per domain is a sample, not a full crawl: raise
pagesPerDomain(up to 15) for large sites. Subdomains you enter are read as given (eu.acme.comis not shortened toacme.com).
FAQ
How do I extract emails from a list of domains?
Paste the domains into Domains or website URLs and run. You get one row per domain with its emails (role or personal), phone numbers, contact page and social links. Rows are in input order.
Does it find emails that are hidden or obfuscated?
Simple forms, yes: name [at] site [dot] com, (at), HTML entities, full-width @, percent-encoded mailto: links and Cloudflare-protected addresses. Addresses assembled by JavaScript or shown as images are not found.
What if a site has no email?
The row has status not_found (site read, nothing published), blocked or unreachable, with a reason. These rows are free.
Which domains are charged?
Only domains with status found: at least one email or phone number after your settings (role / personal / own-domain filters, phones on or off). Everything else is free, including invalid inputs and duplicates.
Can it find personal Gmail or Outlook addresses of a company's staff?
It does not look up people. It returns addresses a site publishes, including a gmail.com address a small business prints on its contact page (marked onDomain: false; set Only addresses on the site's own domain to drop them). Free-mail domains in your input list are skipped.
Does it respect robots.txt?
Yes. See Responsible use. A site that disallows the bot, or whose robots.txt returns a server error, is not read and gets status blocked.
How fast is it?
Domains are read in parallel (10 by default, up to 50), each one request at a time with a 1 second pause. A 5-page domain takes roughly 5 to 10 seconds, so 1,000 domains take about 10 to 20 minutes at the default settings.
Is this legal to use?
Reading public pages is generally allowed, but using the addresses for marketing is regulated. See Responsible use. This is not legal advice.
Related tools
- Work Email Finder: Find Email by Name & Domain (No SMTP): pattern-based likely work emails for named people.
- Phone Number Validation & Lookup: Format, Carrier, Line Type: check the phone numbers you extract.
- Company Enrichment API: Domain to Tech, Jobs & Socials: add tech stack, jobs and social profiles to the same domains.
- Google Sheets Import & Export: Apify Data, No Login: send the results to a Google Sheet.