# Website Contact Details Extractor: Emails, Phones & Socials (`murch1k/website-contact-details-extractor`) Actor

Turn websites or domains into leads: emails, phones, LinkedIn, Facebook, Instagram, X, YouTube, TikTok, company name and address, one row per domain. Crawls contact/about/imprint pages, decodes hidden emails. Fast HTTP, no browser. Pay only for successful sites.

- **URL**: https://apify.com/murch1k/website-contact-details-extractor.md
- **Developed by:** [Murch1k](https://apify.com/murch1k) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 result scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Website Contact Details Extractor — Emails, Phones & Social Profiles from Any Website

Paste a list of websites or domains and get back **one clean lead row per company**: **emails, phone numbers, LinkedIn, Facebook, Instagram, X/Twitter, YouTube, TikTok, WhatsApp** and more, plus **company name, address and the contact page URL**.

The actor visits the homepage, finds the pages where contacts actually live (*Contact, About, Imprint/Impressum, Team, Support, Locations*, in 10+ languages) and merges everything into a single deduplicated record. It runs on plain HTTP with no headless browser, so it is fast and cheap: **hundreds of websites per minute**.

### Why this one

- **One row per domain.** Every website is a single row with all of its emails, phones and socials, not one row per page.
- **Pay per website, not per page.** Page-based contact scrapers usually crawl 5–10 pages per site, which works out to about $0.01–0.02 per website. Here you pay **$0.003 per website**, and **websites that fail are free**.
- **Finds hidden emails:** decodes **Cloudflare email protection** (`[email protected]`) and obfuscated addresses like `info [at] acme [dot] com`, and reads **schema.org / JSON-LD** business data.
- **Clean data:** filters junk such as `logo@2x.png`, `noreply@sentry.io`, placeholder emails, form-placeholder phone numbers, dates and registration numbers. Phones are normalised and deduplicated (`+1 800…` and `1-800…` count as one). Share buttons are not reported as social profiles.
- **Ranks the results:** `primaryEmail` prefers an on-domain role inbox (`info@`, `hello@`, `sales@`…), and `emailSources` tells you which page each email came from.

### Use cases

- Enrich **Google Maps / Yelp / directory exports** that have a website column but no email.
- Build **cold-outreach lists** from a list of company domains (CRM, LinkedIn Sales Navigator, Crunchbase, trade-show exhibitor lists).
- Find **social profiles** of competitors, suppliers or influencers' businesses.
- Clean and verify **contact data** in your CRM on a schedule.

### Input

```json
{
  "websites": ["apify.com", "https://www.joesstonecrab.com", "hubspot.com"],
  "maxPagesPerSite": 6,
  "sameDomainEmailsOnly": false,
  "includeFailedSites": true,
  "maxConcurrency": 40
}
```

| Option | Default | Notes |
|---|---|---|
| `websites` | — | Domains or URLs, one per line. Duplicate domains are processed once. |
| `maxPagesPerSite` | 6 | Homepage + up to 5 best contact-related pages. `1` = homepage only. |
| `sameDomainEmailsOnly` | `false` | Keep only emails on the website's own domain. |
| `includeFailedSites` | `true` | Add free `status: "failed"` rows with the reason (offline, 403, timeout…). |
| `maxResults` | 0 | Cost cap: stop after N successful websites. |
| `maxConcurrency` | 40 | Websites in parallel. |
| `requestTimeoutSecs` | 20 | Per page. |
| `proxyConfiguration` | off | Enable Apify Proxy if many of your sites block cloud servers. |

### Output

```json
{
  "website": "https://www.joesstonecrab.com",
  "domain": "joesstonecrab.com",
  "url": "https://www.joesstonecrab.com/",
  "status": "ok",
  "companyName": "Joe's Stone Crab",
  "title": "Joe's Stone Crab | Seafood Restaurant in Miami Beach, FL",
  "description": "Joe's Stone Crab is a Miami Beach institution since 1913…",
  "language": "en-US",
  "address": null,
  "primaryEmail": "info@joesstonecrab.com",
  "primaryPhone": "3056734611",
  "emails": ["info@joesstonecrab.com"],
  "phones": ["3056734611", "3056730365", "3056739035"],
  "emailSources": { "info@joesstonecrab.com": "https://www.joesstonecrab.com/location/joes-stone-crab/" },
  "linkedin": null,
  "facebook": "https://facebook.com/JoesStoneCrab",
  "instagram": "https://instagram.com/joesstonecrab",
  "twitter": null,
  "youtube": null,
  "tiktok": "https://tiktok.com/@joesstonecrab_",
  "socials": {
    "facebook": ["https://facebook.com/JoesStoneCrab", "https://facebook.com/people/Joes-Take-Away/61559644092931"],
    "instagram": ["https://instagram.com/joesstonecrab", "https://instagram.com/joestakeaway__"],
    "tiktok": ["https://tiktok.com/@joesstonecrab_"]
  },
  "contactPageUrl": "https://www.joesstonecrab.com/contact/",
  "pagesScraped": 5,
  "scrapedAt": "2026-10-13T16:27:20.297Z"
}
```

`socials` can also contain `pinterest`, `github`, `telegram`, `whatsapp`, `threads`, `discord` and `yelp`. The flat `linkedin`/`facebook`/… columns make CSV and Excel exports easy to use.

A website that could not be scraped:

```json
{ "website": "old-shop.com", "domain": "old-shop.com", "status": "failed", "error": "HTTP 403 (blocked — try enabling a proxy)", "httpStatus": 403, "emails": [], "phones": [] }
```

### Use with AI agents (MCP), LangChain, RAG & the API

This actor is a ready-made **tool for AI agents**: an LLM can call it, wait for the run and read clean JSON back.

**MCP server (Claude Desktop, Claude Code, Cursor, VS Code, any MCP client)** — add Apify's hosted MCP server with this actor enabled as a tool:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=murch1k/website-contact-details-extractor",
      "headers": { "Authorization": "Bearer <APIFY_TOKEN>" }
    }
  }
}
```

**LangChain / LangGraph** (`pip install langchain-apify`, set `APIFY_API_TOKEN`):

```python
import json
from langchain_apify import ApifyActorsTool, ApifyWrapper
from langchain_core.documents import Document

## 1) give the actor to an agent as a tool
tool = ApifyActorsTool("murch1k/website-contact-details-extractor")

## 2) or load results as Documents for a RAG index
loader = ApifyWrapper().call_actor(
    actor_id="murch1k/website-contact-details-extractor",
    run_input={"websites": ["apify.com", "https://www.joesstonecrab.com", "hubspot.com"], "maxPagesPerSite": 6, "sameDomainEmailsOnly": False, "includeFailedSites": True, "maxConcurrency": 40},
    dataset_mapping_function=lambda item: Document(page_content=json.dumps(item, ensure_ascii=False), metadata={"url": item.get("url")}),
)
docs = loader.load()
```

**REST API — one synchronous call, dataset items in the response:**

```bash
curl -X POST "https://api.apify.com/v2/acts/murch1k~website-contact-details-extractor/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"websites": ["apify.com", "https://www.joesstonecrab.com", "hubspot.com"], "maxPagesPerSite": 6, "sameDomainEmailsOnly": false, "includeFailedSites": true, "maxConcurrency": 40}'
```

Also works with the Apify Python/JS clients, **Make, Zapier, n8n**, Google Sheets, webhooks and schedules. Export as JSON, CSV, Excel, XML or RSS.

**RAG tip:** An agent can enrich a lead list on the fly: send the domains, read `primaryEmail`, `phones` and `socials` from the rows and write them back to your CRM.

### Pricing

**$3.00 per 1,000 websites** ($0.003 per website with `status: "ok"`). All pages crawled on a site are included. **Failed websites are never charged.**

| Example | Cost |
|---|---|
| 500 restaurant websites from a Google Maps export | $1.50 |
| 10,000 company domains from a CRM | $30.00 |

Set **Max results** to cap the cost of any run. The actor also stops by itself when your spending limit is reached.

### Speed

Benchmark on the Apify platform: **300 real company websites (≈1,330 pages) in 77 seconds** with the default 2 GB of memory, or about 230 websites per minute. Every website is a different server, so you can safely raise `maxConcurrency` (and memory) for big lists.

### Tips

- **Phone numbers** are returned in the format the site uses, cleaned to digits with an optional leading `+`. Numbers without a country code are local to the website's country.
- **Sites that need JavaScript** for their menus are still covered: if no contact links are found in the HTML, the actor tries the usual `/contact`, `/contact-us`, `/about` and `/impressum` paths.
- **Blocked sites (403)**: a few websites block all cloud servers. Enable Apify Proxy and re-run only the failed rows. They don't cost anything.

### FAQ

**Do I pay per page or per website?**
Per website. All pages crawled on a site are included in one $0.003 result, and websites that fail cost nothing.

**Can it find emails hidden behind Cloudflare email protection?**
Yes. `[email protected]` links and obfuscated addresses like `info [at] acme [dot] com` are decoded automatically.

**Where do I get the list of websites?**
Any CSV export works: a CRM, a Google Maps scraper, a directory. Paste the domains or URLs into `websites`.

**Is it an alternative to Hunter.io or Snov.io?**
For company contact pages, yes: it reads what the website itself publishes (contact, about, imprint pages) instead of guessing addresses.

### Legal

The actor only collects information that the websites publish themselves. Personal data (e.g. named employee emails) is protected by laws such as GDPR and CAN-SPAM in many jurisdictions. Make sure you have a legitimate reason to process it and that your outreach complies with those laws.

### Support

Missing a field, or a site that should work but doesn't? Open an issue on the **Issues** tab with the domain, and fixes usually ship within days.

# Actor input Schema

## `websites` (type: `array`):

One per line: <code>acme.com</code>, <code>www.acme.co.uk</code> or a full URL. Duplicates of the same domain are processed once. Paste thousands at once — e.g. the <code>website</code> column from a Google Maps or LinkedIn export.

## `maxPagesPerSite` (type: `integer`):

Homepage + the most promising internal pages (contact, about, imprint, team, support, locations…). 4–8 finds almost everything; 1 = homepage only (fastest).

## `sameDomainEmailsOnly` (type: `boolean`):

Drop emails on other domains (e.g. gmail.com, agency or partner addresses).

## `includeFailedSites` (type: `boolean`):

Add a row with <code>status: "failed"</code> and the reason for websites that are offline or block bots. These rows are free.

## `maxResults` (type: `integer`):

Stop after this many successfully scraped websites. <code>0</code> = no limit.

## `maxConcurrency` (type: `integer`):

Websites processed in parallel. Every website is a different server, so high values are safe.

## `requestTimeoutSecs` (type: `integer`):

Give up on a page after this long. Slow small-business hosting sometimes needs 30+.

## `proxyConfiguration` (type: `object`):

Not needed for most websites. Enable Apify Proxy if many of your sites answer 403 to cloud servers.

## Actor input object example

```json
{
  "websites": [
    "apify.com",
    "https://www.joesstonecrab.com",
    "hubspot.com"
  ],
  "maxPagesPerSite": 6,
  "sameDomainEmailsOnly": false,
  "includeFailedSites": true,
  "maxResults": 0,
  "maxConcurrency": 40,
  "requestTimeoutSecs": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `contacts` (type: `string`):

No description

## `runStats` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "websites": [
        "apify.com",
        "https://www.joesstonecrab.com",
        "hubspot.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("murch1k/website-contact-details-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "websites": [
        "apify.com",
        "https://www.joesstonecrab.com",
        "hubspot.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("murch1k/website-contact-details-extractor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "websites": [
    "apify.com",
    "https://www.joesstonecrab.com",
    "hubspot.com"
  ]
}' |
apify call murch1k/website-contact-details-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,murch1k/website-contact-details-extractor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RWtxSfCJ4kuCBEJ5a/builds/ZEsQca37Gaz5nMim6/openapi.json
