# Website Contact Extractor - Emails, Phones & Social Profiles (`clearfetch/website-contact-extractor`) Actor

Extract business contact details from any website: email addresses, phone numbers in E.164 format, social profiles, postal addresses and the company name. Follows the site's own contact, about and imprint pages. No proxy, no login.

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

## Pricing

from $4.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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Website Contact Extractor - Emails, Phones & Social Profiles

Give this Actor a list of websites and it returns the business contact details behind each one: email addresses,
phone numbers normalised to E.164, social profiles, postal addresses and the company name. It does not just read
the page you give it. It finds the site's own contact, imprint, about and team pages and reads those too, which
is where the real address usually lives. No login, no API key and no proxy. **$0.004 per website**, and sites it
cannot reach are free.

### What data you get

- **Emails**, including ones written to defeat scrapers such as `info [at] example [dot] com` or `&#64;`
  entities, with the source recorded (mailto link, page text, data attribute) and the pages each was found on.
- **Phone numbers in E.164** with the country and the line type where the format allows it, so mobile and
  landline are distinguishable. Local formats are resolved using the site's own country.
- **Social profiles** for Facebook, Instagram, LinkedIn, X, YouTube, TikTok, GitHub, Pinterest, Threads,
  Telegram, WhatsApp, Discord, Reddit and Vimeo, with the handle pulled out. Share and intent links are ignored.
- **Postal addresses** from schema.org data, structured into street, locality, region, postcode and country,
  plus raw text from address tags.
- **Company name**, taken from schema.org Organization data, the og:site\_name tag, the page title or the domain,
  in that order, with the source recorded so you know how much to trust it.
- **`primaryEmail` and `primaryPhone`**, the single best of each, preferring details found on a contact or
  imprint page over ones in a footer. Handy for a CRM import where one value per company is all you want.

### How to use

1. Paste domains or URLs into **Websites**, one per line. Bare domains are fine.
2. Leave **Pages per website** at 5, or lower it to 1 to read only the exact URL you gave.
3. Run it. Each website is one row, exportable as JSON, CSV or Excel, or readable from the API.

### Input

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `urls` | array | — | Domains or URLs. Also accepts `url` and `startUrls` for compatibility with other Actors. |
| `maxPagesPerSite` | integer | `5` | Pages to read per website: the one you gave, plus its most promising contact, imprint, about and team pages. |
| `includeEmails` | boolean | `true` | Extract email addresses. |
| `includePhones` | boolean | `true` | Extract and normalise phone numbers. |
| `includeSocials` | boolean | `true` | Extract social profile links. |
| `includeAddresses` | boolean | `true` | Extract postal addresses. |
| `maxConcurrency` | integer | `10` | Websites processed in parallel (1-50). |
| `timeoutSecs` | integer | `20` | Per-page timeout. |
| `proxyConfiguration` | object | off | Optional. Not needed for most sites. |

### Output example

One website, trimmed to the first address, three phones and four social profiles:

```json
{
  "url": "https://www.zalando.de/",
  "finalUrl": "https://en.zalando.de/?_rfl=de",
  "ok": true,
  "statusCode": 200,
  "company": "Zalando",
  "companySource": "title",
  "emails": [
    {
      "email": "authorities-dsa@zalando.de",
      "sources": [
        "mailto",
        "text"
      ],
      "foundOn": [
        "https://en.zalando.de/legal-notice"
      ]
    },
    {
      "email": "legalnotice@zalando.de",
      "sources": [
        "text"
      ],
      "foundOn": [
        "https://en.zalando.de/legal-notice"
      ]
    }
  ],
  "phones": [
    {
      "phone": "+447428390555",
      "national": "07428 390555",
      "country": "GB",
      "type": "MOBILE",
      "sources": [
        "text"
      ],
      "foundOn": [
        "https://en.zalando.de/?_rfl=de",
        "https://en.zalando.de/faq",
        "https://en.zalando.de/legal-notice",
        "https://en.zalando.de/faq/what-should-i-know-about-the-newsletter.html"
      ]
    },
    {
      "phone": "+442398169220",
      "national": "023 9816 9220",
      "country": "GB",
      "type": "FIXED_LINE",
      "sources": [
        "text"
      ],
      "foundOn": [
        "https://en.zalando.de/?_rfl=de",
        "https://en.zalando.de/faq",
        "https://en.zalando.de/legal-notice",
        "https://en.zalando.de/faq/what-should-i-know-about-the-newsletter.html"
      ]
    },
    {
      "phone": "+447899149931",
      "national": "07899 149931",
      "country": "GB",
      "type": "MOBILE",
      "sources": [
        "text"
      ],
      "foundOn": [
        "https://en.zalando.de/?_rfl=de",
        "https://en.zalando.de/faq",
        "https://en.zalando.de/legal-notice",
        "https://en.zalando.de/faq/what-should-i-know-about-the-newsletter.html"
      ]
    }
  ],
  "socials": [
    {
      "platform": "facebook",
      "url": "https://www.facebook.com/Zalando",
      "handle": "Zalando"
    },
    {
      "platform": "instagram",
      "url": "https://instagram.com/zalando",
      "handle": "zalando"
    },
    {
      "platform": "pinterest",
      "url": "https://www.pinterest.com/zalando",
      "handle": "zalando"
    },
    {
      "platform": "tiktok",
      "url": "https://www.tiktok.com/@zalando",
      "handle": "@zalando"
    }
  ],
  "addresses": [],
  "primaryEmail": "authorities-dsa@zalando.de",
  "primaryPhone": "+447428390555",
  "counts": {
    "emails": 2,
    "phones": 4,
    "socials": 4,
    "addresses": 0
  },
  "pagesCrawled": [
    "https://en.zalando.de/?_rfl=de",
    "https://en.zalando.de/faq",
    "https://en.zalando.de/legal-notice",
    "https://en.zalando.de/faq/what-should-i-know-about-the-newsletter.html"
  ],
  "elapsedMs": 2596,
  "scrapedAt": "2026-09-05T17:42:04.630Z"
}
```

A website that cannot be reached is reported and costs nothing:

```json
{
  "url": "https://this-domain-does-not-exist-12345.com/",
  "ok": false,
  "statusCode": null,
  "error": "getaddrinfo ENOTFOUND this-domain-does-not-exist-12345.com",
  "errorCode": "ENOTFOUND",
  "elapsedMs": 1122,
  "scrapedAt": "2026-09-05T17:42:03.157Z"
}
```

### Pricing

**$0.004 per website**, whatever number of pages it takes to read. 1,000 websites is $4. Websites that fail are
free. No subscription and no API key; it runs on the Apify free plan.

### What it filters out, and why that matters

Contact scrapers are judged on their junk rate, so this one is deliberately strict:

- Emails must sit on a real, ICANN-recognised domain, which throws out addresses glued to the following word
  such as `hello@example.comt`, as well as asset filenames like `logo@2x.png`.
- Placeholder and vendor addresses are dropped: `noreply@`, `user@example.com`, Sentry ingest keys,
  `@wixpress.com`, `@squarespace.com` and similar.
- Numbers found in prose must look like written phone numbers, so VAT, registration and order numbers are not
  reported as contacts.
- Dial-pattern placeholders such as `+33 1 00 00 00 00`, which some sales pages publish, are rejected.
- Social share and intent URLs are not profiles, so `facebook.com/sharer`, `twitter.com/intent` and
  `linkedin.com/shareArticle` never appear.

### Use cases

- **Lead generation**: turn a list of domains from any source into a contact sheet with one email and one phone
  per company.
- **CRM enrichment**: fill in missing contact details for accounts you already have.
- **Sales prospecting**: pull the company's LinkedIn and other profiles alongside the email.
- **Compliance and due diligence**: collect imprint and legal-notice details, which European sites are required
  to publish.
- **Recruiting and partnerships**: find the team or contact page address rather than a generic info@ box.
- **AI agents**: give an assistant a tool that answers "how do I contact this company".

### Integrations

```bash
curl -X POST "https://api.apify.com/v2/acts/clearfetch~website-contact-extractor/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["stripe.com", "basecamp.com"], "maxPagesPerSite": 5}'
```

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("clearfetch/website-contact-extractor").call(run_input={"urls": ["stripe.com"]})
for site in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(site["company"], site["primaryEmail"], site["primaryPhone"])
```

Works with the Apify integrations for n8n, Make, Zapier, Google Sheets, Slack and webhooks, with scheduled runs,
and with AI agents through the Apify MCP server.

### FAQ

**Do I need proxies?** No. Pages are fetched with ordinary browser-like requests. A proxy input exists for sites
that block datacenter traffic.

**Why does it read more than one page?** Because home pages rarely carry the real contact details. The Actor
follows the site's own links whose text or path looks like contact, imprint, about, team or legal, ranked so an
imprint or contact page is read before an about page. You are charged once per website regardless.

**Does it execute JavaScript?** No. Details rendered only by client-side JavaScript, such as an email revealed
after a click, will be missed. That keeps runs fast and cheap for the large majority of sites that do not need it.

**Is this legal?** It reads pages exactly as a browser would, with no login. Business contact details published
on a company's own website are public. How you use them is your responsibility: in the EU and UK, sending
marketing email to those addresses is governed by GDPR and the ePrivacy rules, and this Actor is not a
substitute for a lawful basis or for honouring opt-outs.

### Changelog

- **1.0.0** (2026-09) — first release: emails with de-obfuscation, phones in E.164 with line type, social
  profiles with handles, schema.org and text addresses, company name, and automatic discovery of a site's
  contact and imprint pages.

# Actor input Schema

## `urls` (type: `array`):

Domains or URLs to extract contacts from, one per line. Bare domains are fine. Also accepts "url" or "startUrls" for compatibility with other Actors.

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

How many pages to read per website. The first is the URL you gave; the rest are the site's own contact, imprint, about and team pages, chosen by how likely they are to hold contact details. 1 reads only the page you gave.

## `includeEmails` (type: `boolean`):

Extract email addresses, including ones written as "name \[at] example \[dot] com".

## `includePhones` (type: `boolean`):

Extract phone numbers and normalise them to E.164, using the site's country as a hint for local formats.

## `includeSocials` (type: `boolean`):

Extract profile links for Facebook, Instagram, LinkedIn, X, YouTube, TikTok, GitHub, Pinterest, Threads, Telegram, WhatsApp and more. Share and intent links are ignored.

## `includeAddresses` (type: `boolean`):

Extract postal addresses from schema.org data and address tags.

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

Websites processed in parallel.

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

Give up on a single page after this many seconds.

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

Optional. Most sites answer plain datacenter requests, so no proxy is needed in normal use.

## Actor input object example

```json
{
  "urls": [
    "apify.com",
    "stripe.com"
  ],
  "maxPagesPerSite": 5,
  "includeEmails": true,
  "includePhones": true,
  "includeSocials": true,
  "includeAddresses": true,
  "maxConcurrency": 10,
  "timeoutSecs": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per website: company name, emails, phone numbers in E.164 with country and line type, social profiles by platform, postal addresses, and which pages each detail was found on. Websites that cannot be reached appear with ok=false and are not charged.

# 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 = {
    "urls": [
        "apify.com",
        "stripe.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("clearfetch/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 = { "urls": [
        "apify.com",
        "stripe.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("clearfetch/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 '{
  "urls": [
    "apify.com",
    "stripe.com"
  ]
}' |
apify call clearfetch/website-contact-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,clearfetch/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/jaWWMAndDhqpiDyuf/builds/3pM9HajxQm9YOncRn/openapi.json
