# Website Email & Contact Extractor (`darknezz/website-contact-extractor`) Actor

Extract emails, phone numbers and social profile links from any list of websites. Crawls contact, about and team pages, decodes obfuscated and Cloudflare-protected emails. Perfect for B2B lead generation and CRM enrichment.

- **URL**: https://apify.com/darknezz/website-contact-extractor.md
- **Developed by:** [Oaida Adrian](https://apify.com/darknezz) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 4 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 website processeds

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 Email & Contact Extractor

Extract **emails, phone numbers and social profile links** from any list of websites — built for B2B lead generation, sales prospecting and CRM enrichment. Handles redirects, prioritises contact pages, decodes obfuscated and Cloudflare-protected emails, and returns one clean JSON row per website.

### Why this Actor

A spreadsheet full of company domains is worth little until you know who to call and where to write. This Actor turns a raw domain list into a ready-to-import contact sheet: verified inboxes, phone numbers, and the LinkedIn/Facebook/Twitter profiles of the companies you want to reach. No proxy configuration, no API keys, no login — give it URLs, get structured contacts back.

### What it does

For every website you provide, the Actor:

1. Crawls the homepage, then **prioritises contact, about, team, support, impressum and legal pages** (up to `maxPagesPerSite` pages, same domain only).
2. Extracts **email addresses** from plain text, `mailto:` links, common obfuscations (`name [at] domain [dot] com`) and **Cloudflare-protected emails** (`data-cfemail` decoding).
3. Extracts **phone numbers** from `tel:` links plus international (`+40 …`) and US (`(555) 123-4567`) text formats.
4. Extracts **social profile links** — Facebook, Twitter/X, Instagram, LinkedIn, YouTube, TikTok, GitHub — with per-platform columns for easy spreadsheet export.
5. Outputs **one structured JSON item per website**, with junk emails (image filenames, placeholders, no-reply) filtered out.

### Input

```json
{
  "websites": ["https://example.com", "another-site.com"],
  "maxPagesPerSite": 10,
  "includeSocialLinks": true
}
```

| Option | Description |
|--------|-------------|
| `websites` | List of website URLs or bare domains (required). |
| `maxPagesPerSite` | Max pages to crawl per site (default 10, max 50). Contact/about/team pages are visited first. |
| `includeSocialLinks` | Whether to extract social profile links (default true). |

### Output (one item per website)

```json
{
  "url": "https://example.com",
  "domain": "example.com",
  "pagesCrawled": 10,
  "emails": ["hello@example.com", "sales@example.com"],
  "phones": ["+1 (555) 123-4567"],
  "contactPages": ["https://example.com/contact"],
  "linkedin": "https://linkedin.com/company/example",
  "facebook": "https://facebook.com/example",
  "socialLinks": ["https://facebook.com/example", "https://linkedin.com/company/example"]
}
```

Export to JSON, CSV or Excel in the Apify console, or pull the dataset with the API. One row per website — the per-platform social columns (`linkedin`, `facebook`, `twitter`, `instagram`, `youtube`, `tiktok`, `github`) drop straight into a CRM import template.

### Use cases in detail

- **B2B lead generation** — turn a list of company domains (from a directory, a competitor's customer page, or a Google Sheets export) into a ready-to-import contact list.
- **CRM enrichment** — fill missing email/phone/social columns for accounts you already track; run it nightly on new sign-ups.
- **Outreach prep** — find the correct contact/impressum page and the right inbox before a cold campaign, instead of guessing `info@`.
- **Directory & dataset building** — enrich business listings, marketplace vendors or conference exhibitor lists with verified contact channels.
- **Recruiting & partnerships** — pull team-page and social links to reach the right person directly.

### Run on a schedule or via API

Point an Apify **Schedule** at a fresh batch of domains each day, or trigger the Actor from your own backend and read the results straight into your CRM:

```bash
curl -X POST "https://api.apify.com/v2/acts/darknezz~website-contact-extractor/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"websites":["https://astral.sh","https://www.python.org"],"maxPagesPerSite":10}'
```

From Python:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("darknezz~website-contact-extractor").call(
    run_input={"websites": ["https://astral.sh", "https://www.python.org"], "maxPagesPerSite": 10},
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["domain"], item["emails"])
```

Each run's dataset exports cleanly to JSON, CSV or Excel — one row per website with per-platform social columns for spreadsheet use.

### Worked example (real output)

Running on `https://www.python.org` and `https://astral.sh` (default 10 pages/site) returns:

```json
[
  {
    "url": "https://www.python.org",
    "domain": "python.org",
    "pagesCrawled": 10,
    "emails": ["jobs@python.org", "legal@python.org", "psf@python.org", "python-announce@python.org", "webmaster@python.org"],
    "phones": null,
    "contactPages": ["https://www.python.org/about/help/", "https://www.python.org/about/legal/", "https://www.python.org/jobs/"],
    "twitter": "https://twitter.com/ThePSF",
    "linkedin": "https://www.linkedin.com/company/python-software-foundation",
    "github": "https://github.com/python"
  },
  {
    "url": "https://astral.sh",
    "domain": "astral.sh",
    "pagesCrawled": 10,
    "emails": ["hey@astral.sh"],
    "phones": null,
    "contactPages": ["https://astral.sh/legal/privacy"],
    "twitter": "https://twitter.com/astral_sh",
    "github": "https://github.com/astral-sh"
  }
]
```

The first run found five public Python.org inboxes plus its social profiles; the second surfaced Astral's single contact address and GitHub — enough to enrich a CRM row or start an outreach thread.

### Pricing

Pay per event: **$0.005 per website processed** (`website-processed` primary event) plus a **$0.01 per-run start fee** — charged once per website regardless of how many pages are crawled or contacts found, so cost scales with your input list, not the site's size. Enriching 200 domains costs about $1.00.

### FAQ

**Does it work on JavaScript-heavy sites?** Contacts rendered server-side (the vast majority) are found, including Cloudflare-obfuscated emails. Contacts injected purely client-side after render are not.

**How many pages per site does it crawl?** Up to `maxPagesPerSite` (default 10, max 50), and it visits contact/about/team/support/impressum/legal pages first so the useful data is found early.

**Does it need a proxy or API key?** No — it crawls the sites you provide directly, no proxy or credentials required.

**How do you avoid junk emails?** Image filenames, placeholder addresses (`example.com`, `yourdomain`) and common `no-reply` inboxes are filtered out before output.

**What if a site is down or times out?** The item is still returned with an `error` field describing what happened, so a partial run never silently drops rows.

**Can I crawl more than 50 pages per site?** Not currently — contact data virtually always lives on the first few pages, so the cap keeps runs fast and cheap. Raise a GitHub issue if you need a higher ceiling.

**Is scraping contact data legal?** The Actor only reads publicly displayed information. You are responsible for complying with GDPR/CAN-SPAM when using extracted data for outreach.

### Limitations

- **No JavaScript rendering** — contacts injected purely client-side after page load are not found. Server-rendered contacts (the vast majority, including Cloudflare-obfuscated emails) are.
- **Same-domain crawl only** — the Actor stays on the site's own domain; it will not follow links to external sites to chase a contact.
- **Best-effort dedup** — the same address can appear on several crawled pages; results are de-duplicated per website, but obfuscated and plain variants of the same address are treated as separate strings.
- **No phone validation** — phones come from `tel:` links and text patterns, so malformed or placeholder numbers may pass through; use the output as a starting point, not a verified directory.

# Actor input Schema

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

List of website URLs to extract contacts from (e.g. https://example.com). Bare domains work too.

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

How many pages to crawl per website. Contact, about and team pages are visited first.

## `includeSocialLinks` (type: `boolean`):

Also extract Facebook, Twitter/X, Instagram, LinkedIn, YouTube, TikTok and GitHub profile links.

## `timeoutSecs` (type: `integer`):

Per-page request timeout in seconds.

## Actor input object example

```json
{
  "websites": [
    "https://www.python.org",
    "https://astral.sh"
  ],
  "maxPagesPerSite": 10,
  "includeSocialLinks": true,
  "timeoutSecs": 30
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `url` (type: `string`):

No description

## `finalUrl` (type: `string`):

No description

## `domain` (type: `string`):

No description

## `pagesCrawled` (type: `string`):

No description

## `emails` (type: `string`):

No description

## `phones` (type: `string`):

No description

## `facebook` (type: `string`):

No description

## `twitter` (type: `string`):

No description

## `instagram` (type: `string`):

No description

## `linkedin` (type: `string`):

No description

## `youtube` (type: `string`):

No description

## `github` (type: `string`):

No description

## `error` (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": [
        "https://www.python.org",
        "https://astral.sh"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("darknezz/website-contact-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": [
        "https://www.python.org",
        "https://astral.sh",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("darknezz/website-contact-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": [
    "https://www.python.org",
    "https://astral.sh"
  ]
}' |
apify call darknezz/website-contact-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,darknezz/website-contact-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/29s7J7qFPbL5dWe69/builds/kWvCLjO3tkkrwoc1X/openapi.json
