# Website Email Extractor — Emails, Phones & Socials (`lergassy/website-email-extractor`) Actor

\[$25/1K websites with contacts] Website email extractor: paste website URLs or domains, get every public e-mail with the page it was found on, plus phones, WhatsApp, Telegram and social profiles. One row per website, empty and blocked sites free, no fee per page.

- **URL**: https://apify.com/lergassy/website-email-extractor.md
- **Developed by:** [Matvey](https://apify.com/lergassy) (community)
- **Categories:** Lead generation, Agents, MCP servers
- **Stats:** 4 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $17.50 / 1,000 website with contacts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 Extractor** pulls e-mail addresses out of any list of websites. Paste website URLs or bare domains, press Start, and get one clean row per website: every public **e-mail address** with the page it was found on, plus **phone numbers, WhatsApp and Telegram links, social profiles, the contact page and the postal address** when the site publishes them. No API key, no login, no browser. You pay per website with contacts, never per page. Export to JSON, CSV or Excel, or call it through the API.

> This Actor is a focused entry point for the query "website email extractor". It runs the same engine as **[Email Scraper — Phones, Socials & Contacts from Any Website](https://apify.com/lergassy/website-contacts-api)**, at the same price. Use either one — the output is identical.

### Tested head-to-head — 9 October 2026

![Website email extractors compared](https://raw.githubusercontent.com/lergassy/apify-actor-assets/main/benchmarks/website-email-extractor-tested-2026-10-09.png)

We sent the same 10 websites (python.org, apache.org, eff.org, w3.org and six more) to this Actor and to the four website email scrapers with the most monthly users on Apify Store (A–D, most users first).

- **Found:** an e-mail on 9 of 10 websites. The others found one on 1, 5, 6 and 6.
- **Speed:** 7.7 s for all 10; the others took 19 s to 900 s (one timed out).
- **Output:** one row per website with every address, its type and source page, phones and socials. The others return one row per page, per contact or per e-mail.
- **Price:** $0.225 for the 9 websites with contacts (the 10th, blocked, was free). Three Actors charged $0.29–$0.33 for the same list; one charged $0.036 and found e-mails on 6 sites.
- **Where we were weaker:** w3.org sits behind an anti-bot wall; two of the other Actors got its contact address, we returned a free `blocked` row.

### What does the website email extractor do?

For every website in your list it reads the home page and the few pages that actually carry contacts (contact, about, team, imprint, legal, privacy, locations — in a dozen languages), and extracts e-mail addresses from:

- `mailto:` links and schema.org `email` markup;
- Cloudflare-protected addresses (`data-cfemail` and `/cdn-cgi/l/email-protection` links are decoded);
- addresses written in the page text, including `name [at] company [dot] com` and `name (at) company.com`.

Addresses found only in prose are kept **only when their domain really exists** (a DNS check), and placeholders (`example@`, `yourname@`), template domains and error-tracker addresses (`sentry.io`, `wixpress.com`) are dropped. Each address comes with its type (`role` for info@/sales@/support@, `personal` for `first.last@`, `generic` otherwise — a heuristic), whether it is on the website's own domain, whether it is a free mailbox (gmail.com …), and the source page.

Phone numbers found on the same pages are validated with `libphonenumber` and returned in E.164 with country and type. Social links (LinkedIn, Facebook, Instagram, X, YouTube, TikTok, Pinterest, Threads, GitHub), WhatsApp and Telegram come in the same row at no extra cost.

### How to extract emails from a list of websites

1. Open the **Input** tab.
2. Paste your websites into **🌐 Websites** (one per line), or bare domains like `acme.com` into **🌐 Domains**. You can also upload a file or link a Google Sheet.
3. Press **Start**. Each website takes a few seconds; 10 are scanned in parallel by default.
4. Download the results as JSON, CSV or Excel from the **Output** tab, or read them through the API.

An empty API call works too: with no input, the Actor scans five example websites (apify.com, basecamp.com, ycombinator.com, hubspot.com, zendesk.com) so you can see the output format.

### ⬇️ Input

```json
{
    "startUrls": [
        { "url": "https://www.apify.com" },
        { "url": "https://www.hubspot.com" }
    ],
    "domains": ["basecamp.com"],
    "maxPagesPerSite": 6,
    "onlyOwnDomainEmails": false,
    "checkEmails": false
}
```

| Field | Default | What it does |
|---|---|---|
| `startUrls` | 5 example sites | Websites to scan: a domain, a home page or any page of the site |
| `domains` | empty | Bare domains without `https://`, merged with the websites above |
| `maxPagesPerSite` | `6` | Home page plus the most contact-like pages, 1–30. The price does not depend on it |
| `defaultCountry` | `US` | Country used to read phone numbers written without a country code; a site's country domain wins |
| `onlyOwnDomainEmails` | `false` | Keep only addresses on the website's own domain |
| `checkEmails` | `false` | Paid add-on: DNS-level deliverability, mail provider, disposable / role / free flags, typo suggestion |
| `stopEarly` | `true` | Skip remaining pages once an own-domain e-mail and a phone were found |
| `maxWebsites`, `concurrency`, `pageTimeoutSecs` | `1000`, `10`, `15` | Safety cap, parallelism, per-page timeout |
| `proxyConfiguration`, `useUnblocker` | off | Optional Apify Proxy; Unblocker as a last attempt for the hardest sites |

### ⬆️ Output

One row per website:

```json
{
    "type": "website",
    "inputUrl": "https://www.bmw.de",
    "website": "https://www.bmw.de/de/index.html",
    "domain": "bmw.de",
    "companyName": "BMW",
    "status": "ok",
    "bestEmail": "kundenbetreuung@bmw.de",
    "bestEmailType": "generic",
    "bestPhone": "+4989125016000",
    "emailCount": 2,
    "phoneCount": 2,
    "emails": [
        { "email": "kundenbetreuung@bmw.de", "type": "generic", "isOwnDomain": true, "isFree": false, "source": "mailto", "sourceUrl": "https://www.bmw.de/de/footer/metanavigation/legal-notice-pool/imprint.html" },
        { "email": "bmw-connecteddrive@bmw.de", "type": "generic", "isOwnDomain": true, "isFree": false, "source": "mailto", "sourceUrl": "https://www.bmw.de/de/footer/metanavigation/legal-notice-pool/imprint.html" }
    ],
    "phones": [
        { "phone": "+4989125016000", "formatted": "+49 89 125016000", "country": "DE", "kind": "fixed_line", "source": "tel", "sourceUrl": "https://www.bmw.de/de/footer/metanavigation/legal-notice-pool/imprint.html" }
    ],
    "facebook": "https://facebook.com/BMWDeutschland",
    "instagram": "https://instagram.com/bmwdeutschland",
    "youtube": "https://youtube.com/user/BMWDeutschland",
    "contactPageUrl": "https://www.bmw.de/de/footer/metanavigation/legal-notice-pool/imprint.html",
    "addressStreet": "Petuelring 130",
    "addressCity": "Munich",
    "addressPostalCode": "80788",
    "addressCountry": "DE",
    "pagesScannedCount": 2,
    "summary": "BMW: kundenbetreuung@bmw.de, +4989125016000 (2 e-mails, 2 phones); facebook, instagram, youtube.",
    "scrapedAt": "2026-09-06T00:58:12.415Z"
}
```

(Shortened: every row also carries `whatsapp`, `telegram`, `linkedin`, `x`, `tiktok`, `pinterest`, `threads`, `github`, `contactFormUrl`, `addressRegion`, `addressText`, `language`, `phoneCountryUsed`, `pagesScanned`, `fetchedVia` and `durationMs`, `null` when not found.)

A website that could not be read comes back as an error row, free of charge, so a batch never silently loses a domain:

```json
{ "type": "error", "inputUrl": "https://www.zalando.de", "domain": "zalando.de", "status": "blocked", "httpStatus": 403, "error": "anti_bot_challenge" }
```

### 💰 Pricing

Pay per event, two events:

| Event | Price | When it is charged |
|---|---|---|
| 🌐 Website with contacts | **$25 per 1,000 websites** ($0.025 each, lower on paid Apify plans) | Once per website where at least one e-mail or phone was found |
| ✅ Add-on: e-mail check | $3 per 1,000 addresses ($0.003 each) | Only when `checkEmails` is on, once per checked address (up to 20 per website) |

**Free:** websites with no contacts, unreachable and blocked websites, and every page read. There is no fee per run and no fee per page, and Apify platform usage is included in the price. A list of 1,000 websites costs at most $25, less when some of them publish nothing.

### Limits and honest notes

- **Public data only.** The Actor reads what a website shows to any visitor. It never logs in, never guesses addresses and never uses third-party databases — if a site publishes no e-mail, you get `status: no_contacts`, free.
- **JavaScript-only sites.** A home page that is an empty JavaScript shell yields `no_contacts` with `note: javascript_rendered_site`. No browser is run.
- **Anti-bot walls.** Sites behind strong challenges come back as `status: blocked`, free of charge. Ordinary business websites rarely have them.
- **The e-mail check is domain-level.** It tells you whether the domain accepts mail and who hosts it; it does not confirm that a specific mailbox exists.

### ❓ FAQ

#### How do I extract emails from a website?

Put the website into **🌐 Websites** (or its domain into **🌐 Domains**) and press Start. The row lists every address found, the page each one came from, and the best address in `bestEmail`.

#### Can I extract emails from thousands of websites at once?

Yes. Put the whole list into one run — up to `maxWebsites` (1,000 by default, raise it as needed). You pay only for websites where a contact was found.

#### Does it crawl the whole website?

No. It reads the home page and the pages most likely to carry contacts — 6 by default, up to 30. That finds nearly everything on a normal business site and keeps runs fast. The price is the same whatever this number is.

#### Why is `bestEmail` info@ when a personal address was also found?

The general inbox is the address a company publishes as its contact, so it ranks first. Personal addresses are still in `emails[]` with `type: "personal"`.

#### What is the difference from Email Scraper — Phones, Socials & Contacts from Any Website?

None in the data: this Actor runs the same engine at the same price. It is a separate entry point for people searching for a website email extractor. The main Actor is [lergassy/website-contacts-api](https://apify.com/lergassy/website-contacts-api).

#### Is it legal to extract emails from websites?

The Actor collects only what websites publish to every visitor. What you do with it — outreach, storage, profiling — is governed by laws such as GDPR and CAN-SPAM. Check the rules for your use case; personal addresses in particular carry obligations.

### Your feedback

Found a website where a published address was missed? Open an **Issue** on this page with the URL.

# Actor input Schema

## `startUrls` (type: `array`):

Websites to extract e-mails from, one per line: a domain (<code>acme.com</code>), a home page or any page of the site. Paste a list, upload a file, or link a Google Sheet. One dataset row comes back per website.

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

Bare domains without https://, e.g. <code>acme.com</code> — handy for lists exported from Google Maps, a CRM or a spreadsheet. Merged with the websites above.

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

Home page plus the most contact-like pages (contact, about, team, imprint, legal). 6 finds nearly everything on a normal business site; raise it for large sites. The price does not depend on this number.

## `defaultCountry` (type: `string`):

Two-letter country code used to read phone numbers written without a country code. A site's own country domain (<code>.de</code>, <code>.co.uk</code>, <code>.id</code>) always wins over this value.

## `checkEmails` (type: `boolean`):

Adds deliverability signals for every e-mail found: whether the domain accepts mail (DNS MX), the mail provider, disposable and role flags and a typo suggestion. Charged per checked address. This is a domain-level check, not a mailbox probe.

## `onlyOwnDomainEmails` (type: `boolean`):

Drop addresses on other domains (a partner, a web agency, a gmail.com mailbox). Off by default because a sole trader's only address is often on gmail.com.

## `stopEarly` (type: `boolean`):

Faster runs: once a page has yielded both an e-mail on the site's own domain and a valid phone, the remaining pages of that website are skipped. Turn off to collect every address on every page.

## `maxWebsites` (type: `integer`):

Safety cap on how many websites from the list are processed in one run.

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

How many websites are scanned at the same time.

## `pageTimeoutSecs` (type: `integer`):

Give up on a page after this many seconds.

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

Not needed for normal business websites and off by default. Turn on Apify Proxy only if your list is full of sites that block datacenter traffic.

## `useUnblocker` (type: `boolean`):

Off by default. Sites behind the strongest anti-bot walls — large marketplaces, review and job boards — refuse both ordinary and residential addresses. With this on, such a site gets one more attempt through Apify's Unblocker, which solves the challenge with a real browser. It costs noticeably more per site, so turn it on only when your list is full of big platforms; ordinary business websites never need it.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.apify.com"
    },
    {
      "url": "https://www.basecamp.com"
    },
    {
      "url": "https://www.ycombinator.com"
    },
    {
      "url": "https://www.hubspot.com"
    },
    {
      "url": "https://www.zendesk.com"
    }
  ],
  "domains": [],
  "maxPagesPerSite": 6,
  "defaultCountry": "US",
  "checkEmails": false,
  "onlyOwnDomainEmails": false,
  "stopEarly": true,
  "maxWebsites": 1000,
  "concurrency": 10,
  "pageTimeoutSecs": 15,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "useUnblocker": false
}
```

# Actor output Schema

## `websites` (type: `string`):

One flat row per website: company name, best e-mail and phone, every e-mail and phone with its source page, WhatsApp, Telegram, LinkedIn, Facebook, Instagram, X, YouTube, TikTok, contact page, contact form, postal address, pages scanned and a one-sentence summary. Error rows carry the reason.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.apify.com"
        },
        {
            "url": "https://www.basecamp.com"
        },
        {
            "url": "https://www.ycombinator.com"
        },
        {
            "url": "https://www.hubspot.com"
        },
        {
            "url": "https://www.zendesk.com"
        }
    ],
    "domains": [],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lergassy/website-email-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 = {
    "startUrls": [
        { "url": "https://www.apify.com" },
        { "url": "https://www.basecamp.com" },
        { "url": "https://www.ycombinator.com" },
        { "url": "https://www.hubspot.com" },
        { "url": "https://www.zendesk.com" },
    ],
    "domains": [],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("lergassy/website-email-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 '{
  "startUrls": [
    {
      "url": "https://www.apify.com"
    },
    {
      "url": "https://www.basecamp.com"
    },
    {
      "url": "https://www.ycombinator.com"
    },
    {
      "url": "https://www.hubspot.com"
    },
    {
      "url": "https://www.zendesk.com"
    }
  ],
  "domains": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call lergassy/website-email-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lergassy/website-email-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/ambKkz8lqNo7OgU7d/builds/1gaGiuwoCegmt5TYN/openapi.json
