# Website Email Scraper — Emails, Phones & Socials (`memo23/website-email-scraper`) Actor

Extract emails, phone numbers & social profiles from any list of websites. Direct crawl of each site's contact pages — ranked emails with confidence, optional MX verification, payment-stack detection & 0-100 lead scoring. Paste 10,000 URLs, get one graded row per site. JSON/CSV/API.

- **URL**: https://apify.com/memo23/website-email-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Lead generation, Agents, AI
- **Stats:** 11 total users, 11 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 website scraped for contacts

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/platform/actors/running/actors-in-store#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 — Emails, Phones & Socials

Turn any list of websites into a contact database.
Paste URLs or domains — the actor crawls each site's homepage and contact pages directly and returns every email, phone number, and social profile it finds, with a confidence grade and a 0–100 lead score on every row. JSON, CSV, Excel, or API out.

### Why Use This Scraper?

- ✅ Bulk-first — paste 10 or 10,000 websites in one run, one structured row per site
- ✅ Ranked emails with a source + confidence grade on every row
- ✅ Phone numbers and social profiles (LinkedIn, X/Twitter, Instagram, Facebook, YouTube, TikTok) from the same crawl at no extra cost
- ✅ Optional email verification — syntax, MX record, disposable / role-based / free-provider flags
- ✅ Optional payment-stack detection — know which leads actually take money online (Stripe, Shopify, PayPal, Paddle & more)
- ✅ Built-in 0–100 lead score with explainable signals
- ✅ Duplicate-proof billing — `stripe.com`, `https://www.Stripe.com/` and `STRIPE.COM` collapse to one charged crawl
- ✅ Drop-in compatible — accepts the `startUrls` input shape of other website-email actors unchanged

### Overview

The Website Email Scraper is built for sales teams, lead-gen agencies, and data teams who have a list of company websites and need the contacts behind them — without visiting each site by hand.

The output is one row per website. Each row carries every email, phone, and social profile found on that site's public pages, plus grading fields (`source`, `confidence`, `leadScore`) so you can sort a large run by quality instead of eyeballing it.

Not every website publishes a contact email — that is a property of the web, not a bug. Rows for such sites still return phones and socials when present, and the `onlyWithEmails` toggle lets you emit (and pay for) only the rows where an email was found.

### Supported Inputs

#### Accepted website formats

| Format | Example |
|---|---|
| Bare domain | `stripe.com` |
| Full URL | `https://www.stripe.com/` |
| URL with path | `https://stripe.com/about` (crawled from its domain) |

#### Copy-pasteable input

```json
{
  "websites": [
    "apify.com",
    "stripe.com",
    "charitywater.org"
  ]
}
```

#### Paste a list

Have the sites in a spreadsheet column or a text file? Paste the whole blob into `inputText` — newline, comma, or semicolon separated, mixed formats welcome. Duplicates (with/without `www`, `http`, trailing slash, different casing) are detected and billed once.

#### Migrating from another email actor?

The actor also accepts the `startUrls` field (plain strings or `{ "url": "..." }` objects), so the input of any competing website-email scraper works here unchanged.

#### Unsupported inputs

- ❌ Pages behind a login wall or paywall
- ❌ Social profile URLs as the target site (use the `socials` output field instead — pointing the crawler at facebook.com pages yields nothing useful)
- ❌ Email discovery by company *name* alone — this actor takes websites; for name-to-domain discovery and person-level lookups use [Email Finder & Verifier](https://apify.com/memo23/email-finder)

### Use Cases

| Audience | Use case |
|---|---|
| **Sales / SDR teams** | Turn a scraped or purchased list of company websites into outreach-ready emails and phones |
| **Lead-gen agencies** | Deliver enriched contact lists to clients without manual site visits |
| **Marketers** | Build niche outreach lists (local businesses, ecommerce brands, SaaS tools) with deliverability flags |
| **Data / RevOps teams** | Enrich CRM records that have a website but no contact details |
| **Founders & indie hackers** | Qualify prospect lists by who actually takes payments online before spending outreach effort |

### How It Works

![How It Works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-website-email-scraper.png)

1. **Input** — paste websites (or a raw text blob) into the input; duplicates collapse automatically
2. **Crawl** — each site's homepage plus common contact, about, and team pages are fetched directly
3. **Extract** — emails, phone numbers, and social profile links are harvested and de-duplicated; role addresses (info@, sales@) are ranked ahead of noise
4. **Grade** — every row gets a source, a confidence grade, and a 0–100 lead score; optional MX verification and payment-stack detection run in the same pass
5. **Output** — one row per website in the dataset, exportable as JSON, CSV, Excel, or via API

### Input Configuration

#### Input fields

| Field | Type | Required | Notes |
|---|---|---|---|
| `websites` | `array<string>` | yes (or `inputText`) | Websites to scrape, one URL or domain per entry |
| `inputText` | `string` | optional | Paste a blob of URLs/domains — newline, comma, or semicolon separated |
| `onlyWithEmails` | `boolean` | optional | Emit only rows with at least one email — you pay only for hits. Default `false` |
| `verifyEmails` | `boolean` | optional | Validate each found email (syntax + MX + disposable/role/free flags). Billed per email. Default `false` |
| `maxVerifiedEmailsPerSite` | `integer` | optional | Ceiling on verified (billed) emails per site; the rest return unverified |
| `qualifyByPayment` | `boolean` | optional | Detect payment processors on the pages already fetched. Free. Default `false` |
| `hunterApiKey` | `string` | optional | Your own Hunter.io key enables a paid fallback when the site scrape finds nothing |
| `maxItems` | `integer` | optional | Hard cap on websites processed. Free plans are capped at 25 |
| `maxConcurrency` | `integer` | optional | Parallel crawls, 1–50. Default `10` |
| `proxy` | `object` | optional | Leave empty — built-in residential proxy is included |

The `startUrls` field (strings or `{ "url": ... }` objects) is also accepted and merged into `websites`.

#### Common scenarios

**1. Bulk list, pay only for sites where an email was found**

```json
{
  "inputText": "stripe.com, notion.so, charitywater.org, basecamp.com",
  "onlyWithEmails": true
}
```

**2. Verified, deliverability-graded emails (bounded spend)**

```json
{
  "websites": ["apify.com", "stripe.com", "charitywater.org"],
  "verifyEmails": true,
  "maxVerifiedEmailsPerSite": 3
}
```

**3. Monetization-qualified leads**

```json
{
  "websites": ["charitywater.org", "patagonia.com", "moz.com"],
  "qualifyByPayment": true,
  "onlyWithEmails": false
}
```

### Output Overview

Each dataset item is one website row containing:

- **Identity** — `website` (as you entered it), `domain` (normalized), `resolvedWebsite`
- **Emails** — `email` (best), `emails` (ranked list), `emailCount`, plus `source` (`site-scrape` / `hunter` / `none`) and `confidence` (`high` / `medium` / `low`)
- **Phones** — `phone` (first), `phones`, `phoneCount`
- **Socials** — `socials` keyed by network (linkedin / twitter / instagram / facebook / youtube / tiktok), `socialCount`
- **Verification** (when `verifyEmails` is on) — `emailVerifications` per address, `validEmails`, `validEmailCount`, `bestValidEmail`
- **Payment qualification** (when `qualifyByPayment` is on) — `takesPayments`, `paymentProcessors`, `stripeLiveKey`, `paymentConfidence`
- **Scoring** — `leadScore` (0–100), `leadSignals` (which signals fired)

Sites that publish no email still emit a row (unless `onlyWithEmails` is set) — often with phones and socials that make the lead workable anyway.

### Output Samples

#### Full-signal row (verification + payment detection on)

```jsonc
{
  "website": "charitywater.org",
  "domain": "charitywater.org",
  "resolvedWebsite": "https://charitywater.org",
  "email": "info@charitywater.org",
  "emails": ["info@charitywater.org", "team@charitywater.org"],
  "emailCount": 2,
  "phone": "6466882323",
  "phones": ["6466882323", "9293674827"],
  "phoneCount": 2,
  "socials": {
    "twitter": ["https://twitter.com/charitywater"],
    "facebook": ["https://facebook.com/charitywater"],
    "instagram": ["https://instagram.com/charitywater"],
    "youtube": ["https://youtube.com/user/charitywater"],
    "linkedin": ["https://linkedin.com/company/charity-water"]
  },
  "socialCount": 5,
  "source": "site-scrape",
  "confidence": "high",
  "emailVerifications": [
    {
      "email": "info@charitywater.org",
      "syntaxValid": true,
      "mxFound": true,
      "isDisposable": false,
      "isRoleBased": true,
      "isFreeProvider": false,
      "verdict": "risky"
    }
    /* one entry per verified email */
  ],
  "takesPayments": true,
  "paymentProcessors": ["stripe", "shopify", "paypal"],
  "stripeLiveKey": "pk_live_…",
  "paymentConfidence": "high",
  "leadScore": 69,
  "leadSignals": ["emailPresent", "emailDomainMatch", "emailProviderBusiness", "phonePresent", "websitePresent", "socialAny"],
  "scrapedAt": "2026-08-08T14:06:46.631Z"
}
```

#### Row where the site publishes no email

```jsonc
{
  "website": "lagovistafamilydentistry.com",
  "domain": "lagovistafamilydentistry.com",
  "emails": [],
  "emailCount": 0,
  "phone": "5122773311",
  "phones": ["5122773311", "5123797704"],
  "phoneCount": 2,
  "socials": {},
  "source": "none",
  "confidence": "low",
  "leadScore": 20,
  "leadSignals": ["phonePresent", "websitePresent"]
}
```

### Key Output Fields

#### Identity

- `website`, `domain`, `resolvedWebsite`, `scrapedAt`

#### Emails & Verification

- `email`, `emails[]`, `emailCount`, `source`, `confidence`
- `emailVerifications[]` — `syntaxValid`, `mxFound`, `isDisposable`, `isRoleBased`, `isFreeProvider`, `verdict` (`valid` / `risky` / `invalid`)
- `validEmails[]`, `validEmailCount`, `bestValidEmail`

#### Phones & Socials

- `phone`, `phones[]`, `phoneCount`
- `socials.{linkedin,twitter,instagram,facebook,youtube,tiktok}[]`, `socialCount`

#### Payment Qualification

- `takesPayments`, `paymentProcessors[]`, `stripeLiveKey`, `paymentConfidence`

#### Lead Scoring

- `leadScore` (0–100), `leadSignals[]`

### FAQ

#### Which pages does the actor fetch per website?

The homepage plus common contact-bearing paths (contact, about, team and similar). With `qualifyByPayment` on, checkout-related paths (pricing, cart, shop) are also probed so checkout-only payment processors are caught.

#### Will every website return an email?

No. Many sites — especially large brands — publish no address anywhere and route everything through a form. Those rows still return phones and socials when present. If you only want (and only want to pay for) rows with an email, set `onlyWithEmails: true`.

#### What do the verification verdicts mean?

`valid` = syntax OK, the domain accepts mail, and the address isn't disposable, role-based, or on a free provider. `risky` = deliverable but role-based (info@, team@) or on a free provider — fine for many outreach flows, flagged so you can decide. `invalid` = failed syntax or MX. Verification is DNS/list-based; it does not do live SMTP mailbox probing.

#### I have input formatted for another website-email actor — will it work here?

Yes. The actor accepts `startUrls` (strings or `{"url": ...}` objects) alongside its own `websites` field, so you can paste the same input you used elsewhere.

#### Do duplicate entries get billed twice?

No. Entries are normalized (scheme, `www.`, path, casing stripped) before billing, so `stripe.com` and `https://www.Stripe.com/` count once.

#### Can it scrape emails behind a login?

No. Only publicly reachable pages are fetched — no authenticated endpoints, no paywalled content.

#### What about JavaScript-heavy sites?

The crawler reads server-rendered HTML. Sites that render every byte client-side may yield fewer contacts; in practice most business sites expose contact details in the initial HTML.

#### Do I need my own proxies?

No — runs are routed through the actor's built-in residential proxy at no extra cost. You can override with your own proxy configuration if you prefer.

### Support

- **Found a bug or need a new field?** Open a ticket on the **Issues** tab of this actor — it's the fastest way to reach me and I actively maintain this actor.
- **Email:** <muhamed.didovic@gmail.com>
- **Website:** [muhamed-didovic.github.io](https://muhamed-didovic.github.io/)

### Additional Services

Need something beyond the standard output? I build and maintain custom actors and data pipelines. Happy to help with:

- Person-level contact discovery (names, titles, LinkedIn profiles) on top of these rows
- Scheduled monitoring runs with change detection
- Custom export shapes or direct delivery to your CRM / webhook

Drop me a line at <muhamed.didovic@gmail.com>.

### Explore More Scrapers

If you found this useful, you might also like:

- [**Email Finder & Verifier**](https://apify.com/memo23/email-finder) — person-level lookups, name→domain discovery, and who-works-there discovery mode
- [**Europages B2B Scraper**](https://apify.com/memo23/europages-scraper) — European company data with emails and VAT IDs
- [**Yelp Leads & Business Scraper**](https://apify.com/memo23/yelp-scraper) — local business leads with emails and AI insights
- [**LinkedIn Company Employees Scraper**](https://apify.com/memo23/linkedin-company-employees-scraper) — employees + email finder, no login

Full list at [apify.com/memo23](https://apify.com/memo23).

### 🤖 For AI Agents & LLM Apps

Compact reference for AI agents calling this actor via the [Apify MCP server](https://mcp.apify.com) or the Apify API (actor: `memo23/website-email-scraper`).

**Purpose:** bulk-crawl a list of websites for contact data — one row per site with ranked emails, phones, social profiles, optional MX verification, optional payment-stack detection, and a 0–100 lead score.

**Minimal input:**

```json
{ "websites": ["apify.com"], "maxItems": 10 }
```

**Output:** one dataset row per website — `website`, `domain`, `resolvedWebsite`, `email`, `emails[]`, `emailCount`, `phone`, `phones[]`, `phoneCount`, `socials {linkedin, twitter, instagram, facebook, youtube, tiktok}`, `socialCount`, `source`, `confidence`, `leadScore`, `leadSignals[]`, plus `emailVerifications[]` / `validEmails[]` when `verifyEmails` is on and `takesPayments` / `paymentProcessors[]` when `qualifyByPayment` is on.

**Behaviors an agent should know:**

- Always set `maxItems` — an uncapped run processes every entry supplied.
- Input is deduplicated by normalized domain before billing; `startUrls` (strings or `{url}` objects) and `inputText` blobs are accepted and merged into `websites`.
- Billing: $0.004 per website row emitted (`website-scraped`); with `verifyEmails` on, $0.001 per email verified (`emails-verified`). `onlyWithEmails: true` means rows without emails are neither emitted nor charged. `qualifyByPayment` is free.
- Free (non-paying) accounts are capped at 25 websites per run.
- No login-gated content; JS-only sites may yield fewer contacts; sites with no published email return `emails: []` with `source: "none"`.

***

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by any of the websites it is pointed at. All trademarks, brand names, and logos mentioned or encountered belong to their respective owners.

The scraper accesses only publicly available web pages — no authenticated endpoints, paid features, or content behind a login wall. Users are responsible for ensuring that their use of the extracted data complies with the target websites' Terms of Service, applicable data-protection and anti-spam law (GDPR, CCPA, CAN-SPAM, PECR, etc.), and any contractual obligations of their own organization. Contact data should be used responsibly and lawfully.

***

### SEO Keywords

website email scraper, email scraper, scrape emails from website, email extractor, bulk email finder, contact scraper, website contact extractor, email crawler, contact information scraper, lead generation scraper, b2b lead generation data, email list building, CRM enrichment, phone number scraper, social media links scraper, email verification MX check, ecommerce leads Stripe detection, sales prospecting data, cold outreach email list, Apify email scraper, email finder API

# Actor input Schema

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

Websites to scrape for contacts — one URL or domain per entry, e.g. stripe.com or https://stripe.com. Each site's homepage and contact/about/team pages are crawled directly and every email, phone number and social profile found is returned in one row per site.

## `inputText` (type: `string`):

Alternative — paste a blob of URLs or domains separated by new lines, commas, or semicolons. Merged with the Websites field above. Duplicates (with/without www, http, trailing slash) are detected and billed once.

## `onlyWithEmails` (type: `boolean`):

Emit only rows where at least one email was found — so you pay only for successful hits.

## `verifyEmails` (type: `boolean`):

Validate every email found: checks syntax, looks up the domain's MX record (does it accept mail?), and flags disposable, role-based (info@, sales@) and free-provider (gmail, etc.) addresses. Adds an `emailVerifications` array plus `validEmails`, `validEmailCount` and `bestValidEmail` — deliverable addresses, not just candidates. (DNS/list-based validation; no live SMTP mailbox probing.) Billed per email verified.

## `maxVerifiedEmailsPerSite` (type: `integer`):

Optional ceiling on how many emails are verified per site. Verification is billed per email, and one site can legitimately expose dozens of addresses — this bounds that spend. Emails beyond the ceiling are still returned, just unverified and unbilled. Leave empty to verify everything found.

## `qualifyByPayment` (type: `boolean`):

Scans each website — reusing the pages already fetched for contact discovery, so no extra cost or time — for payment processors and e-commerce platforms (Stripe, Shopify, PayPal, Paddle, Lemon Squeezy, WooCommerce, Square, Chargebee and more). Adds `takesPayments`, `paymentProcessors`, `stripeLiveKey` (the public key if exposed) and `paymentConfidence`. Turn raw contacts into monetization-qualified leads at no extra charge.

## `hunterApiKey` (type: `string`):

Optional — supply your own Hunter.io key to enable a paid domain-search fallback when the site scrape finds no emails. Leave empty to use the free site-scrape path only.

## `maxItems` (type: `integer`):

Hard cap on how many websites this run processes. Free plans are capped at 25.

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

How many websites to scrape in parallel.

## `proxy` (type: `object`):

Leave empty — the actor already routes all traffic through its own built-in residential proxy at no extra cost to you. Only set this if you want to use your own proxies.

## Actor input object example

```json
{
  "websites": [
    "apify.com",
    "stripe.com",
    "charitywater.org"
  ],
  "onlyWithEmails": false,
  "verifyEmails": false,
  "qualifyByPayment": false,
  "maxItems": 100000,
  "maxConcurrency": 10
}
```

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

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/website-email-scraper").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": [
        "apify.com",
        "stripe.com",
        "charitywater.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("memo23/website-email-scraper").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": [
    "apify.com",
    "stripe.com",
    "charitywater.org"
  ]
}' |
apify call memo23/website-email-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/website-email-scraper"
        }
    }
}

```

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/d85T7R1jqBa56pswi/builds/rE91anoGHtqcMLA2t/openapi.json
