# Contact Details Scraper: Website Emails, Phones & Socials (`jfaro19/website-contact-finder`) Actor

Find emails, phone numbers, social profiles and address for any list of company websites (e.g. the website column of Google Maps results). Crawls homepage + contact/about pages, decodes hidden emails, checks emails can receive mail. Pay only when an email or phone is found.

- **URL**: https://apify.com/jfaro19/website-contact-finder.md
- **Developed by:** [Jason Faro](https://apify.com/jfaro19) (community)
- **Categories:** Lead generation, Automation, Business
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 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.

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

### What does Contact Details Scraper do?

**Contact Details Scraper** is an **email extractor and contact scraper for websites**. It takes a list of websites and returns the **email addresses, phone numbers, social media profiles, business address and contact page** of each one. For every site it crawls the homepage plus the pages most likely to hold contact details (Contact, About, Team, Locations, Impressum…), then cleans, validates and ranks the results.

**You pay only for websites where at least one email or phone number is found.** Websites with no contacts, unreachable sites and errors are free, and the price is per website, not per page crawled.

Paste your websites, click **Start**, and download the results as CSV, Excel or JSON, or get them through the Apify API. You can schedule runs and connect them to Google Sheets, Make, Zapier, n8n or your CRM.

### Why use this contact details scraper?

- **Enrich lead lists.** Turn a list of company websites into emails, phones and social profiles. It works well with the `website` column from a Google Maps scrape.
- **Finds emails other tools miss.** It decodes Cloudflare-protected emails and `name [at] domain [dot] com` style addresses, and reads schema.org business data hidden in the page.
- **Cleaner data.**
  - Placeholders (`you@example.com`), image names (`logo@2x.png`) and tracking IDs are removed.
  - Phone numbers are validated and formatted in international E.164 format (`+15025610375`).
- **Knows which emails are worth using.** Each email is labeled:
  - `generic` (info@, sales@) or `personal`
  - on the company's own domain or not
  - from a free provider (Gmail, Yahoo…) or not
  - whether its domain can actually **receive mail** (checked via its MX records), which catches typos like `info@compnay.com`
- **Picks the best contact.** `primaryEmail` and `primaryPhone` give you one ready-to-use value per company.
- **Includes the email provider.** `mailboxProvider` (Google Workspace, Microsoft 365, …) comes free, which is useful for segmenting outreach.

### How to scrape emails and phone numbers from websites

1. Click **Try for free**.
2. Paste websites into the **Websites** field, one per line. `example.com`, `https://www.example.com/contact` and `jane@example.com` all work.
3. Optionally, adjust **Max pages per website** (default 5) and **Default country** for phone numbers.
4. Click **Start**.
5. Download the dataset from the **Output** tab or connect it to your tools.

### Input

| Field | Type | Description |
|---|---|---|
| `websites` | array of strings | Domains, URLs or emails. They are normalized and de-duplicated. |
| `maxPagesPerWebsite` | integer (default `5`) | Homepage plus the most likely contact pages. Price doesn't depend on this. |
| `defaultCountry` | string (default `US`) | Country used for phone numbers written without a country code. Country-code domains like `.de` and `.co.uk` are detected automatically. |
| `maxConcurrency` | integer (default `15`) | Number of websites processed in parallel. |

```json
{
  "websites": ["apify.com", "https://www.example-plumbing.com/contact-us"],
  "maxPagesPerWebsite": 5,
  "defaultCountry": "US"
}
```

### Output

Each website produces one item. This example is from a real run on `apify.com`:

```json
{
  "domain": "apify.com",
  "status": "ok",
  "contactsFound": true,
  "companyName": "Apify",
  "primaryEmail": "hello@apify.com",
  "primaryPhone": null,
  "emailCount": 1,
  "emails": [
    {
      "email": "hello@apify.com",
      "type": "generic",
      "sameDomain": true,
      "freeMailProvider": false,
      "domainAcceptsMail": true,
      "foundOn": ["https://apify.com/contact"]
    }
  ],
  "phones": [],
  "socialProfiles": {
    "linkedin": "http://linkedin.com/company/apify",
    "x": "https://x.com/apify",
    "tiktok": "https://www.tiktok.com/@apifytech",
    "github": "https://github.com/apify"
  },
  "address": {
    "streetAddress": "Na Příkopě 959/27",
    "addressLocality": "Prague",
    "postalCode": "11000",
    "addressCountry": "CZ"
  },
  "contactPageUrl": "https://apify.com/contact",
  "hasContactForm": true,
  "contactFormUrl": "https://apify.com/contact-sales",
  "mailboxProvider": "Google Workspace",
  "websiteUrl": "https://apify.com/",
  "pagesCrawled": ["https://apify.com/", "https://apify.com/contact", "https://apify.com/contact-sales", "https://apify.com/about"]
}
```

#### Main fields

| Field | Description |
|---|---|
| `primaryEmail` / `primaryPhone` | The best single contact: same-domain generic inbox first, then other emails. Phones are ranked by how often they appear. |
| `emails[]` | Every email found, with `type`, `sameDomain`, `freeMailProvider`, `domainAcceptsMail` and the pages it was found on |
| `phones[]` | Validated phone numbers in E.164 format, with the pages they were found on |
| `socialProfiles` | Facebook, Instagram, LinkedIn, X/Twitter, YouTube, TikTok, Pinterest, Threads, Telegram, WhatsApp, GitHub, Yelp |
| `address` | Postal address from the site's structured data, when published |
| `contactPageUrl`, `contactFormUrl` | Where to reach the company if there's no email |
| `mailboxProvider` | The company's email provider (Google Workspace, Microsoft 365, Zoho, GoDaddy…) |
| `status` | `ok`, `website_unreachable` or `error` (never charged) |

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

The Actor uses **pay-per-event** pricing, charged **per website where at least one email or phone number was found**. Check the **Pricing** tab for the current price per 1,000 websites. Sites with no contacts, sites that only have social profiles, unreachable sites and errors cost nothing. Crawling more pages per site doesn't raise the price. You can set a maximum cost per run, and the Actor stops when it reaches the limit.

### Tips

- Feed it the `website` field from Google Maps, Yelp or directory scrapes to turn business listings into contactable leads.
- Filter on `emails.domainAcceptsMail = true` and `emails.sameDomain = true` for the cleanest outreach lists.
- If you only need the main contact, use `primaryEmail` and `primaryPhone`.
- Sites that load all their content with JavaScript may show fewer results. Most small-business sites (WordPress, Wix, Squarespace, Duda, GoDaddy) work well.

### Works well with

- [Domain Intelligence](https://apify.com/jfaro19/domain-intel): add each company's tech stack, email provider (Google Workspace, Microsoft 365…) and SPF/DKIM/DMARC grade to your lead list.
- [Website Screenshot & PDF](https://apify.com/jfaro19/website-screenshot): capture a clean screenshot of every website (no cookie banners) for personalized outreach or audits.

### FAQ, disclaimers and support

**Is it legal?** The Actor only reads public web pages, the same way a visitor's browser would. It doesn't log in, submit forms or bypass access controls. Contact details can include personal data (for example a named employee's email). You're responsible for having a lawful basis to process it and for following anti-spam laws such as GDPR, CAN-SPAM and CASL when you contact anyone.

**Why didn't it find an email for some sites?** Many small businesses publish only a phone number or a contact form. In that case you get `contactFormUrl`, and if no email or phone was found at all, you aren't charged.

**Found a bug or a site it handles badly?** Open an issue on the **Issues** tab and include the website. Fixes ship regularly.

# Actor input Schema

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

Websites to search for contacts. Paste domains (example.com), URLs (https://www.example.com/contact) or email addresses; they are normalized and de-duplicated. Works great with the 'website' column from a Google Maps scrape.

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

Homepage plus the most likely contact pages (Contact, About, Team, Impressum, Locations...). You pay per website, not per page, so this only affects speed.

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

Two-letter country code used to interpret phone numbers written without a country code (e.g. US, GB, DE). Country-code domains (.de, .co.uk, ...) are detected automatically.

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

How many websites to process in parallel.

## Actor input object example

```json
{
  "websites": [
    "apify.com",
    "louisvilleroofing.com"
  ],
  "maxPagesPerWebsite": 5,
  "defaultCountry": "US",
  "maxConcurrency": 15
}
```

# Actor output Schema

## `results` (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 = {
    "websites": [
        "apify.com",
        "louisvilleroofing.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jfaro19/website-contact-finder").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",
        "louisvilleroofing.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("jfaro19/website-contact-finder").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",
    "louisvilleroofing.com"
  ]
}' |
apify call jfaro19/website-contact-finder --silent --output-dataset

```

## MCP server setup

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

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/jipdiW9Rwbp1Lruzx/builds/bPYY3xMJOTh7QMkRx/openapi.json
