# Website Contact Extractor - Emails & Phones (`aolmo/contact-extractor`) Actor

Extracts emails, phone numbers and social profiles from any website by crawling its contact, about and legal pages. Validates email domains via DNS. Plain HTTP, no browser: fast, and you pay only for websites where contacts were found.

- **URL**: https://apify.com/aolmo/contact-extractor.md
- **Developed by:** [Antonio del Olmo Tena](https://apify.com/aolmo) (community)
- **Categories:** Lead generation, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 contacts founds

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

Give it a list of websites and get back the emails, phone numbers and social profiles published on each one. The Actor crawls the home page and the pages where contact details usually live (contact, about, team, legal, imprint, support) on the same domain, extracts every contact it finds, validates the email domains via DNS and returns one clean, deduplicated record per website.

You pay only for websites where at least one contact was found. No browser, no proxies, no CAPTCHA tricks: plain HTTP requests, fast and cheap.

### What you get

One Dataset item per website with:

- `emails`: each with `mxValid` (the domain can receive mail), the `source` (`mailto` link or visible text) and the `page` where it was found.
- `phones`: each with the `source` (`tel` link or visible text) and the `page`. Numbers are normalized to digits with the international prefix when present.
- `socials`: first profile link found per network: Facebook, Instagram, LinkedIn, Twitter/X, YouTube, TikTok, Pinterest, Threads, WhatsApp, Telegram, GitHub. Share buttons and video links are ignored.
- `title`, `description`, `finalUrl`, `pagesCrawled`, `pages`, `failedPages`, `skippedByRobots`.

Websites that cannot be fetched are returned with an `error` field and are not charged.

### How to use it

1. Open the **Input** tab.
2. Paste the website URLs in **Website URLs**, one per line (the home page is enough).
3. Optionally change **Max pages per website** (10 by default, up to 30) and **Validate email domains**.
4. Click **Start**. Read the results in the **Output** tab or export them as JSON, CSV or Excel for your CRM.
5. Run it from your code or an AI agent with the API call below, or schedule it to re-check your list and get `EMAIL_ADDED`, `PHONE_ADDED` and `SOCIAL_CHANGED` events when a company publishes new contact details.

### Input

```json
{
  "websites": ["https://www.iana.org/", "https://example-company.com"],
  "maxPages": 10,
  "validateEmails": true
}
```

| Field            | Description |
|------------------|-------------|
| `websites`       | Website URLs. Up to 50 per run. Private or internal addresses are rejected. |
| `maxPages`       | Pages crawled per website, home page included. Default 10, maximum 30. |
| `validateEmails` | Default `true`. Adds `mxValid` to every email by checking the domain's MX records. |

### Output example

```json
{
  "url": "https://www.iana.org/",
  "finalUrl": "https://www.iana.org/",
  "title": "Internet Assigned Numbers Authority",
  "emails": [{ "email": "iana@iana.org", "mxValid": true, "source": "mailto", "page": "https://www.iana.org/contact" }],
  "phones": [{ "number": "+13108239358", "source": "text", "page": "https://www.iana.org/contact" }],
  "socials": { "twitter": "https://x.com/iana" },
  "pagesCrawled": 10,
  "failedPages": 0,
  "skippedByRobots": 0,
  "timestamp": "2026-10-02T20:00:00.000Z"
}
```

### Pricing

You pay per website with results, nothing else:

- **Contacts found** ($0.003): one website where at least one email, phone or social profile was found, with everything included.
- **Contacts changed** ($0.005): only in scheduled runs, when a website's contacts changed since the previous run.
- **Actor start** ($0.00005): Apify's standard start fee.

Websites with no contacts and websites that fail are free. 1,000 websites with contacts cost $3. Comparable Actors charge $0.01 to $0.02 per email.

### Use it as an API

```bash
curl -X POST "https://api.apify.com/v2/acts/USERNAME~contact-extractor/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"websites":["https://www.iana.org/"],"maxPages":10}'
```

Replace `USERNAME~contact-extractor` with the Actor id shown on this page. The call returns the Dataset items directly. The Actor is also available to AI agents through Apify's MCP integration.

### FAQ

**It found nothing on a site that clearly has a contact page.** Some sites render their content only with JavaScript or hide emails behind forms or images; a plain HTTP crawler cannot read those. Check `pagesCrawled`: if it is 1, the site may block crawlers or list no internal links.

**Why are some emails flagged `mxValid: false`?** Their domain has no mail server, so messages would bounce. Typical for placeholder or outdated addresses.

**Does it respect robots.txt?** Yes. Pages disallowed for all crawlers are skipped and counted in `skippedByRobots`.

**Can I monitor a list of companies?** Yes. Schedule the Actor; every run compares each website with the previous snapshot and emits events for new or removed emails, phones and social profiles.

**Is anything bypassed?** No. The Actor reads public pages with plain requests, never requests private or internal addresses and never evades anti-bot systems.

# Actor input Schema

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

One per line, e.g. https://example.org. The home page and up to maxPages pages of the same domain are crawled.

## `maxPages` (type: `integer`):

Pages crawled per website (home page included). Contact, about, team and legal pages are visited first.

## `validateEmails` (type: `boolean`):

Check via DNS that each email's domain can receive mail (MX record). Adds the mxValid flag to every email.

## `product` (type: `string`):

Internal. Leave as is.

## Actor input object example

```json
{
  "websites": [
    "https://www.iana.org/"
  ],
  "maxPages": 10,
  "validateEmails": true,
  "product": "contact-extractor"
}
```

# Actor output Schema

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

Dataset items: url, changed, events, data, timestamp and error (when the target failed).

# 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.iana.org/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("aolmo/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.iana.org/"] }

# Run the Actor and wait for it to finish
run = client.actor("aolmo/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.iana.org/"
  ]
}' |
apify call aolmo/contact-extractor --silent --output-dataset

```

## MCP server setup

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