# Website Email Scraper & Phone Finder (`scrapers-hub/website-email-phone-extractor`) Actor

Website Email Scraper & Phone Finder crawls domains for emails, phone numbers and social links across Facebook, Instagram, LinkedIn, Twitter, YouTube and TikTok, with page limits and concurrency. 📇 Complete contact data enrichment.

- **URL**: https://apify.com/scrapers-hub/website-email-phone-extractor.md
- **Developed by:** [Scrapers Hub](https://apify.com/scrapers-hub) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.99 / 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?

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 Email Scraper & Phone Finder

### 📧 Website Email Scraper & Phone Finder – Contact Details, Phones & Socials From Any Domain

The **website email scraper** crawls a list of websites and returns the email addresses, phone numbers and social media profiles published on them, with full provenance for every contact found. Give this website email scraper and phone finder a list of domains and it visits each site, follows a configurable number of internal pages, and writes one record per domain containing the emails discovered, where each was found, any phone numbers, and social profile URLs split by network.

What separates it from a naive regex crawler is the detail it keeps. Each record carries `fetchedUrls` showing exactly which pages were visited, `httpStatusCodes` showing what each returned, `emailDetails` recording the source URL and inferred type of every address, and `contactSignals` summarising the yield. That means you can audit any contact back to the page it came from — which matters both for data quality and for compliance.

***

### 📊 What Data Can You Extract with This Website Email Scraper?

Each dataset item covers one input domain:

| Category | Fields | What you get |
|---|---|---|
| 🔗 Identity | `input`, `url`, `domain`, `status` | The value you supplied, the resolved URL, the normalised domain and the outcome status for that site |
| 📧 Email data | `emails`, `emailDetails` | The list of addresses found, plus per-address detail including source URL and inferred type |
| ☎️ Phone data | `phones` | Phone numbers discovered across the crawled pages |
| 🌐 Social profiles | `socialLinks`, `facebooks`, `instagrams`, `linkedIns`, `twitters`, `youtubes`, `tiktoks` | A combined social link map plus per-network arrays for six platforms |
| 🕷️ Crawl provenance | `pagesFetched`, `fetchedUrls`, `httpStatusCodes` | How many pages were visited, exactly which URLs, and the status code each returned |
| 📈 Diagnostics | `contactSignals`, `errors`, `durationMs` | A summary of contact counts, any errors encountered, and how long the site took to process |

The field that earns its place most often is `emailDetails`. A bare list of addresses gives you no way to distinguish a genuine contact address on a `/contact` page from a stray image-credit address in a footer. `emailDetails` records the source URL and inferred type for each, so you can rank and filter by where the address actually appeared before anything reaches an outreach tool.

***

### 🌟 Key Features of the Website Email Scraper & Phone Finder

| Feature | Description |
|---|---|
| 📋 Bulk domain processing | `domains` accepts a list of website URLs or bare domains and processes the whole batch in one run |
| 🕸️ Configurable crawl depth | `maxPagesPerWebsite` controls how many pages per site are checked — deeper crawls find more contacts but take longer |
| ⚡ High parallelism | `concurrency` defaults to 100 parallel websites, so large lists complete quickly |
| 🎯 Three result modes | `resultMode` returns only sites with emails, only sites with any contacts, or every site scanned including empty ones |
| ☎️ Phone extraction | `extractPhones` collects phone numbers alongside email addresses |
| 🌐 Six social networks | `extractSocials` returns Facebook, Instagram, LinkedIn, Twitter/X, YouTube and TikTok profiles in separate arrays |
| 🔒 Same-domain containment | `sameDomainOnly` keeps the crawl on the target domain rather than wandering to external sites |
| 🧾 Full provenance | `fetchedUrls`, `httpStatusCodes` and `emailDetails` let you trace every contact back to its source page |
| ⏱️ Timeout control | `requestTimeoutSecs` bounds per-request wait time so slow sites cannot stall a batch |

***

### 🚀 Why Choose This Website Email Scraper?

**Provenance for every contact.** Most email finders hand you an address and nothing else. This one records which URL it came from in `emailDetails`, which pages were visited in `fetchedUrls`, and what each returned in `httpStatusCodes`. When a prospect asks where you got their address — or when you need to verify a suspicious result — you have the answer.

**Result modes that match how you actually work.** `resultMode` has three settings for three genuinely different jobs. `emailsOnly` gives a clean outreach list. `contactsOnly` widens it to sites with any contact signal including phones and socials. `allWebsites` returns every domain scanned, including empty ones, which is what you need when the absence of a contact is itself the finding.

**Genuinely fast on large lists.** With `concurrency` defaulting to 100 parallel websites and a short `requestTimeoutSecs`, thousands of domains are practical in a single run. The sample record shows a three-page crawl completing in 1,431 milliseconds — small sites are processed in around a second each.

**Phones and socials in the same pass.** Running separate tools for emails, phone numbers and social profiles means three crawls of the same sites. Here `extractPhones` and `extractSocials` are both on by default, so one crawl yields the complete contact surface.

***

### 📥 Input

```json
{
  "domains": ["centralrestaurante.com", "alchemist.dk", "caitlinmcweeney.com"],
  "maxResults": 1000,
  "resultMode": "emailsOnly",
  "maxPagesPerWebsite": 3,
  "concurrency": 100,
  "requestTimeoutSecs": 5,
  "extractPhones": true,
  "extractSocials": true,
  "includePersonalData": true,
  "sameDomainOnly": true
}
```

#### 🔧 Website Email Scraper Input Fields

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `domains` | array | Yes | `["centralrestaurante.com", "alchemist.dk", "caitlinmcweeney.com"]` | List of website URLs or domains to scan |
| `maxResults` | integer | No | `1000` | Maximum number of saved results |
| `resultMode` | string | No | `emailsOnly` | Which results to save. `emailsOnly` (only websites with emails), `contactsOnly` (only websites with contacts), `allWebsites` (all scanned websites) |
| `maxPagesPerWebsite` | integer | No | `3` | Pages to check per website. Controls crawl depth and saved contact fields. Higher values can find more emails but increase runtime |
| `concurrency` | integer | No | `100` | Number of parallel websites to process |
| `requestTimeoutSecs` | integer | No | `5` | Timeout for requests in seconds |
| `extractPhones` | boolean | No | `true` | Extract phone numbers |
| `extractSocials` | boolean | No | `true` | Extract social media profiles |
| `includePersonalData` | boolean | No | `true` | Extract personal data |
| `sameDomainOnly` | boolean | No | `true` | Restrict crawl to the same domain |

#### 💡 Input Examples

Fast, wide sweep for email addresses only:

```json
{
  "domains": ["example.com", "example.org", "example.net"],
  "resultMode": "emailsOnly",
  "maxPagesPerWebsite": 2,
  "concurrency": 150,
  "requestTimeoutSecs": 4,
  "extractPhones": false,
  "extractSocials": false
}
```

Deep contact discovery on a small, high-value list:

```json
{
  "domains": ["centralrestaurante.com", "alchemist.dk"],
  "resultMode": "contactsOnly",
  "maxPagesPerWebsite": 10,
  "concurrency": 10,
  "requestTimeoutSecs": 15
}
```

Full audit of every domain scanned, with personal data excluded:

```json
{
  "domains": ["example.com", "example.co.uk"],
  "resultMode": "allWebsites",
  "includePersonalData": false,
  "sameDomainOnly": true,
  "maxResults": 5000
}
```

***

### 📤 Output

```json
{
  "input": "caitlinmcweeney.com",
  "url": "https://caitlinmcweeney.com",
  "domain": "caitlinmcweeney.com",
  "status": "found",
  "pagesFetched": 3,
  "fetchedUrls": [
    "https://caitlinmcweeney.com/",
    "https://caitlinmcweeney.com/contact",
    "https://caitlinmcweeney.com/about"
  ],
  "emails": ["caitlin@caitlinmcweeney.com"],
  "phones": [],
  "facebooks": ["https://www.facebook.com/caitlinmcweeneyphotography"],
  "instagrams": ["https://www.instagram.com/caitlinmcweeneyphotography/"],
  "linkedIns": [],
  "contactSignals": {
    "emails": 1,
    "phones": 0,
    "socialProfiles": 2,
    "pagesFetched": 3
  },
  "errors": [],
  "durationMs": 1431
}
```

#### 🧾 Website Email Scraper Output Fields

| Field | Type | Description |
|---|---|---|
| `input` | string | null | The value as you supplied it in `domains` |
| `url` | string | null | Canonical URL of the scraped site |
| `domain` | string | null | Normalised domain name |
| `status` | string | null | Outcome status for this site, such as `found` |
| `pagesFetched` | integer | null | Number of pages fetched for this site |
| `fetchedUrls` | array | null | The exact URLs that were fetched |
| `emails` | array | null | Email addresses found |
| `emailDetails` | array | null | Per-email detail including source URL and inferred type |
| `phones` | array | null | Phone numbers found |
| `socialLinks` | object | null | Combined map of social links keyed by platform domain |
| `facebooks` | array | null | Facebook profile URLs |
| `instagrams` | array | null | Instagram profile URLs |
| `linkedIns` | array | null | LinkedIn profile URLs |
| `twitters` | array | null | Twitter/X profile URLs |
| `youtubes` | array | null | YouTube channel URLs |
| `tiktoks` | array | null | TikTok profile URLs |
| `contactSignals` | object | null | Summary counts of emails, phones, social profiles and pages fetched |
| `httpStatusCodes` | object | null | HTTP status code returned by each fetched URL |
| `errors` | array | null | Errors encountered while processing this site |
| `durationMs` | integer | null | Processing time for this site in milliseconds |

***

### 💻 How to Use the Website Email Scraper (Step by Step)

#### Step 1: Assemble and clean your domain list

`domains` accepts either full website URLs or bare domains, so both `https://example.com/about` and `example.com` work. Cleaner input still gives cleaner output: strip tracking parameters, deduplicate, and remove obviously dead domains before running. The value you supply is echoed back in `input`, which makes joining results to your source list straightforward regardless of format.

#### Step 2: Choose a result mode

This is the most consequential input. `emailsOnly` — the default — saves only sites where an email was found, giving you a ready-to-use outreach list with no filtering. `contactsOnly` widens the net to any site with a contact signal, including phone-only or social-only sites. `allWebsites` saves every domain scanned, which is what you want for coverage auditing, because it lets you distinguish "no contact found" from "not processed".

#### Step 3: Set crawl depth per website

`maxPagesPerWebsite` defaults to 3, which typically covers a homepage plus contact and about pages — exactly where contact details usually live, as the sample output shows. Increasing it to 8 or 10 finds contacts on sites that bury them deeper, at proportionally higher runtime. For very large lists, staying at 2 or 3 and re-running the misses more deeply is more efficient than deep-crawling everything.

#### Step 4: Tune concurrency and timeout together

`concurrency` defaults to 100 parallel websites and `requestTimeoutSecs` to 5. These interact: high concurrency with a short timeout maximises throughput but drops slow-responding sites, which then appear with errors or no contacts. For a high-value list where every domain matters, lower `concurrency` to 10–20 and raise `requestTimeoutSecs` to 15. For a bulk sweep, keep the defaults.

#### Step 5: Decide on personal data and crawl containment

`includePersonalData` controls whether personal data is extracted. Where you are targeting corporate contacts only, or operating under strict privacy policy, setting it to `false` narrows what is collected. `sameDomainOnly` defaults to `true` and should usually stay there — it prevents the crawler following external links and collecting contacts belonging to unrelated third parties.

#### Step 6: Run and read the diagnostics

Start the run, then examine `contactSignals`, `pagesFetched` and `httpStatusCodes` on a sample of records. If `pagesFetched` is consistently 1 while `maxPagesPerWebsite` is 3, the crawler is not finding internal links to follow — often a sign of JavaScript-rendered navigation. Non-200 codes in `httpStatusCodes` explain most empty results.

#### Step 7: Filter with emailDetails before outreach

Export the dataset and, before anything is sent, use `emailDetails` to rank addresses by source. An address found on `/contact` is a stronger prospect than one scraped from a blog post byline. Filtering on source URL and inferred type at this stage does more for deliverability and reply rates than any amount of tweaking the crawl.

***

### 🔌 API Access & Integrations

Run the website email scraper and phone finder in a single call:

```bash
curl -X POST "https://api.apify.com/v2/acts/scrapers-hub~website-email-phone-extractor/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "domains": ["centralrestaurante.com", "alchemist.dk"],
    "resultMode": "emailsOnly",
    "maxPagesPerWebsite": 3,
    "extractPhones": true,
    "extractSocials": true
  }'
```

Python, using the official client:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")

run = client.actor("scrapers-hub/website-email-phone-extractor").call(
    run_input={
        "domains": ["example.com", "example.org"],
        "resultMode": "contactsOnly",
        "maxPagesPerWebsite": 5,
        "concurrency": 50,
        "requestTimeoutSecs": 10,
    }
)

for site in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(site["domain"], site["status"], site.get("emails"), site.get("phones"))
```

Results can be pushed to Zapier, Make, Google Sheets or Slack, or delivered to your own endpoint with an Apify webhook that fires when the run succeeds.

***

### 💡 Best Use Cases for Website Contact Data

#### 🎯 B2B lead enrichment at scale

Take the domain list from your CRM and fill the contact gaps. `emails` gives you addresses, `phones` gives sales a direct line, and `linkedIns` gives the company page for research. Because `input` is echoed back verbatim, joining enriched results to existing records needs no fuzzy matching at all.

#### 🍽️ Local business and hospitality outreach

The default domain list — restaurants and independent studios — reflects a common use case. Small businesses publish contact details openly but inconsistently, sometimes only on a contact page and sometimes only in an Instagram bio. Running with `resultMode` set to `contactsOnly` and `extractSocials` enabled captures whichever channel each business actually uses.

#### 🤝 Partnership and supplier discovery

When evaluating a list of potential partners or suppliers, `contactSignals` gives a quick read on how reachable each one is, and `socialLinks` shows where they are active. A company with no email, no phone and no social presence on its own site is a meaningful signal in a procurement shortlist.

#### 📰 PR and media list building

Publications and independent journalists list contact addresses across contact, about and masthead pages. Setting `maxPagesPerWebsite` higher and using `emailDetails` to filter for addresses found on editorial pages produces a targeted media list rather than a pile of generic `info@` addresses.

#### 🔍 Contact data auditing and verification

With `resultMode` set to `allWebsites`, the output becomes an audit rather than a lead list. `fetchedUrls` and `httpStatusCodes` document exactly what was checked and what responded, which is what you need to prove a domain genuinely publishes no contact details rather than assuming the crawler missed them.

#### 📊 Competitive contact surface analysis

Run a competitor set and compare the per-network arrays — `facebooks`, `instagrams`, `linkedIns`, `twitters`, `youtubes`, `tiktoks`. Which networks a company links from its own site is a direct statement of where it invests, and the `contactSignals` counts quantify how accessible each competitor makes itself.

#### 🧹 CRM hygiene and dead-domain detection

Run your existing account domains periodically. Records where `status` is not `found`, where `errors` is populated, or where `httpStatusCodes` shows widespread non-200 responses identify domains that have gone dark — companies that closed, rebranded or migrated. That is data decay you would otherwise only discover when an email bounces.

***

### ⚙️ Tips for Better Website Email Scraping Results

- **Match `concurrency` to `requestTimeoutSecs`.** High concurrency with a 5-second timeout maximises throughput but drops slow sites. For high-value lists, lower concurrency and raise the timeout.
- **Use `allWebsites` for coverage, `emailsOnly` for outreach.** Running once in `allWebsites` mode tells you your true hit rate; switching to `emailsOnly` afterwards gives the clean working list.
- **Increase depth only on the misses.** Crawl everything at 2–3 pages, then re-run just the empty results at 8–10. That is far cheaper than deep-crawling the whole list.
- **Keep `sameDomainOnly` enabled.** Letting the crawler follow external links collects contacts belonging to third parties who are not your prospects and may not be lawful targets.
- **Rank by `emailDetails` source URL.** Addresses found on contact pages consistently outperform those scraped from blog footers. This single filter improves list quality more than any crawl setting.
- **Watch `pagesFetched` versus your configured depth.** A consistent gap indicates JavaScript-rendered navigation the crawler cannot follow, which tells you those sites need a different approach.

***

### 🛠️ Troubleshooting

**A domain I know publishes an email returned nothing.**
Check `pagesFetched` and `httpStatusCodes` on that record. If only one page was fetched, the crawler could not find internal links — common on JavaScript-rendered sites. If the status codes are non-200, the site blocked or failed the request. Try raising `maxPagesPerWebsite` and `requestTimeoutSecs`.

**Most of my domains are missing from the output entirely.**
That is expected behaviour with the default `resultMode` of `emailsOnly`, which only saves sites where an email was found. Switch to `allWebsites` to see every domain that was scanned, including the empty ones.

**The run is timing out on large lists.**
Reduce `requestTimeoutSecs` so slow sites are abandoned faster, keep `concurrency` high, and lower `maxPagesPerWebsite` to 2. If the list is very large, also confirm `maxResults` is high enough that you are not capping output prematurely.

**Phone numbers look malformed or include non-phone digits.**
Phone extraction works from patterns in page text, and numbers appearing near other digit sequences can be captured imperfectly. Validate against an expected country format before dialling, and cross-check against `fetchedUrls` to see the source page.

**Emails appear that clearly belong to a different company.**
This usually means the crawl followed a link off-domain. Confirm `sameDomainOnly` is set to `true`, and use `emailDetails` to check the source URL of any suspicious address before using it.

***

### ❓ Frequently Asked Questions About Website Email Scraping

**What does the website email scraper and phone finder do?**
It crawls a list of websites and extracts the email addresses, phone numbers and social media profiles published on them, along with full provenance showing which pages were visited and where each contact was found.

**How many websites can I process in one run?**
As many as `maxResults` allows, which defaults to 1000 saved results. With `concurrency` at 100 parallel sites, large batches complete quickly.

**What is the difference between the three result modes?**
`emailsOnly` saves only sites where an email was found. `contactsOnly` saves sites with any contact signal, including phone or social only. `allWebsites` saves every site scanned, including those with nothing found.

**How deep does it crawl each site?**
`maxPagesPerWebsite` pages, defaulting to 3. That typically covers the homepage plus contact and about pages, which is where contact details usually live.

**Can I extract phone numbers as well as emails?**
Yes. `extractPhones` is enabled by default and populates the `phones` array.

**Which social networks are supported?**
Six, each in its own array: Facebook, Instagram, LinkedIn, Twitter/X, YouTube and TikTok, plus a combined `socialLinks` map. Controlled by `extractSocials`.

**How do I know where an email came from?**
`emailDetails` records the source URL and inferred type for each address, and `fetchedUrls` lists every page the crawler visited for that domain.

**What does `includePersonalData` do?**
It controls whether personal data is extracted. Set it to `false` when you want to restrict collection to non-personal contact information.

**Should I leave `sameDomainOnly` enabled?**
Yes, in almost all cases. It keeps the crawl on the target domain so you do not collect contacts belonging to unrelated third-party sites.

**Do I need to configure proxies?**
No. Proxy rotation is handled automatically by the actor; there is no proxy input to fill in.

**Why is `durationMs` useful?**
It shows how long each site took to process. Consistently high values across a batch usually mean `requestTimeoutSecs` is set too generously for the throughput you want.

**Can I schedule this to run regularly?**
Yes. Apify Schedules can run the actor on any cron expression, which makes it practical as a recurring CRM hygiene job as well as a one-off enrichment.

**Can I accept full URLs rather than bare domains?**
Yes. The `domains` field accepts website URLs or bare domains, and the resolved value is returned in `url` with the normalised form in `domain`.

**Why does `status` matter?**
It reports the outcome for each site — `found` in the sample record. Combined with `errors` and `httpStatusCodes`, it distinguishes a site with no contacts from a site that failed to load.

**Is it legal to scrape email addresses from websites?**
The scraper collects only publicly published information. Email addresses are personal data under GDPR and similar regimes even in a business context, so you must establish a lawful basis and comply with anti-spam law such as CAN-SPAM, CASL and PECR before using them for outreach.

***

### 🆘 Support & Feedback

If a site is not being crawled correctly, contacts are missing, or a run fails, please open a report on the **Issues** tab with your input configuration and the run ID.

For custom work — additional extraction patterns, higher-throughput builds, bespoke output formats, or a private variant for your team — email **scraperhubapi@gmail.com** with your requirements.

If this website email scraper saves you time, a review on the actor page is much appreciated and helps decide which improvements get built next.

***

### ⚖️ Disclaimer

This website email scraper collects only publicly available contact information that websites choose to publish on pages accessible without authentication. It does not log into any site, bypass access controls, or retrieve data hidden behind a form or paywall.

Email addresses, phone numbers and social profiles are personal data under GDPR, UK GDPR, CCPA and comparable privacy regimes, including when they belong to a business contact. You are responsible for establishing a lawful basis for processing, honouring opt-out and erasure requests, providing the required privacy notices, and complying with anti-spam legislation such as CAN-SPAM, CASL and PECR before contacting anyone. The `includePersonalData` input is provided so you can restrict collection where your policy requires it. You are also responsible for respecting the terms of service and robots directives of the websites you scan.

To request removal of specific data collected by this actor, email **scraperhubapi@gmail.com** with the details.

# Actor input Schema

## `domains` (type: `array`):

List of website URLs or domains.

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

Maximum number of saved results.

## `resultMode` (type: `string`):

Select the result mode.

## `maxPagesPerWebsite` (type: `integer`):

Control crawl depth and saved contact fields. Higher values can find more emails but increase runtime.

## `concurrency` (type: `integer`):

Number of parallel websites to process.

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

Timeout for requests in seconds.

## `extractPhones` (type: `boolean`):

Extract phone numbers.

## `extractSocials` (type: `boolean`):

Extract social media profiles.

## `includePersonalData` (type: `boolean`):

Extract personal data.

## `sameDomainOnly` (type: `boolean`):

Restrict crawl to the same domain.

## Actor input object example

```json
{
  "domains": [
    "centralrestaurante.com",
    "alchemist.dk",
    "caitlinmcweeney.com"
  ],
  "maxResults": 1000,
  "resultMode": "emailsOnly",
  "maxPagesPerWebsite": 3,
  "concurrency": 100,
  "requestTimeoutSecs": 5,
  "extractPhones": true,
  "extractSocials": true,
  "includePersonalData": true,
  "sameDomainOnly": true
}
```

# Actor output Schema

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

Records scraped by Website Email Scraper & Phone Finder, stored in the run's default dataset.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapers-hub/website-email-phone-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapers-hub/website-email-phone-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 '{}' |
apify call scrapers-hub/website-email-phone-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapers-hub/website-email-phone-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/CIcQzbVhrcbA7cFQ9/builds/x1vJUm2qTzDjEE6BQ/openapi.json
