# Email & Phone Extractor – Scrape Contacts from Websites (`rl1987/universal-contact-extractor`) Actor

Paste a list of website URLs and get the contacts published on those pages: email addresses, phone numbers and LinkedIn, X, Instagram, Facebook, GitHub and Discord links. One row per contact, de-duplicated and stamped with the page it came from. Pages are rendered in a real browser. No API key.

- **URL**: https://apify.com/rl1987/universal-contact-extractor.md
- **Developed by:** [R.L.](https://apify.com/rl1987) (community)
- **Categories:** Social media
- **Features:** Limited permissions
- **Stats:** 23 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## Email & Phone Extractor – Scrape Contacts from Websites

Give this Actor a list of website URLs and it returns the contact details published on
those pages: **email addresses, phone numbers, and LinkedIn, X (Twitter), Instagram,
Facebook, GitHub and Discord links** — one row per contact, de-duplicated across the run,
each stamped with the page it came from.

It loads every page in a real browser (Camoufox, a stealth Firefox build), so contact
details that only appear after the page's JavaScript runs are still seen. It is
site-agnostic: company homepages, "contact us" and "about" pages, directory pages,
personal sites, conference pages — anything reachable without a login.

### What does it extract?

| `contact_type` | What it matches |
| --- | --- |
| `email` | Email addresses published as `mailto:` links. |
| `phone_no` | `tel:` links; on a page with no `tel:` link, phone numbers detected in the page text using the `phone_country` you set. |
| `linkedin_url` | LinkedIn personal (`/in/…`) and company (`/company/…`) profile URLs. |
| `x_url` | X / Twitter profile URLs. `twitter.com` links are normalised to `x.com`. |
| `instagram_url` | Instagram profile URLs. |
| `facebook_url` | Facebook page and profile URLs on `www.facebook.com`. |
| `github_url` | GitHub user and organisation URLs (the profile root, not repositories). |
| `discord_url` | Discord links (`discordapp.com`). |

Deep links, tracking-parameter URLs and post/status URLs are filtered out, so you get the
profile itself rather than every share button on the page.

### How do I extract emails from a list of websites?

1. Put your URLs into **Start URLs** — paste them one per line, or link a file or Google
   Sheet of URLs.
2. Leave **Max Crawl Depth** at `0` to look only at the pages you listed, or raise it to
   also follow links found on those pages.
3. Set **Phone country** to the country whose phone-number format you expect (e.g. `US`,
   `GB`, `DE`).
4. Click **Start**, then download the dataset as JSON, CSV or Excel — or fetch it through
   the Apify API.

### What input does it take?

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `start_urls` | array of `{url}` | – | **Required.** The pages to extract contacts from. |
| `max_depth` | integer | `0` | `0` = only the pages you listed. Higher values also follow links found on those pages, up to this depth, staying on the same hostname. |
| `phone_country` | string | `US` | Two-letter country code used to recognise phone numbers written in page text. |

```json
{
    "start_urls": [
        { "url": "https://www.whitehouse.gov/" }
    ],
    "phone_country": "US",
    "max_depth": 1
}
```

### What does each row contain?

Three fields: the kind of contact, the contact itself, and the page it was found on.

|    | contact                               | contact_type   | url                               |
|---:|:--------------------------------------|:---------------|:----------------------------------|
|  0 | https://x.com/whitehouse              | x_url          | https://www.whitehouse.gov        |
|  1 | https://www.instagram.com/whitehouse/ | instagram_url  | https://www.whitehouse.gov        |
|  2 | (202) 225-1904                        | phone_no       | https://www.whitehouse.gov/visit/ |
|  3 | (202) 456-7041                        | phone_no       | https://www.whitehouse.gov/visit/ |
|  4 | (202) 224-3121                        | phone_no       | https://www.whitehouse.gov/visit/ |
|  5 | https://instagram.com/whitehouse/      | instagram_url  | https://www.whitehouse.gov/wire/  |

Each contact is emitted **once per run**, even if it appears on many pages; `url` is the
first page it was seen on. One row is one billable result.

### How much does it cost?

**$0.01 per contact row** returned, plus Apify platform usage (the browser is the main cost
driver). A page with an email, a phone number and three social links is five rows. To put a
ceiling on a run, set its **maximum cost per run** in the run options and keep `max_depth`
at `0` — raising the depth multiplies the number of pages visited.

### FAQ

**Do I need an API key, an account or a proxy?** No. The Actor fetches the pages itself with
a built-in browser. It can only read what a visitor can read without logging in.

**Can I feed it a list of hundreds of websites?** Yes — that is the normal use. Put every URL
into `start_urls` (paste them, or link a file or Google Sheet of URLs) and run it once.

**Where do the email addresses come from?** From `mailto:` links on the page. A page that
publishes its address only as an image, or hides it behind a contact form, produces no email
row — check such sites manually or crawl deeper with `max_depth`.

**How are phone numbers found?** `tel:` links are preferred. If a page has none, the page text
is scanned for numbers in the format of the `phone_country` you set, so set it to the country
you are prospecting in — a US setting will miss most German numbers.

**Will it crawl the whole website?** Only if you ask it to. `max_depth` `0` (the default)
visits exactly the URLs you supplied; a higher value follows links found on those pages, up
to that depth, and stays on the same hostname rather than wandering onto other sites.

**Are duplicate contacts removed?** Yes. The same email, phone number or profile URL is
returned once per run, no matter how many pages carry it, so you are not billed twice for the
same contact.

**Can it pull contacts out of the LinkedIn or Instagram profiles it finds?** No. It collects
the profile links published on the pages you give it; it never logs into those platforms. Use
a dedicated social-profile Actor for what is behind those links.

### Did you find this useful?

Rate this Actor on Apify — your feedback helps other people find it and helps us keep
improving it.

# Actor input Schema

## `start_urls` (type: `array`):

URLs to start with

## `max_depth` (type: `integer`):

Max crawling depth (set 0 to disable link traversal)

## `phone_country` (type: `string`):

Phone number format country (used to autodetect phone numbers in text) - 2 letter code

## Actor input object example

```json
{
  "start_urls": [
    {
      "url": "https://www.whitehouse.gov"
    }
  ],
  "max_depth": 0,
  "phone_country": "US"
}
```

# 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 = {
    "start_urls": [
        {
            "url": "https://www.whitehouse.gov"
        }
    ],
    "max_depth": 0,
    "phone_country": "US"
};

// Run the Actor and wait for it to finish
const run = await client.actor("rl1987/universal-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 = {
    "start_urls": [{ "url": "https://www.whitehouse.gov" }],
    "max_depth": 0,
    "phone_country": "US",
}

# Run the Actor and wait for it to finish
run = client.actor("rl1987/universal-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 '{
  "start_urls": [
    {
      "url": "https://www.whitehouse.gov"
    }
  ],
  "max_depth": 0,
  "phone_country": "US"
}' |
apify call rl1987/universal-contact-extractor --silent --output-dataset

```

## MCP server setup

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