The Mine Works
Scrape Business Emails, Phones and Social Profiles from Any Website
← All posts
tutorial June 30, 2026 · 3 min read

Scrape Business Emails, Phones and Social Profiles from Any Website

How to extract contact information from a list of company domains at scale — emails, phone numbers, LinkedIn, X, Instagram and more — with no API key.

Try the scraper

The actor referenced in this article. Pay only for results delivered.

View the scraper →

Finding the contact details for a list of target companies is genuinely tedious: open each website, hunt through the footer, check the /contact page, try to find LinkedIn. For ten companies that is ten minutes. For a thousand it is a week of grunt work.

The Website Contact Finder crawls each domain automatically — homepage, /contact, /about, /team, and footer-discovered links — and extracts every email address, phone number, and social profile link it finds. No API key, no browser required.

What It Extracts Per Domain

For each domain you supply, the actor returns:

  • emails — from mailto: links, regex extraction, and inline text. Junk addresses (no-reply, image hashes, framework artifacts) are filtered automatically.
  • phones — from tel: links and free-text regex, normalised and length-validated (7–15 digits, E.164 compliant).
  • socials — structured object with one URL per platform: linkedin, twitter, facebook, instagram, youtube. Only company/profile URLs are captured — share buttons and intent links are excluded.
  • pagesScanned — how many pages were crawled before the actor found or exhausted contacts.

Crawl a Domain List in Python

import os
from apify_client import ApifyClient

apify = ApifyClient(os.environ["APIFY_TOKEN"])

domains = [
    "stripe.com",
    "notion.so",
    "linear.app",
    "vercel.com",
    "cal.com",
]

run = apify.actor("themineworks/website-contact-finder").call(run_input={
    "domains": domains,
    "maxPagesPerSite": 5,
})

results = list(apify.dataset(run["defaultDatasetId"]).iterate_items())

for r in results:
    if r.get("_type") == "summary":
        continue
    print(f"\n{r['domain']}")
    print(f"  emails:  {', '.join(r.get('emails', [])[:3])}")
    print(f"  phones:  {', '.join(r.get('phones', [])[:2])}")
    socials = r.get("socials", {})
    for platform, url in socials.items():
        print(f"  {platform}: {url}")

Wire It Into a Claude Agent

The actor is available as an MCP tool. Add it to Claude Desktop:

{
  "mcpServers": {
    "contact-finder": {
      "command": "npx",
      "args": ["-y", "@apify/mcp-client"],
      "env": {
        "APIFY_TOKEN": "your-token-here",
        "MCP_ACTOR_URL": "https://mcp.apify.com/?tools=themineworks/website-contact-finder"
      }
    }
  }
}

Then you can paste a list of company websites into Claude and ask it to return a structured CSV of contact details. Claude calls the actor, formats the output, and flags any domains that returned no contacts.

A practical pattern: combine Website Contact Finder with the B2B Leads Finder for the same domain list. Contact Finder gives you the generic company contact info (and the LinkedIn company page URL); B2B Leads gives you individual person-level contacts at the same company. Together they give you both channels — the public-facing address and the named decision-maker.

What It Will and Will Not Find

It will find contacts that are linked from or visible on publicly accessible pages. Most B2B company sites have at least a hello@ or info@ address, a phone number in the footer, and a LinkedIn company page in the header.

It will not find contacts on:

  • Login-walled or member-only pages (the actor runs as an anonymous visitor)
  • JavaScript-heavy SPAs that render content only after complex user interactions (it uses plain HTTP, not a browser)
  • Cloudflare-protected sites that block non-browser user agents

For JavaScript-heavy sites pair it with RAG Crawler, which uses Playwright to render pages before extraction.

Pricing and Charging Logic

Each domain that returns at least one contact costs $0.004. Domains that crawl successfully but yield no contacts are never charged — you only pay for results you can actually use.

At scale: 1,000 domains with contacts = $4. For most sales prospecting workflows that is roughly the cost of one minute of a salesperson’s time.

Frequently Asked Questions

Why did some domains return no contacts?

Several reasons: the site may block non-browser requests (Cloudflare, Vercel’s bot protection), contact info may only appear on pages not reachable from the homepage without JavaScript, or the company genuinely does not publish contact details publicly. The domain still appears in output with empty arrays — it is not an error.

Does it follow redirects?

Yes. HTTP → HTTPS redirects and www → apex redirects are followed automatically (up to 5 hops). The crawler normalises the domain before crawling so http://www.stripe.com and stripe.com both resolve to the same root.

Can I supply full URLs instead of domains?

Yes. The actor normalises any URL string — it strips the protocol and www prefix, extracts the hostname, and crawls from there. https://www.stripe.com/enterprise becomes stripe.com internally.

Related Actor

Explore the scraper referenced in this article — see inputs, outputs, and pricing, then run it on Apify.