# Website Contact Scraper: Emails, Phones, Socials, Tech (`nat-labs/website-contact-scraper`) Actor

One row per domain: company e-mails, phones (E.164), social profiles, imprint details (name, address, VAT, register no.), tech stack, mail provider, SPF/DMARC and domain age. Respects robots.txt, no proxy. Pay only for domains with contacts found: $2 per 1,000.

- **URL**: https://apify.com/nat-labs/website-contact-scraper.md
- **Developed by:** [Nat | Data Tools](https://apify.com/nat-labs) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 domains

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

## Website Contact Scraper: Emails, Phones, Socials, Tech Stack

Turn a list of websites into **one clean row per company**: business e-mails, phone numbers in international format, social profiles (LinkedIn, Facebook, Instagram, X, YouTube, TikTok and more), the company's legal name, address, VAT ID and register number from the imprint, its **tech stack**, **mail provider** (Google Workspace, Microsoft 365…), SPF/DMARC records and **domain age**. Export to JSON, CSV or Excel.

**$2 per 1,000 domains, everything included. You pay only for domains where contact details were found.** Unreachable sites, sites that don't allow crawling and sites without contacts are free.

### Why this contact scraper

| | This Actor | Typical contact scrapers |
|---|---|---|
| Billing | **Per domain**, flat: homepage + 3 best contact/imprint/about pages included | Per page crawled, often 10–20 pages per site by default |
| Price for 1,000 websites | **$2.00** (down to $0.90 on higher plans), only for domains with results | $2 per 1,000 *pages* → $10–40 per 1,000 websites at default settings, plus start fees or add-ons |
| Failed sites | **Free**: unreachable, blocked, no contacts found | Every page request is billed |
| Output | **One merged row per domain**, ready for a CRM or spreadsheet | One row per page; you merge and dedupe yourself |
| Company data | Legal name, address, VAT ID, register number (Impressum / legal notice), schema.org data | E-mails and phones only |
| Extra intelligence | **Tech stack** (~170 technologies), **mail provider**, SPF/DMARC, **domain age & registrar** (RDAP), language | Not included, or a separate paid add-on |
| Speed | Plain HTTP, no browser, no proxy: ~100 domains in 2 minutes at the default 1 GB; raise memory to go faster at the same cost | Headless browsers, 4 GB memory |
| Privacy by default | **Company addresses only** (info@, sales@…); named people's addresses withheld unless you opt in | Everything, including personal addresses |
| Polite crawling | robots.txt always respected, pages of one site fetched one at a time | Varies |

### What you can do

- **Lead generation**: enrich a list of companies, a trade-show exhibitor list or Google Maps results with e-mails, phones and LinkedIn pages.
- **CRM enrichment and cleanup**: fill missing phone numbers, social profiles, legal names and addresses for accounts you already have.
- **Sales intelligence**: find shops on Shopify or WooCommerce, companies on HubSpot or Salesforce, or sites without analytics, then prioritise by domain age.
- **Market research**: map the tech stack, mail provider and email security (DMARC) of a whole industry.
- **Agency prospecting**: spot outdated sites (old WordPress, no consent banner, no analytics) to pitch your services.
- **Compliance checks**: verify a supplier's legal name, VAT ID and register number from its imprint.
- **AI agents**: call it from Claude, ChatGPT or Cursor through Apify's AI integrations. Input is lenient: bare domains, URLs and e-mail addresses all work.
- **Your own stack**: run it from the Apify API, the Python or JavaScript client, Make, Zapier, n8n, Google Sheets, Slack, webhooks or a schedule; export JSON, CSV or Excel.

### Quick start

#### 1. Enrich a list of websites

```json
{ "domains": ["stripe.com", "manufactum.de", "https://www.tado.com/de-en/", "info@bluebottlecoffee.com"] }
```

#### 2. Enrich results of another Actor (e.g. Google Maps)

```json
{ "datasetId": "YOUR_DATASET_ID", "datasetField": "website" }
```

Any dataset row with a `website`, `url` or `domain` field works. Duplicate domains are removed for free.

#### 3. Local businesses with local phone numbers

```json
{ "domains": ["baeckerei-beispiel.de", "zahnarzt-beispiel.de"], "countryHint": "DE" }
```

`countryHint` lets the Actor read numbers like `030 1234567` that are written without `+49`.

#### 4. Deeper crawl

```json
{ "domains": ["example.com"], "maxPagesPerDomain": 8 }
```

4 pages per domain are included in the price; each additional page is billed as an extra page.

### Output

One row per domain:

```json
{
    "domain": "manufactum.de",
    "status": "ok",
    "finalUrl": "https://www.manufactum.de/",
    "emails": ["info@manufactum.de", "presse@manufactum.de"],
    "emailDetails": [{ "email": "info@manufactum.de", "type": "generic", "onDomain": true, "source": "https://www.manufactum.de/" }],
    "personalEmailsHidden": 3,
    "phones": ["+492309939050", "+49230993900"],
    "phoneDetails": [{ "phone": "+49 2309 939050", "e164": "+492309939050", "country": "DE", "type": "FIXED_LINE", "source": "https://www.manufactum.de/" }],
    "socials": { "facebook": "https://www.facebook.com/manufactum", "instagram": "https://www.instagram.com/manufactum", "pinterest": "https://www.pinterest.de/manufactum" },
    "contactPageUrl": "https://www.manufactum.de/kontakt-c199446/",
    "imprintUrl": "https://www.manufactum.de/impressum-c199455/",
    "company": {
        "name": "Manufactum",
        "legalName": "Manufactum GmbH",
        "address": "Hiberniastraße 5, 45731 Waltrop",
        "vatId": "DE315189509",
        "registrationNumber": "HRB 7982 G",
        "foundingDate": "1987"
    },
    "title": "Manufactum. Das Warenhaus der guten Dinge",
    "language": "de",
    "technologies": [{ "name": "Google Tag Manager", "category": "tag-manager" }, { "name": "Google Cloud", "category": "hosting" }],
    "tech": { "cms": null, "ecommerce": null, "webServer": "Caddy", "analytics": ["Google Tag Manager"], "cdnHosting": ["Google Cloud"], "marketing": [], "liveChat": [] },
    "mail": { "provider": "Other / self-hosted", "mxHosts": ["mx51.manufactum.de"], "dmarcPolicy": "reject", "verifiedServices": ["atlassian-domain", "facebook-domain", "microsoft", "miro"] },
    "domainInfo": { "available": false, "reason": "no-rdap-server" },
    "pagesCrawled": 4,
    "charged": true,
    "scrapedAt": "2026-10-18T11:45:34.231Z"
}
```

For a `.com` domain `domainInfo` looks like `{ "available": true, "createdAt": "1996-04-24T04:00:00.000Z", "expiresAt": "2027-04-25T04:00:00.000Z", "ageYears": 30.5, "registrar": "COREhub, S.R.L." }`.

`status` is one of `ok` (contacts found, charged), `no-contacts` (reachable, nothing found, free), `unreachable`, `blocked`, `http-error` or `blocked-by-robots` (all free). The dataset has ready-made views: **Contacts**, **Company & domain**, **Tech stack** and **Status**.

### Pricing

Pay per event. **Platform usage is included**: no start fee and no compute bill on top.

| Event | What it is | Price |
|---|---|---|
| Domain | One domain where at least one e-mail, phone, social profile or company detail was found. Includes 4 pages, tech stack, mail DNS and domain age | **$2.00 / 1,000** ($0.002) |
| Extra page | Each page beyond the 4 included ones (only if you raise *Pages per domain*) | $0.30 / 1,000 |

Lower rates apply automatically on higher Apify plans (domains down to **$0.90 / 1,000**). **Never charged:** unreachable or blocked sites, sites whose robots.txt disallows crawling, sites without any contact details, duplicate domains.

Examples: 1,000 websites with contacts found on 700 = **$1.40**. 10,000 Google Maps leads = at most **$20**, usually less.

The Actor checks your run's **maximum cost** before each domain and stops cleanly when it is reached.

**Free Apify plan:** up to 50 domains and 4 pages per domain per run (a limit set by the developer, not by Apify). Any paid plan removes it.

### How it works

1. The domain's `robots.txt` is read first and **always respected**. If it disallows our crawler (or is temporarily unavailable), the domain is skipped for free.
2. The homepage is fetched (falling back to `http://` and `www.` if needed). Links are ranked: imprint / legal notice, contact, about.
3. Up to 3 more pages are fetched, one after another. Pages are parsed for `mailto:` and `tel:` links, visible e-mail addresses (including common obfuscations), labelled phone numbers, social links, schema.org data and imprint details.
4. Public DNS (MX, SPF, DMARC) and RDAP (domain registration) are queried. No request goes to the site for these.

### Good to know

- **E-mails of people are withheld by default.** Addresses like `jane.doe@company.com` are personal data under the GDPR. With the default *Company addresses only* setting they are not returned, only counted (`personalEmailsHidden`). Switch to *All addresses* only if you have a legal basis.
- **Phone numbers** come from `tel:` links, schema.org data or lines labelled *Tel*, *Phone*, *Telefon*…, and are validated. Fax numbers are skipped. Set `countryHint` for local numbers.
- **Company details** (legal name, VAT, register number) are best on European sites with an imprint (Impressum, mentions légales, aviso legal). Third parties named in imprints (web agencies, dispute-resolution bodies, Google) are filtered out.
- **JavaScript-only sites**: the Actor reads the HTML the server sends. Sites that render everything in the browser may return fewer details; they are free if nothing is found.
- **Domain age** comes from RDAP. Some country domains (for example `.de`) have no public RDAP service yet; their rows say `"reason": "no-rdap-server"`.
- **Not a people finder**: no LinkedIn profiles of employees, no e-mail guessing, no SMTP probing.

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

This Actor reads pages that companies publish for anyone to see, such as their contact page and legally required imprint, honours robots.txt and identifies itself with an honest user agent. By default it returns only company role addresses (info@, sales@…), phone numbers and company social profiles. If you process personal data (for example named e-mail addresses), you are responsible for having a legal basis under the GDPR or similar laws, and for respecting opt-out and anti-spam rules (e.g. CAN-SPAM, ePrivacy) when you contact anyone. Consult a lawyer for your use case.

### FAQ

**How is this different from Contact Details Scraper?** That Actor bills per page and crawls up to 20 pages per website by default, so 1,000 websites can cost $10–40 before add-ons. This one bills one flat price per domain, only when something was found, and adds company, tech-stack, mail and domain data to the same row.

**Can I get more than 4 pages per website?** Yes, up to 20 with *Pages per domain*. Pages 5+ are billed as extra pages at $0.30 per 1,000.

**How fast is it?** About 100 domains in 2 minutes with the default 1 GB memory. Speed scales with memory (Apify gives CPU in proportion to memory), and the cost per domain stays about the same, so for 10,000+ domains run it with 4 GB.

**Does it use a proxy?** No. Business websites answer normal requests; no proxy cost is passed on to you. You can still add one in the input.

**How fresh is the data?** Every run fetches the live websites, DNS and RDAP.

**What if a site blocks the crawler?** Sites that time out or rate-limit are retried once at the end of the run. If they still fail, the row says `unreachable`, `blocked` or `blocked-by-robots` and is free. The run's `STATISTICS` record lists every failure with the reason.

**Something is missing or wrong?** Open an issue in the Issues tab with the domain; it's answered within 24 hours.

# Actor input Schema

## `domains` (type: `array`):

Domains (stripe.com), URLs (https://www.example.de/en/) or e-mail addresses (info@example.com). Duplicates of the same domain are removed for free. Up to 100,000 per run.

## `datasetId` (type: `string`):

ID of a dataset from another Actor run (e.g. a Google Maps scraper). Rows with a website, url or domain field are enriched.

## `datasetField` (type: `string`):

Optional. Field to read from each dataset row. Default: the first of website, url, domain, site, homepage.

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

Homepage plus the best contact, imprint and about pages. 4 pages are included in the domain price; each page beyond 4 is billed as an extra page. Free plan: max 4.

## `emailScope` (type: `string`):

By default only role addresses are returned; addresses that look like a person's name are withheld and counted in personalEmailsHidden. Choose "all" only if you have a legitimate interest or consent to process personal data.

## `countryHint` (type: `string`):

Optional 2-letter country code (e.g. DE, US) used to read local phone numbers without a + prefix. Numbers in tel: links and international format work without it.

## `extractTechStack` (type: `boolean`):

CMS, e-commerce platform, analytics, ad pixels, marketing tools, chat, CDN and hosting from the homepage.

## `extractMailDns` (type: `boolean`):

MX records → Google Workspace, Microsoft 365, etc., plus SPF/DMARC records and verified SaaS from public DNS.

## `extractDomainAge` (type: `boolean`):

Registration and expiry date and registrar from the official RDAP registry (the successor of WHOIS).

## `includeFailedRows` (type: `boolean`):

Also output (free) rows for unreachable sites, sites that block crawling in robots.txt, and sites without contact details — useful to see why.

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

Stop after this many domains (0 = all). Also bounded by the run's maximum charge.

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

Upper limit of domains processed at once. The Actor also limits parallelism by the run's memory, because Apify gives CPU in proportion to memory: 1 GB → 10 domains at once, 4 GB → 40. For big lists, raise the run memory to go faster at about the same cost. Pages of one domain are always fetched one after another.

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

Not needed: business websites answer direct requests. Use a proxy only if many of your sites block datacenter IPs.

## Actor input object example

```json
{
  "domains": [
    "stripe.com",
    "hubspot.com",
    "mailchimp.com",
    "atlassian.com",
    "cloudflare.com",
    "manufactum.de",
    "tado.com",
    "sennheiser.com",
    "bluebottlecoffee.com",
    "allbirds.com"
  ],
  "maxPagesPerDomain": 4,
  "emailScope": "generic",
  "extractTechStack": true,
  "extractMailDns": true,
  "extractDomainAge": true,
  "includeFailedRows": true,
  "maxItems": 0,
  "maxConcurrency": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per domain: e-mails, phones, social profiles, company details, tech stack, mail provider and domain age.

## `statistics` (type: `string`):

Per-run counters (domains with contacts, unreachable, blocked by robots.txt, charged), pages fetched and failures with reasons.

# 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 = {
    "domains": [
        "stripe.com",
        "hubspot.com",
        "mailchimp.com",
        "atlassian.com",
        "cloudflare.com",
        "manufactum.de",
        "tado.com",
        "sennheiser.com",
        "bluebottlecoffee.com",
        "allbirds.com"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nat-labs/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 = {
    "domains": [
        "stripe.com",
        "hubspot.com",
        "mailchimp.com",
        "atlassian.com",
        "cloudflare.com",
        "manufactum.de",
        "tado.com",
        "sennheiser.com",
        "bluebottlecoffee.com",
        "allbirds.com",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("nat-labs/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 '{
  "domains": [
    "stripe.com",
    "hubspot.com",
    "mailchimp.com",
    "atlassian.com",
    "cloudflare.com",
    "manufactum.de",
    "tado.com",
    "sennheiser.com",
    "bluebottlecoffee.com",
    "allbirds.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call nat-labs/website-contact-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nat-labs/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/nTqmBVOibJPtIgMFw/builds/wCCpn87BomokzEcRN/openapi.json
