# Website Contact & Email Extractor – Emails, Phones, Socials (`ninhothedev/website-contact-extractor`) Actor

Extract emails, phone numbers and LinkedIn, Facebook, X, Instagram, YouTube & TikTok links from any list of websites, incl. contact/about pages. For B2B lead gen, sales & CRM enrichment.

- **URL**: https://apify.com/ninhothedev/website-contact-extractor.md
- **Developed by:** [ninhothedev](https://apify.com/ninhothedev) (community)
- **Categories:** Lead generation, Automation, SEO tools
- **Features:** Limited permissions
- **Stats:** 5 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 results

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/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 Contact & Email Extractor – Emails, Phones & Social Links in Bulk

**Website Contact & Email Extractor** visits a list of company websites and pulls out every **published email address**, **phone number** and **social media profile** (LinkedIn, Facebook, X/Twitter, Instagram, YouTube, TikTok, Pinterest). It checks the homepage and automatically follows up to 4 **contact, about, team, imprint or impressum pages** on the same site, then returns **one clean row per website** that you can export to CSV, Excel, JSON or Google Sheets. No API key, no browser extension, and you pay only per website delivered.

Built for B2B lead generation, sales and marketing teams, agencies enriching prospect lists, recruiters and researchers who need contact details for hundreds of domains without copying them by hand.

### What data can you extract?

| Field | Example | Description |
|---|---|---|
| `url` | `https://www.eff.org/` | Website you asked to check (normalized) |
| `domain` | `eff.org` | Hostname without `www.` |
| `title` | `Electronic Frontier Foundation \| Defending your rights…` | Homepage `<title>` |
| `emails` | `["info@eff.org", "press@eff.org"]` | Deduplicated, lowercased emails from mailto links and page text (`null` if none) |
| `phones` | `["+1-510-243-8020", "(415) 436-9333"]` | Phone candidates from `tel:` links and international/bracketed numbers in text |
| `linkedin` | `https://www.linkedin.com/company/EFF` | Company LinkedIn profile |
| `facebook` | `https://www.facebook.com/eff` | Facebook page |
| `twitter` | `https://twitter.com/ThePSF` | X / Twitter profile |
| `instagram` | `https://www.instagram.com/efforg/` | Instagram profile |
| `youtube` | `https://www.youtube.com/efforg` | YouTube channel |
| `tiktok` / `pinterest` | `https://www.tiktok.com/@efforg` | TikTok and Pinterest profiles |
| `status` | `ok` | `ok` = contacts found, `empty` = no contacts, `partial` = a follow-up page failed or more contact pages existed than were checked |
| `pages_crawled` | `5` | Pages successfully inspected for this website |
| `source_pages` | `["https://www.eff.org/about/contact", …]` | Exact pages the contacts were collected from |
| `errors` | `[]` | Follow-up pages that could not be loaded |
| `scraped_at` | `2026-10-15T18:02:12+00:00` | UTC time of extraction |

Each row also contains `id`, `source_url`, `pages_attempted`, `coverage_limited` and `crawl_contact_pages` for auditing.

### How to use the Website Contact Extractor

1. Paste your websites into **Website URLs** – full URLs (`https://www.example.com/`) or bare domains (`example.com`). One row is produced per website; `www.` and HTTP/HTTPS duplicates of the same hostname are merged.
2. Keep **Crawl contact / about pages** enabled to also scan up to 4 contact, about, team or imprint pages per site, and set **Max websites** to the number of sites you want processed.
3. Click **Start**, then download the results as CSV, Excel, JSON or HTML, or send them to Google Sheets, your CRM, Make, Zapier or n8n.

Example input:

```json
{
  "startUrls": ["https://www.eff.org/", "python.org", "https://www.fsf.org/"],
  "crawlContactPages": true,
  "maxItems": 100
}
```

### Output example

Real output from a local test run (email and phone lists shortened):

```json
[
  {
    "url": "https://www.eff.org/",
    "domain": "eff.org",
    "title": "Electronic Frontier Foundation | Defending your rights in the digital world",
    "emails": ["info@eff.org", "press@eff.org", "membership@eff.org", "activist@eff.org"],
    "phones": ["+1-510-243-8020", "(415) 436-9333", "+1-415-436-9333"],
    "facebook": "https://www.facebook.com/eff",
    "twitter": null,
    "linkedin": "https://www.linkedin.com/company/EFF",
    "instagram": "https://www.instagram.com/efforg/",
    "youtube": "https://www.youtube.com/efforg",
    "tiktok": "https://www.tiktok.com/@efforg",
    "pinterest": null,
    "pages_crawled": 5,
    "scraped_at": "2026-10-15T18:02:12.999643+00:00",
    "id": "website:ed4fd82507666e35cf54a5d36cd67e0f6d3475a14c025f24232c2a30fa27ec70",
    "source_url": "https://www.eff.org/",
    "status": "partial",
    "pages_attempted": 5,
    "source_pages": [
      "https://www.eff.org/",
      "https://www.eff.org/about",
      "https://www.eff.org/about/contact",
      "https://www.eff.org/press/contact",
      "https://www.eff.org/about/staff"
    ],
    "errors": [],
    "coverage_limited": true,
    "crawl_contact_pages": true
  },
  {
    "url": "https://www.python.org/",
    "domain": "python.org",
    "title": "Welcome to Python.org",
    "emails": null,
    "phones": null,
    "twitter": "https://twitter.com/ThePSF",
    "linkedin": "https://www.linkedin.com/company/python-software-foundation/",
    "pages_crawled": 5,
    "status": "partial",
    "coverage_limited": true
  }
]
```

Websites with no published contacts still get a row (`status: "empty"`), so you can see exactly which domains were checked. A homepage that cannot be loaded at all is not billed and is listed in the `RUN_SUMMARY` record of the run's key-value store.

### Pricing

This actor uses **pay-per-event** pricing – you pay only for websites delivered to the dataset:

- **$0.002 per website** (one result row, however many emails/phones it contains)
- **$2.00 per 1,000 websites**
- **$0.00005 per actor start**

| Scenario | Cost |
|---|---:|
| 100 websites, one run | ≈ $0.20 |
| 1,000 websites, one run | ≈ $2.00 |
| 10,000 websites (lead list enrichment) | ≈ $20.00 |
| 500 websites re-checked weekly for a month (4 runs) | ≈ $4.00 |

No proxies or paid third-party APIs are used, so there are no hidden extra costs. Use **Max websites** and Apify's *maximum cost per run* setting to cap spending.

### Use cases

- **B2B lead generation** – turn a list of company domains into emails, phone numbers and LinkedIn pages for outreach.
- **CRM enrichment** – fill missing contact and social fields for accounts already in HubSpot, Salesforce or Pipedrive.
- **Agency prospecting** – collect contact details of local businesses, shops or SaaS companies found via directories or Google Maps.
- **Partner and supplier research** – find the right press, sales or info mailbox for hundreds of vendors at once.
- **Social media audits** – check which brands link to LinkedIn, Instagram, TikTok or YouTube from their website.
- **Data quality checks** – verify that the contact details published on your own websites are complete and consistent.

### Integrations and API

Run the contact extractor from the Apify API, CLI or any integration: **Make**, **Zapier**, **n8n**, **Google Sheets**, **Slack**, **Airbyte** or **webhooks**. A common workflow is: Google Sheet of domains → this actor → enriched rows back into the sheet or CRM.

Python example with the official `apify-client`:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("ninhothedev/website-contact-extractor").call(
    run_input={"startUrls": ["https://www.eff.org/", "python.org"], "crawlContactPages": True, "maxItems": 100}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["domain"], item["emails"], item["phones"], item["linkedin"])
```

### FAQ

**Is it legal to extract contact details from websites?**
The actor only reads information that companies publish openly on their public web pages. Personal data (e.g. named employee emails) may still be protected by GDPR, CCPA or similar laws, so make sure you have a legitimate reason to process it and follow anti-spam rules when contacting people.

**Which pages are scanned?**
The homepage plus up to 4 same-site links whose URL or link text looks like contact, about, team, imprint or impressum. Links to other domains are not followed. Turn off **Crawl contact / about pages** for a faster homepage-only check.

**How many websites can I process?**
Up to 1,000 websites per run (`maxItems` 1–1000). For larger lists, split them across several runs or tasks.

**Are emails verified?**
No. Emails are extracted as published on the site, and phone numbers are plausible candidates, not validated numbers. To guess and DNS-check addresses for a domain, use the [Email Finder & Verifier](https://apify.com/ninhothedev/email-finder-scraper).

**Does it render JavaScript or use proxies?**
No. It fetches static HTML with a browser-like HTTP client, which keeps it fast and cheap. Contacts that only appear after JavaScript runs, or that are obfuscated (e.g. "info \[at] domain"), can be missed. There is no proxy rotation, so sites that block automated requests will show up as errors.

**What does `status: "partial"` mean?**
Contacts were extracted, but either a follow-up page failed to load or the site had more contact-like pages than the 4-page limit. If any follow-up page fails, the run is marked as failed so you notice it, but all delivered rows are kept.

**Can I schedule it?**
Yes. Save your input as a task and add an Apify Schedule (daily, weekly, monthly) to keep contact data fresh.

**Something does not work?**
Open an issue on the actor's **Issues** tab with the run ID and an example URL – we usually respond within a day.

### Related actors

- [Email Finder & Verifier](https://apify.com/ninhothedev/email-finder-scraper) – find, guess and MX-verify company email addresses by domain.
- [Website Link Extractor](https://apify.com/ninhothedev/website-link-extractor) – list all internal and external links of a website.
- [JSON-LD Extractor](https://apify.com/ninhothedev/json-ld-extractor) – pull Schema.org structured data (Organization, LocalBusiness, contact points) from any page.
- [Google Reviews Scraper](https://apify.com/ninhothedev/google-reviews-scraper) – collect Google business reviews and ratings at scale.
- [Website Uptime & Status Checker](https://apify.com/ninhothedev/website-uptime-monitor) – remove dead websites from a lead list before enrichment.

# Actor input Schema

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

Websites to extract contacts from – full URLs (https://www.example.com/) or bare domains (example.com). One result row per hostname; www. and http/https duplicates are merged. Up to 1,000 entries.

## `crawlContactPages` (type: `boolean`):

Also scan up to 4 same-site pages linked as contact, about, team, imprint or impressum to find more emails, phones and social links. Turn off for a faster homepage-only check.

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

Maximum number of websites (result rows) to process in this run, 1–1000. Each delivered website is one billable result.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.python.org/"
  ],
  "crawlContactPages": true,
  "maxItems": 5
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

# 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": [
        "https://www.python.org/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ninhothedev/website-contact-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "startUrls": ["https://www.python.org/"] }

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

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.python.org/"
  ]
}' |
apify call ninhothedev/website-contact-extractor --silent --output-dataset

```

## MCP server setup

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

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/dn1iXT4Mlj6KV53TF/builds/3YSgNsaWvaGVR9Rws/openapi.json
