# Website Contact Scraper — Emails, Phones & Social Media (`extractmaster01/website-contact-scraper`) Actor

Email extractor and B2B lead scraper. Crawls any website and extracts emails, phone numbers, and 14 social media profiles (LinkedIn, Twitter/X, Instagram, Facebook, WhatsApp, Telegram, Discord, TikTok, YouTube, Pinterest, Snapchat, Reddit, Threads, GitHub). Pay per email found — no wasted spend.

- **URL**: https://apify.com/extractmaster01/website-contact-scraper.md
- **Developed by:** [extractmaster01](https://apify.com/extractmaster01) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 email 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 Contact Scraper — Extract Emails, Phone Numbers & Social Media Profiles

**Website Contact Scraper** crawls any website and extracts the full contact profile for every domain: emails, phone numbers, physical address, company name, and 14 social media platforms. Give it a list of URLs and get back a clean dataset ready to import into any CRM or spreadsheet. No subscriptions.

⚡ **[TRY IT FOR FREE](https://console.apify.com/actors/sQiQwjhPWAqX5Nfbo)**

---

### What data can Website Contact Scraper extract?

| Data type | Details |
|---|---|
| 📧 Email addresses | Deduplicated per domain, quality-filtered, Cloudflare obfuscation decoded, `[at]`/`(at)` obfuscation decoded, optional MX validation |
| 📞 Phone numbers | High-confidence (`phones`) from `tel:` links + lower-confidence (`possiblePhones`) from page text. US and international formats. |
| 🏢 Company name | Extracted from `og:site_name` and `application-name` meta tags |
| 📍 Physical address | Extracted from Schema.org `PostalAddress` JSON-LD or HTML microdata |
| 📄 Page context | `pageTitle` and `pageDescription` of the page where each email was found (per-email mode) |
| 💼 LinkedIn | Company and personal profiles |
| 🐦 Twitter / X | Brand and personal handles |
| 📸 Instagram | Business and creator profiles |
| 📘 Facebook | Pages and business profiles |
| ▶️ YouTube | Brand channels |
| 🎵 TikTok | Brand and creator profiles |
| 💻 GitHub | Organization profiles, user profiles, and repositories |
| 💬 WhatsApp | Business numbers, direct links, and WhatsApp Channels |
| ✈️ Telegram | Channels, groups, and user profiles |
| 🎮 Discord | Server invite links |
| 📌 Pinterest | Brand profiles |
| 👻 Snapchat | Public profiles |
| 🧵 Threads | Public profiles |
| 👥 Reddit | Subreddits and user pages |

---

### Why use Website Contact Scraper?

Most contact scrapers return only emails or lock you into a monthly subscription. This one returns the full contact profile for every domain — including address, company name, and 14 social platforms — and you only pay for what the Actor actually finds.

| Feature | This Actor | Email-only scrapers | $10–$20/mo scrapers |
|---|---|---|---|
| Email addresses | ✅ | ✅ | ✅ |
| Phone numbers | ✅ | ❌ | ✅ |
| 14 social platforms | ✅ | ❌ | ✅ |
| Company name | ✅ | ❌ | ❌ |
| Physical address | ✅ | ❌ | ❌ |
| Page title & description | ✅ | ❌ | ❌ |
| Email domain validation | ✅ | ❌ | Paid add-on |
| Contact page auto-discovery | ✅ | ❌ | ❌ |
| Cloudflare + `[at]` email decode | ✅ | ❌ | ❌ |
| Pay per event (no subscription) | ✅ | Some | ❌ |
| Per-email and per-domain output | ✅ | ❌ | ❌ |

---

### How to scrape contact information from any website

1. **Create a free Apify account** using your email.
2. **Open Website Contact Scraper** and go to the Input tab.
3. **Add your URLs** — one domain per entry. Duplicates are handled automatically.
4. **Pick an output mode** — `per-email` for CRM import or `per-domain` to get everything grouped by site.
5. **Click Start** — the Actor automatically discovers contact pages and crawls up to the configured depth.
6. **Download your data** as JSON, CSV, Excel, XML, or HTML, or connect via API.

```json
{
  "urls": [
    { "url": "https://company1.com" },
    { "url": "https://company2.com" },
    { "url": "https://company3.com" }
  ],
  "contactPagesOnly": true,
  "outputMode": "per-domain"
}
````

***

### How much does it cost to scrape emails from websites?

Website Contact Scraper uses the **pay-per-event (PPE)** pricing model — no subscription, no monthly fee. You pay only for what the Actor actually does. Check the **[Pricing tab](https://apify.com/extractmaster01/website-contact-scraper/pricing)** for the full event list.

There are two billable events:

| Event | Price | When it fires |
|---|---|---|
| `domain-processed` | $0.01 | Once per domain, when the first page loads successfully. Does not fire if all pages are blocked (`status: "blocked"`) or the site is a JS-only SPA (`status: "js-only"`). |
| `email-found` | $0.004 | Once per unique email found. Does not fire if no emails are found. |

**Estimated cost by batch size** (assuming ~2 emails per domain on average):

| Domains | Emails found | Estimated cost |
|---|---|---|
| 10 | ~20 | ~$0.18 |
| 50 | ~100 | ~$0.90 |
| 100 | ~200 | ~$1.80 |
| 500 | ~1,000 | ~$9.00 |
| 1,000 | ~2,000 | ~$18.00 |

You are not charged for sites that cannot be scraped. Domains that require residential proxies may incur additional platform proxy usage costs.

To control costs, use `maxEmailsPerDomain` to cap emails per site and `maxPagesPerDomain` to limit the number of pages crawled per domain.

***

### ⚙️ Input parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `urls` | array | required | Website URLs to crawl |
| `outputMode` | string | `per-email` | `per-email`: one row per email (includes `pageTitle` + `pageDescription`) · `per-domain`: all contacts grouped |
| `maxEmailsPerDomain` | integer | 0 | Global email cap per domain — cost control (0 = unlimited) |
| `maxPagesPerDomain` | integer | 0 | Max pages to crawl per domain — cost control (0 = unlimited) |
| `crawlDepth` | integer | 2 | How deep to follow links (1–5) |
| `contactPagesOnly` | boolean | true | Only visit contact-related pages (faster, cheaper) |
| `extractPhones` | boolean | true | Extract phone numbers |
| `extractSocials` | boolean | true | Extract 14 social profiles |
| `extractAddress` | boolean | true | Extract physical address via Schema.org |
| `validateEmails` | boolean | false | DNS MX check — filters dead email domains |
| `includeDebugInfo` | boolean | false | Add `debugInfo` array to output for troubleshooting |
| `proxyConfiguration` | object | Apify Proxy | Pass `null` for direct mode (no proxy) |

For the full input reference, see the **Input tab**.

***

### 📊 Output examples

#### `outputMode: "per-email"` — one row per email (CRM-ready)

Best for importing directly into HubSpot, Salesforce, Apollo, or any sequencer. Every row includes the email, which page it came from, company name, address, phones, and social profiles.

```json
{
  "sourceUrl": "https://acme.com",
  "domain": "acme.com",
  "companyName": "Acme Corp",
  "address": "123 Main St, San Francisco, CA 94105, US",
  "pageUrl": "https://acme.com/contact",
  "pageTitle": "Contact Us — Acme Corp",
  "pageDescription": "Get in touch with our sales and support teams.",
  "email": "sales@acme.com",
  "phones": ["+1-555-0123"],
  "possiblePhones": [],
  "socials": {
    "linkedin": "https://linkedin.com/company/acme",
    "twitter": "https://x.com/acmecorp",
    "instagram": null,
    "facebook": "https://facebook.com/acmecorp",
    "youtube": null,
    "tiktok": null,
    "github": null,
    "whatsapp": "https://wa.me/15550123",
    "telegram": null,
    "discord": null,
    "pinterest": null,
    "snapchat": null,
    "reddit": null,
    "threads": null
  },
  "scrapedAt": "2026-06-04T10:00:00.000Z"
}
```

#### `outputMode: "per-domain"` — all contacts grouped

One row per domain with all emails, phones, address, company name, and socials found across every page visited.

```json
{
  "sourceUrl": "https://acme.com",
  "domain": "acme.com",
  "companyName": "Acme Corp",
  "address": "123 Main St, San Francisco, CA 94105, US",
  "emails": ["sales@acme.com", "info@acme.com", "support@acme.com"],
  "phones": ["+1-555-0123", "+1-555-9876"],
  "possiblePhones": ["(800) 555-9876"],
  "socials": {
    "linkedin": "https://linkedin.com/company/acme",
    "twitter": "https://x.com/acmecorp",
    "instagram": null,
    "facebook": "https://facebook.com/acmecorp",
    "youtube": null,
    "tiktok": null,
    "github": null,
    "whatsapp": "https://wa.me/15550123",
    "telegram": null,
    "discord": null,
    "pinterest": null,
    "snapchat": null,
    "reddit": null,
    "threads": null
  },
  "pagesScanned": 3,
  "status": "success",
  "scrapedAt": "2026-06-04T10:00:00.000Z"
}
```

The `status` field tells you what happened per domain:

| Value | Meaning |
|---|---|
| `success` | Contacts found, no pages were blocked |
| `partial` | Contacts found, but some pages were blocked by bot protection |
| `empty` | Crawled OK but no contacts found (contact form only, or genuinely no public email) |
| `blocked` | All pages were blocked — no data collected |
| `js-only` | Site renders content via JavaScript (SPA/React/Vue) — no static HTML contact data found |

You can download the dataset as JSON, CSV, Excel, XML, or HTML from the dataset view.

***

### 🤔 Which output mode should I use?

**Use `per-email` if you are:**

- Importing contacts into a CRM (HubSpot, Salesforce, Apollo, Instantly)
- Running an email outreach sequence
- Working with tools that expect one row = one contact

Every row has the email, the page it came from (`pageUrl`, `pageTitle`, `pageDescription`), and all the domain's phones and social profiles attached. If a domain has 3 emails, you get 3 rows — one per contact, ready to import.

**Use `per-domain` if you are:**

- Building a spreadsheet or report where the company is the unit
- Enriching an existing account list (you already have the company, you want to fill in missing fields)
- Running market research or competitive analysis across many domains

Every row has all emails as an array, all phones, and all socials grouped under one domain. One domain = one row, no matter how many emails were found.

| | `per-email` | `per-domain` |
|---|---|---|
| Row unit | One email | One domain |
| CRM import | ✅ Direct | ❌ Needs processing |
| Spreadsheet analysis | ⚠️ Repeated rows per domain | ✅ Clean |
| `pageTitle` / `pageDescription` | ✅ Yes | ❌ No |
| Multiple emails per domain | Multiple rows | Single row, array |

***

### 💡 Use cases for website contact scraping

**B2B sales prospecting** — Turn a list of target domains into a contact file ready to import, with email, phone, LinkedIn, and company address in every row.

**Agency lead generation** — Find contacts at target companies by category and city, at scale.

**CRM enrichment** — Fill missing email, phone, address, and social fields for existing accounts in bulk.

**Recruiting** — Collect contact info from company career and team pages.

**Partnership outreach** — Extract contacts from potential partners, resellers, or integration targets.

**Competitor research** — Map the social media presence and contact points of competitors.

***

### 🔗 Integrations

You can integrate Website Contact Scraper with almost any cloud service or web app. The Apify platform has built-in integrations, a full REST API, scheduling, and webhook support.

- **Make / Zapier** — trigger workflows when new contacts are found
- **Google Sheets** — direct dataset export
- **HubSpot / Salesforce / Apollo** — import CSV or use the API
- **Webhooks** — get notified when a run completes
- **Apify API** — `apify-client` for Node.js and Python
- **MCP Server** — use this Actor directly inside Claude or any MCP-compatible client

***

### ❓ Frequently asked questions

#### Does Website Contact Scraper work on all websites?

It works on most contact, about, and team pages since these are almost always static HTML. For sites that require JavaScript to render content, the Actor detects this and marks the domain as `status: "js-only"` in the output.

#### Why didn't it find emails on a specific site?

The most common causes are: emails only visible after a form submission, domain blocking datacenter IPs, or a JavaScript-rendered site. Check the `status` field in per-domain mode — `blocked` means IPs were rejected, `js-only` means the site requires a browser. Enable `includeDebugInfo: true` in the input to get detailed reason codes in the output.

#### What is `possiblePhones`?

`possiblePhones` contains phone numbers extracted from visible page text via regex — lower confidence than `phones`, which come from `tel:` href links. Numbers in `possiblePhones` may include false positives like order IDs or dates. Use `phones` for outreach and `possiblePhones` as a fallback.

#### How does address extraction work?

The Actor looks for Schema.org `PostalAddress` data in JSON-LD blocks (the structured data search engines use). If not found, it falls back to HTML microdata (`itemprop="streetAddress"`). Sites that don't publish structured data will return `address: null`. You can disable extraction with `extractAddress: false`.

#### How do I extract emails from multiple websites at once?

Add all your URLs to the `urls` array. Each domain is processed independently and results are deduplicated automatically.

#### Can I use Website Contact Scraper with the Apify API?

Yes. The Apify API lets you run the Actor, retrieve datasets, schedule runs, and set up webhooks. Use the `apify-client` package for Node.js or Python. See the **API tab** for the full reference.

#### Is it legal to scrape contact information from websites?

Scraping publicly available contact information is generally legal, but you should check compliance with GDPR, CAN-SPAM, and the terms of service of each website before using the data for outreach.

#### What does email validation do?

When `validateEmails: true`, each email domain is checked for a valid MX record via DNS. Domains without one are discarded, which filters out dead domains and placeholder addresses. This adds ~100ms per unique email domain.

***

### Your feedback

If you found a bug or have a feature request, please create an issue in the [Issues tab](https://apify.com/extractmaster01/website-contact-scraper/issues/open).

***

### You might also like

**[Apify Store Scraper](https://apify.com/extractmaster01/apify-store-scraper)** — scrapes all 26,000+ Actors on the Apify Store. Useful for market research and competitor tracking.

# Actor input Schema

## `urls` (type: `array`):

List of website URLs to crawl for contact information. Each unique domain is deduplicated automatically.

## `outputMode` (type: `string`):

per-email: one row per email found (easy to process in CRMs). per-domain: one row per domain with all contacts grouped (easier to read).

## `maxEmailsPerDomain` (type: `integer`):

Maximum unique emails to collect per seed domain. 0 = unlimited.

## `maxPagesPerDomain` (type: `integer`):

Maximum number of pages to crawl per domain. Useful to control cost on large sites. 0 = unlimited.

## `crawlDepth` (type: `integer`):

How many levels of internal links to follow. 1 = seed URL only. 2 = seed + linked pages (recommended). 3+ = deeper crawl.

## `contactPagesOnly` (type: `boolean`):

Only crawl pages with contact-related paths (/contact, /about, /team, /support, etc.). Faster, cheaper, and finds more emails per page crawled.

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

Extract phone numbers from pages (US and international formats). Included in every row at no extra cost.

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

Extract links to LinkedIn, Twitter/X, Instagram, Facebook, YouTube, TikTok, GitHub, WhatsApp, Telegram, Discord, Pinterest, Snapchat, Reddit, and Threads.

## `extractAddress` (type: `boolean`):

Extract physical address from Schema.org JSON-LD (PostalAddress) or HTML microdata. Useful for local business prospecting.

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

Verify that each email's domain has a valid MX record (DNS lookup). Filters out dead domains and placeholder emails. Adds ~100ms per unique domain.

## `includeDebugInfo` (type: `boolean`):

Add a debugInfo array to each result with internal crawl diagnostics (e.g. cloudflare-challenge-detected, js-only-page). Useful for troubleshooting. Off by default.

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

Apify proxy settings for rotating IPs. Leave default for automatic datacenter proxy rotation. Pass null for direct mode (no proxy).

## Actor input object example

```json
{
  "urls": [
    {
      "url": "https://apify.com"
    }
  ],
  "outputMode": "per-email",
  "maxEmailsPerDomain": 0,
  "maxPagesPerDomain": 0,
  "crawlDepth": 2,
  "contactPagesOnly": true,
  "extractPhones": true,
  "extractSocials": true,
  "extractAddress": true,
  "validateEmails": false,
  "includeDebugInfo": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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 = {
    "urls": [
        {
            "url": "https://apify.com"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("extractmaster01/website-contact-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 = {
    "urls": [{ "url": "https://apify.com" }],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("extractmaster01/website-contact-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    {
      "url": "https://apify.com"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call extractmaster01/website-contact-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=extractmaster01/website-contact-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Website Contact Scraper — Emails, Phones & Social Media",
        "description": "Email extractor and B2B lead scraper. Crawls any website and extracts emails, phone numbers, and 14 social media profiles (LinkedIn, Twitter/X, Instagram, Facebook, WhatsApp, Telegram, Discord, TikTok, YouTube, Pinterest, Snapchat, Reddit, Threads, GitHub). Pay per email found — no wasted spend.",
        "version": "0.0",
        "x-build-id": "EySR3bExt2D2e8nqs"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/extractmaster01~website-contact-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-extractmaster01-website-contact-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/extractmaster01~website-contact-scraper/runs": {
            "post": {
                "operationId": "runs-sync-extractmaster01-website-contact-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/extractmaster01~website-contact-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-extractmaster01-website-contact-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "urls"
                ],
                "properties": {
                    "urls": {
                        "title": "URLs to scrape",
                        "type": "array",
                        "description": "List of website URLs to crawl for contact information. Each unique domain is deduplicated automatically.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "outputMode": {
                        "title": "Output mode",
                        "enum": [
                            "per-email",
                            "per-domain"
                        ],
                        "type": "string",
                        "description": "per-email: one row per email found (easy to process in CRMs). per-domain: one row per domain with all contacts grouped (easier to read).",
                        "default": "per-email"
                    },
                    "maxEmailsPerDomain": {
                        "title": "Max emails per domain",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum unique emails to collect per seed domain. 0 = unlimited.",
                        "default": 0
                    },
                    "maxPagesPerDomain": {
                        "title": "Max pages per domain",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of pages to crawl per domain. Useful to control cost on large sites. 0 = unlimited.",
                        "default": 0
                    },
                    "crawlDepth": {
                        "title": "Crawl depth",
                        "minimum": 1,
                        "maximum": 5,
                        "type": "integer",
                        "description": "How many levels of internal links to follow. 1 = seed URL only. 2 = seed + linked pages (recommended). 3+ = deeper crawl.",
                        "default": 2
                    },
                    "contactPagesOnly": {
                        "title": "Contact pages only (recommended)",
                        "type": "boolean",
                        "description": "Only crawl pages with contact-related paths (/contact, /about, /team, /support, etc.). Faster, cheaper, and finds more emails per page crawled.",
                        "default": true
                    },
                    "extractPhones": {
                        "title": "Extract phone numbers",
                        "type": "boolean",
                        "description": "Extract phone numbers from pages (US and international formats). Included in every row at no extra cost.",
                        "default": true
                    },
                    "extractSocials": {
                        "title": "Extract social media profiles",
                        "type": "boolean",
                        "description": "Extract links to LinkedIn, Twitter/X, Instagram, Facebook, YouTube, TikTok, GitHub, WhatsApp, Telegram, Discord, Pinterest, Snapchat, Reddit, and Threads.",
                        "default": true
                    },
                    "extractAddress": {
                        "title": "Extract physical address",
                        "type": "boolean",
                        "description": "Extract physical address from Schema.org JSON-LD (PostalAddress) or HTML microdata. Useful for local business prospecting.",
                        "default": true
                    },
                    "validateEmails": {
                        "title": "Validate email domains (MX check)",
                        "type": "boolean",
                        "description": "Verify that each email's domain has a valid MX record (DNS lookup). Filters out dead domains and placeholder emails. Adds ~100ms per unique domain.",
                        "default": false
                    },
                    "includeDebugInfo": {
                        "title": "Include debug info in output",
                        "type": "boolean",
                        "description": "Add a debugInfo array to each result with internal crawl diagnostics (e.g. cloudflare-challenge-detected, js-only-page). Useful for troubleshooting. Off by default.",
                        "default": false
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Apify proxy settings for rotating IPs. Leave default for automatic datacenter proxy rotation. Pass null for direct mode (no proxy)."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
