How do I find a company's contact email, phone and social profiles from its domain?
Short answer: fetch the company's homepage plus its contact, about and imprint pages (respecting robots.txt), extract mailto:/tel: links, JSON-LD Organization data, obfuscated emails and social links, then validate the emails' domain for MX records. The Fairquery Website Contact & Company Enricher does all of that per domain and returns one clean row (role emails, E.164 phones, socials, company name, description, address) for $0.003 per domain; unreachable, blocked or invalid domains are free.
What you get per domain
- Business emails, validated with the same code as the Fairquery Email Validator: syntax, DNS MX / null MX, disposable list, free-provider and typo checks (no SMTP probing). By default only role/generic inboxes (
info@,sales@,hello@) are returned. - Phone numbers normalised to E.164, with the page they came from.
- Social profiles: company LinkedIn, X/Twitter, GitHub, Facebook, Instagram, YouTube, TikTok and so on. Personal LinkedIn profiles (
/in/...) are never returned. - Company name, description and postal address from JSON-LD,
og:site_name,<address>blocks and imprint pages. - Mail domain facts: MX, null MX, mail provider (for example Google Workspace or Microsoft 365), optional SPF/DMARC.
How it works
- Normalises each input (
https://www.Acme.com/contact,jane@acme.com,acme.com→acme.com) and removes duplicates. - Reads
robots.txt(RFC 9309) and honoursDisallowandCrawl-delayfor user agentFairqueryBot. - Fetches the homepage, then the best-scoring same-site pages (contact, Kontakt, contacto, about, imprint/Impressum, legal notice, team) up to
maxPagesPerDomain(default 5, max 15), one request at a time per site withrequestDelayMs(default 1,000 ms) between them. - Extracts JSON-LD,
mailto:/tel:links, Cloudflare-protected emails,name [at] domain [dot] comobfuscation, social links and addresses, then validates the emails.
It is plain HTTP, with no headless browser and no proxy, so sites that render contact details only with JavaScript or block datacenter IPs return fewer fields.
How to run it with curl
curl -X POST \
"https://api.apify.com/v2/acts/fairquery~website-contact-company-enricher/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"domains": ["apify.com"], "maxPagesPerDomain": 4}'
Real output from that request
We ran exactly this on October 17, 2026 (row shown in full, minus the timestamp and the duplicate addresses array):
{
"type": "domain",
"input": "apify.com",
"domain": "apify.com",
"final_url": "https://apify.com/",
"company_name": "Apify Technologies s.r.o.",
"description": "Thousands of tools to automate your business. Get real-time web data, track competitors, generate leads, and integrate your apps and AI agents.",
"emails": [
{
"email": "hello@apify.com",
"source_url": "https://apify.com/contact",
"is_role_account": true,
"on_company_domain": true,
"is_free_provider": false,
"is_disposable": false,
"verdict": "valid",
"reasons": [
"ROLE_ACCOUNT"
],
"has_mx": true,
"mail_provider": "Google Workspace / Gmail"
}
],
"primary_email": "hello@apify.com",
"phones": [],
"social_links": {
"github": [
"https://github.com/apify"
],
"linkedin": [
"https://linkedin.com/company/apify"
],
"twitter": [
"https://x.com/apify"
],
"tiktok": [
"https://tiktok.com/@apifytech",
"https://tiktok.com/@apifyoffice"
]
},
"address": "Na Příkopě 959/27, 11000, Prague, CZ",
"mail_domain": {
"has_mx": true,
"null_mx": false,
"mail_provider": "Google Workspace / Gmail",
"has_spf": null,
"has_dmarc": null,
"dmarc_policy": null
},
"pages_crawled": [
"https://apify.com/",
"https://apify.com/contact",
"https://apify.com/contact-sales"
],
"pages_blocked_by_robots": 0,
"robots_txt": "ok",
"email_scope": "role"
}
The run crawled 3 pages, took 5.1 seconds and would cost $0.003. The README documents about 3–8 seconds per domain with the default politeness settings and 5 domains in parallel, so 100 domains take roughly 1–3 minutes. No phone number was published on the crawled pages here, so phones is empty rather than guessed.
Python: enrich a CSV of company websites
import csv, os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
domains = [row["website"] for row in csv.DictReader(open("companies.csv"))]
run = client.actor("fairquery/website-contact-company-enricher").call(
run_input={"domains": domains, "emailScope": "role", "defaultPhoneCountry": "US"}
)
for r in client.dataset(run["defaultDatasetId"]).iterate_items():
if r["type"] == "domain":
print(r["domain"], r["primary_email"], [p["e164"] for p in r["phones"]],
r["social_links"].get("linkedin"))
else:
print("skipped:", r.get("code"), r.get("message"))
Input options
| Field | Default | Meaning |
|---|---|---|
domains | (required) | Domains, URLs or emails |
maxPagesPerDomain | 5 | 1–15, homepage included |
emailScope | role | business adds named addresses on the company's own domain; all returns everything found |
validateEmails | true | MX / disposable / typo checks |
checkSpfDmarc | false | SPF/DMARC for the company mail domain |
defaultPhoneCountry | – | e.g. US; also parses national-format numbers in page text |
domainConcurrency / requestDelayMs / requestTimeoutSecs | 5 / 1000 / 15 | Politeness and timeouts |
maxDomains | 1000 | Safety cap per run |
Error rows (never charged): INPUT_EMPTY, INVALID_DOMAIN, MAX_DOMAINS_EXCEEDED, SITE_UNREACHABLE, BLOCKED_BY_ROBOTS, ENRICH_FAILED.
From an AI agent
Call Actor fairquery/website-contact-company-enricher through Apify MCP, or run the stdio MCP server from the GitHub repo. It has enrich_domains (paid, your Apify token) and a free local normalize_domains tool for cleaning a messy list first. Real output of normalize_domains for ["https://www.Apify.com/contact", "jane@stripe.com", "basecamp.com", "apify.com", "not a domain"]:
{
"domains": ["apify.com", "stripe.com", "basecamp.com"],
"invalid": ["not a domain"],
"duplicates_removed": 1
}
Pricing
$0.003 per domain enriched (= $3 per 1,000 domains) on Apify, pay per event, plus Apify's $0.00005 Actor-start event. Only domains that return a result row are charged; unreachable, robots-blocked and invalid domains are free.
How it compares with alternatives
| Option | Good for | Trade-offs |
|---|---|---|
| Doing it by hand | A handful of companies | Slow; easy to miss imprint pages and obfuscated emails |
| Writing your own scraper | Full control | robots.txt handling, page discovery, email de-obfuscation, phone parsing and email validation to build and maintain |
| B2B contact databases (for example Hunter, Apollo, ZoomInfo) | Finding named people, job titles and personal work emails from large pre-built databases | Subscription pricing; data comes from their database rather than a live read of the company's site |
| Fairquery Contact Enricher | Live, per-domain company contact data with source URLs and validated emails, pay per domain | Only what the company publishes on its own site; role inboxes by default, no person search; JavaScript-only sites yield less |
FAQ
How can I get a company's contact email from its website domain?
Crawl the homepage and its contact, about and imprint pages, extract mailto links, JSON-LD and obfuscated emails, and validate the domain's MX records. The Fairquery Website Contact & Company Enricher does this per domain for $0.003 and returns validated role emails with the page they were found on.
Does it find personal email addresses of employees?
No. By default it returns only role/generic inboxes such as info@, sales@ or hello@ (emailScope 'role'). 'business' adds named addresses published on the company's own domain. It never returns personal LinkedIn profiles and does not search for people.
Does it respect robots.txt?
Yes. It reads robots.txt (RFC 9309), honours Disallow and Crawl-delay for user agent FairqueryBot, makes one request at a time per site with a 1 second default delay, and reports pages_blocked_by_robots.
How fast is it?
About 3-8 seconds per domain with the default settings and 5 domains in parallel, so 100 domains take roughly 1-3 minutes. Our single-domain test run took 5.1 seconds.
What does it cost?
$0.003 per domain enriched on Apify. Unreachable, robots-blocked and invalid domains are free.
Why are some fields empty?
It only returns what the company publishes on the crawled pages. Sites that render contacts with JavaScript only, or block datacenter IPs, return fewer fields, because it uses plain HTTP without a browser or proxy.
Use responsibly: business contact data can still be personal data under GDPR/UK GDPR. Have a lawful basis, honour opt-outs, and follow anti-spam law (CAN-SPAM, ePrivacy/PECR) when you contact anyone. DNS checks cannot prove a mailbox exists.
Source and docs: github.com/fairquery/website-contact-company-enricher (MIT) · Apify Store · all Fairquery tools