# Website Contact Scraper: Emails, Phones & Social Profiles (`stratumics/website-contact-scraper`) Actor

Turn a list of websites into one row per company with verified emails, formatted phone numbers, social profiles (LinkedIn, Facebook, Instagram, X), address and contact page. Pay only for results.

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

## Pricing

from $2.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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does Website Contact Scraper do?

**Website Contact Scraper** turns a list of websites into **one clean row per company** with **email addresses, phone numbers, social media profiles, postal address and the contact page URL**. Paste domains like `acme.com` or full URLs, and it reads each homepage plus the pages most likely to hold contact details (Contact, About, Team, Imprint, Locations), then merges everything it finds.

It works as a **contact details scraper, email extractor and phone number finder** in one, through the Apify Console, the **Apify API** or any AI agent connected to Apify.

### Why use Website Contact Scraper?

- **One row per website, not one row per page.** No deduplication work in a spreadsheet afterwards.
- **Pay only for results.** Websites that are offline, parked or blocked cost nothing.
- **Emails you can use.** Placeholder addresses (`you@example.com`), image file names, tracking IDs and "website by" agency credits are filtered out. Each email domain is checked for an MX record so dead domains do not pollute your list. Addresses hidden by Cloudflare email protection and written as `name [at] company [dot] com` are decoded.
- **Phone numbers in a standard format.** Every number is validated and returned in international format (`+44 20 7946 0958`) and E.164 (`+442079460958`), with country and line type (mobile or fixed line). Company registration numbers, VAT IDs and order numbers are not mistaken for phones.
- **Real social profiles only.** LinkedIn, Facebook, Instagram, X (Twitter), YouTube, TikTok, Pinterest, GitHub, WhatsApp, Telegram, Discord, Threads, Google Maps and Yelp links, with share buttons, single posts and widget links removed.
- **Best contact first.** `primaryEmail` and `primaryPhone` pick the address and number you are most likely to want: on the company's own domain, from a mailto or tel link, general inbox before personal.
- **Fast and light.** Plain HTTP requests, no browser, so thousands of websites finish in minutes.

Typical uses: **lead generation and sales prospecting**, **CRM enrichment**, building B2B contact lists from Google Maps or directory exports, checking which suppliers have a public phone line, and giving an AI agent a reliable "find contact details for this company" tool.

### What data can you extract?

| Field | Example |
|---|---|
| `companyName` | Lebkuchen-Schmidt |
| `primaryEmail` | service@lebkuchen-schmidt.com |
| `emails` | All deliverable emails, best first |
| `emailDetails` | Type (role or personal), on the company domain or not, domain accepts mail, source, page |
| `primaryPhone` | +49 911 896631 |
| `phones` / `phoneDetails` | International, national and E.164 formats, country, mobile or fixed line, source, page |
| `linkedin`, `facebook`, `instagram`, `twitter`, `youtube`, `tiktok`, ... | Profile URLs |
| `address` / `addressDetails` | Zollhausstraße 30, Nürnberg, Bayern 90469, DE |
| `contactPageUrl` | The page most likely to be the contact page |
| `hasContactForm` | True when the site has a contact form |
| `status` | ok, unreachable, blocked or parked |

### How to scrape contact details from websites

1. Open the **Input** tab and paste your websites into **Websites**, one per line. Domains (`acme.com`), URLs and even email addresses are accepted.
2. Keep **Max pages per website** at 6 for small business sites, or raise it for large company sites.
3. Choose what to collect: emails, phones, social profiles. All three are on by default.
4. Click **Start**. Results appear in the **Output** tab as they finish.
5. Download the table as **CSV, Excel, JSON or HTML**, or send it to Google Sheets, HubSpot, Zapier, Make or n8n.

### How much does it cost to scrape website contact details?

You pay per website, and only when the scan worked:

| Result | Price |
|---|---|
| Website with at least one email, phone or social profile | $0.003 |
| Website scanned, nothing found | $0.001 |
| Website offline, parked, suspended or blocked | Free |

**1,000 websites cost about $3**, including up to 6 pages per website. That price covers all pages; you are never charged per page. Apify's free plan includes $5 of monthly credit, enough to try the scraper on well over a thousand websites.

Larger Apify plans pay less automatically: a website with contacts costs $0.0025 on Scale and $0.002 on Business.

### Input

See the **Input** tab for every option. The only required field is **Websites**. Example:

```json
{
    "websites": ["apify.com", "https://www.lebkuchen-schmidt.com", "stripe.com"],
    "maxPagesPerWebsite": 6,
    "extractEmails": true,
    "extractPhones": true,
    "extractSocials": true,
    "verifyEmailDomains": true,
    "onlySameDomainEmails": false,
    "phoneCountry": ""
}
```

- **Default country for local phone numbers**: numbers written without a country code (for example `(03) 9484 9639`) are read using the country of the website's domain (`.com.au` means Australia), then the page language, then the address. Set a two-letter code such as `GB` to force one.
- **Only emails on the website's own domain**: turn on to drop Gmail and other outside addresses. Leave off for small businesses, many of which use Gmail.

### Output

You can download the dataset in various formats such as JSON, HTML, CSV or Excel. A trimmed real result:

```json
{
    "website": "https://www.lebkuchen-schmidt.com",
    "domain": "lebkuchen-schmidt.com",
    "status": "ok",
    "companyName": "Lebkuchen-Schmidt",
    "primaryEmail": "service@lebkuchen-schmidt.com",
    "emails": ["service@lebkuchen-schmidt.com", "affiliate@lebkuchen-schmidt.com", "info@lebkuchen-schmidt.de"],
    "primaryPhone": "+49 911 896631",
    "phones": ["+49 911 896631", "+49 69 65009565", "+49 911 89660"],
    "phoneDetails": [
        { "number": "+49911896631", "international": "+49 911 896631", "national": "0911 896631", "country": "DE", "type": "fixed_line", "source": "tel-link", "foundOn": "https://www.lebkuchen-schmidt.com/de/kontakt/kontaktanfrage/" }
    ],
    "linkedin": "https://linkedin.com/company/lebkuchen-schmidt-business",
    "facebook": "https://facebook.com/lebkuchen.schmidt",
    "instagram": "https://instagram.com/lebkuchenschmidt",
    "youtube": "https://youtube.com/user/SchmidtLebkuchen",
    "address": "Zollhausstraße 30, Nürnberg, Bayern 90469, DE",
    "contactPageUrl": "https://www.lebkuchen-schmidt.com/de/kontakt/",
    "pagesCrawled": 6
}
```

```json
{
    "website": "https://www.drunkenbarber.com.au",
    "domain": "drunkenbarber.com.au",
    "status": "ok",
    "companyName": "Drunken Barber",
    "primaryEmail": "drunkenbarber3065@gmail.com",
    "primaryPhone": "+61 3 9417 1561",
    "facebook": "https://facebook.com/Drunken-Barber-543923568968459"
}
```

### Tips for better results

- **Feed it websites from anywhere**: Google Maps exports, directory listings, trade show exhibitor lists, CRM exports. Duplicates and `www.` variants are merged automatically.
- **Large company sites** spread contacts across many pages. Raise **Max pages per website** to 10 or 15.
- **Sites built entirely in JavaScript** (a small share of websites) show little text to a plain HTTP reader, so they may return fewer contacts.
- **Seeing many `blocked` rows?** Turn on Apify Proxy in the Advanced section.
- Schedule the scraper in Apify to refresh contact lists every month.

### Integrations and API

- **API**: start runs and download results from any language. Open the **API** tab for ready code in Python, JavaScript and cURL.
- **Python**: `from apify_client import ApifyClient`, then `client.actor("stratumics/website-contact-scraper").call(run_input={"websites": ["acme.com"]})`.
- **JavaScript**: `import { ApifyClient } from 'apify-client'`, then the same call with `client.actor('stratumics/website-contact-scraper').call({ websites: ['acme.com'] })`.
- **No-code**: Zapier, Make, n8n, Google Sheets, HubSpot and Slack integrations from the **Integrations** tab.
- **AI agents**: connect any MCP-capable assistant or agent to Apify's MCP server (`mcp.apify.com`) and it can call this scraper as a tool to look up a company's contact details.

### FAQ

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

This scraper only reads pages that the website publishes for everyone, and the contact details businesses list there for the purpose of being contacted. Our Actors are ethical and do not extract any private user data. However, you should be aware that your results could contain personal data, such as the work email of a named employee. Personal data is protected by the GDPR in the European Union and by other regulations around the world. You should not scrape personal data unless you have a legitimate reason to do so. If you're unsure whether your reason is legitimate, consult your lawyers. When you email the contacts you find, follow the anti-spam rules of the recipient's country (for example CAN-SPAM, PECR and the GDPR).

#### Why did a website return no emails?

Some businesses show only a contact form, or put their address in an image. Check `hasContactForm` and `contactPageUrl` to reach them another way, and look at `phones` and the social profiles.

#### What do the email types mean?

`role` means a shared inbox such as info@, sales@ or support@. `personal` means an address that looks like a person's, such as jane.smith@. `sameDomain` tells you whether the address is on the company's own website domain.

#### How is this different from a Google Maps scraper?

A Google Maps scraper finds businesses. This tool reads their websites. Run a Maps scraper first, then pass its website column here to add emails and social profiles.

#### Found a problem or need a field?

Open an issue in the **Issues** tab. Every issue is read and usually answered within a day.

# Actor input Schema

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

Domains or URLs to scan, one per line, for example "example.com" or "https://www.example.com". Duplicates are merged and each website returns one row.

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

The homepage plus the most likely contact pages (contact, about, team, imprint, locations). 6 finds contacts on most small business sites; raise it for large sites.

## `extractEmails` (type: `boolean`):

Collect email addresses from mailto links, page text, Cloudflare-protected addresses, structured data and common obfuscations like "name \[at] example \[dot] com".

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

Collect phone numbers from tel: links, WhatsApp links, structured data and page text, validated and formatted in international format.

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

Collect links to LinkedIn, Facebook, Instagram, X (Twitter), YouTube, TikTok, Pinterest, GitHub, WhatsApp, Telegram, Discord, Threads, Google Maps, Yelp and more. Share buttons and post links are ignored.

## `verifyEmailDomains` (type: `boolean`):

Looks up each email domain's MX record. Addresses on domains that cannot receive mail are kept in emailDetails but left out of the emails list.

## `onlySameDomainEmails` (type: `boolean`):

Drop addresses on other domains (for example gmail.com or a web agency's address). Leave off to keep them; many small businesses use Gmail.

## `phoneCountry` (type: `string`):

Two-letter country code (US, GB, DE, AU...) used to read numbers written without a country code. Leave empty to detect it from the domain, the page language and the address.

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

How many pages are fetched at the same time across all websites. Each website is only ever hit a few times.

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

Most company websites answer directly, so no proxy is used by default. Turn on Apify Proxy if many sites come back as blocked.

## Actor input object example

```json
{
  "websites": [
    "apify.com",
    "https://www.lebkuchen-schmidt.com",
    "stripe.com"
  ],
  "maxPagesPerWebsite": 6,
  "extractEmails": true,
  "extractPhones": true,
  "extractSocials": true,
  "verifyEmailDomains": true,
  "onlySameDomainEmails": false,
  "phoneCountry": "",
  "maxConcurrency": 25,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `contacts` (type: `string`):

No description

## `allFields` (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",
        "https://www.lebkuchen-schmidt.com",
        "stripe.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("stratumics/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 = { "websites": [
        "apify.com",
        "https://www.lebkuchen-schmidt.com",
        "stripe.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("stratumics/website-contact-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",
    "https://www.lebkuchen-schmidt.com",
    "stripe.com"
  ]
}' |
apify call stratumics/website-contact-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,stratumics/website-contact-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/zwGPe07X2CLypK5q7/builds/nU62hQcOY4VVjXzoJ/openapi.json
