# Company Contact Extractor - Emails, Phones & Socials (`artificially/company-contact-extractor`) Actor

Extract public business contact details from company websites: emails, phone numbers, LinkedIn/X/Facebook/Instagram/YouTube/TikTok/GitHub/Crunchbase profiles, contact page, address. Input: domains or URLs. Output: one item per domain. Pay only for domains with contacts.

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

## Pricing

from $6.30 / 1,000 domain 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

## Company Contact Extractor – Emails, Phones & Social Profiles from Websites

Turn a list of company domains into **public business contact details**: emails, phone numbers, LinkedIn / X / Facebook / Instagram / YouTube / TikTok / GitHub / Crunchbase profiles, the contact page, the contact form and the postal address. Paste domains, get **one clean item per company**, and pay only for companies where something was found.

**Built by [Artificially](https://apify.com/artificially)** | Follow us on [X @artificially\_io](https://x.com/artificially_io)

#### Use with AI agents (MCP)

This actor works as a tool for Claude, ChatGPT, Cursor and other AI agents through [Apify's MCP server](https://mcp.apify.com). Ask something like "find the contact email and LinkedIn page for stripe.com, apify.com and hetzner.com" and the agent calls it for you. Set `compactOutput: true` (and `maxPagesPerDomain: 5` for speed) so results are short and fit easily in the agent's context.

**Quick setup** (sign in with your Apify account when asked):

- **Claude** (claude.ai or Claude Desktop): Settings → Connectors → Add custom connector, and paste `https://mcp.apify.com?tools=artificially/company-contact-extractor`
- **Claude Code or Cursor** via the Apify CLI (latest version, `apify upgrade`): `apify mcp install claude-code --tools artificially/company-contact-extractor` (use `cursor` instead of `claude-code` for Cursor)
- **Any MCP client** (Cursor, VS Code, Windsurf):

```json
{
  "mcpServers": {
    "apify": { "url": "https://mcp.apify.com?tools=artificially/company-contact-extractor" }
  }
}
```

**Try asking:**

- "Find the public contact email, phone and LinkedIn page for these 50 company websites."
- "Get the contact page and support email for stripe.com, apify.com and posthog.com."

### Why this actor

- **One item per company, not per page** – all contacts from the home page, contact, imprint, about and legal pages are merged and deduplicated, and every email and phone keeps the `sourceUrl` where it was found.
- **Smart crawl, not a blind spider** – the home page first, then the pages that actually carry contact details (contact, Impressum/imprint, about, team, support, legal/privacy, careers) in 20+ languages: Kontakt, Impressum, contacto, contatti, mentions légales, despre noi, over ons, and more.
- **Clean emails** – mailto links, page text, schema.org data, obfuscated emails (`info [at] example [dot] com`, `&#64;`) and Cloudflare-protected emails. Image names like `logo@2x.png`, Sentry/Wix tracking addresses, placeholders like `name@example.com` and no-reply addresses are filtered out.
- **Generic vs personal** – every email is tagged `generic` (info@, sales@, support@, office@, presse@, vanzari@ …) or `personal`, plus `isCompanyDomain` so third-party addresses (a web agency or a regulator in the imprint) are easy to drop. Use `emailFilter: "generic_only"` to keep only role addresses.
- **Valid, normalized phones** – tel: links, schema.org and labeled numbers in text ("Tel.:", "Phone:", "Telefon"), validated with libphonenumber and returned in international and E.164 format. The country for local numbers comes from the domain ending, the address or the page language. Fax numbers are skipped.
- **The company's own social profiles** – share buttons and unrelated profiles are ignored; profiles in the header/footer, in schema.org `sameAs`, or matching the domain name win.
- **Fast and cheap** – plain HTTP requests (no browser), about 10 requests and 3–5 seconds per domain, 10 domains in parallel with polite per-site limits.
- **You only pay for results** – a domain is saved and charged only if at least one email, phone or social profile was found. Unreachable, blocked, parked and empty domains are listed for free in `FAILED_DOMAINS`.

### Use cases

- **Lead generation and enrichment** – you have a list of company domains from a CRM, a trade-show list or a directory; get their generic sales/info address, phone and LinkedIn page in one run.
- **"Hiring signal" outreach** – find companies that are hiring with the [Career Site Jobs Scraper](https://apify.com/artificially/career-site-jobs-scraper), then get their contact channels here.
- **Account research** – pair with the [LinkedIn Company Scraper](https://apify.com/artificially/linkedin-company-scraper) for firmographics and with this actor for the official contact channels.
- **Data hygiene** – verify and refresh the phone numbers, emails and social links stored in your CRM.
- **Local and European businesses** – German, Austrian and Swiss sites publish full contact details in the Impressum; the actor finds and reads it.

### Input

| Field | Type | Description | Default |
|-------|------|-------------|---------|
| `websites` | array | Domains or URLs, e.g. `stripe.com`, `www.hetzner.com`, `https://apify.com/contact` | Required |
| `maxPagesPerDomain` | integer | Pages loaded per website (1–50), most promising first | `10` |
| `includeEmails` | boolean | Extract emails | `true` |
| `emailFilter` | string | `all`, `generic_only` (info@, sales@ …) or `exclude_generic` | `all` |
| `includePhones` | boolean | Extract phone numbers | `true` |
| `includeSocials` | boolean | Extract social profiles | `true` |
| `compactOutput` | boolean | Slim items (domain, company name, email and phone strings, found socials, contact page). Best for AI agents | `false` |
| `sameDomainOnly` | boolean | Stay on the website's host; `false` also follows the company's subdomains | `true` |
| `respectRobotsTxt` | boolean | Skip pages disallowed by robots.txt | `true` |
| `maxConcurrency` | integer | Websites crawled in parallel (1–50) | `10` |
| `proxyConfiguration` | object | Optional Apify Proxy for sites with bot protection | none |

#### Example input

```json
{
    "websites": ["stripe.com", "https://www.manufactum.de", "fancourier.ro", "plausible.io"],
    "maxPagesPerDomain": 10,
    "emailFilter": "all",
    "compactOutput": false
}
```

### Output

One item per company website:

```json
{
    "input": "manufactum.de",
    "domain": "manufactum.de",
    "websiteUrl": "https://www.manufactum.de/",
    "companyName": "manufactum",
    "emails": [
        { "email": "info@manufactum.de", "type": "generic", "isCompanyDomain": true, "sourceUrl": "https://www.manufactum.de/" },
        { "email": "presse@manufactum.de", "type": "generic", "isCompanyDomain": true, "sourceUrl": "https://www.manufactum.de/kontakt-c199446/" }
    ],
    "phones": [
        { "number": "+49 2309 939050", "e164": "+492309939050", "country": "DE", "sourceUrl": "https://www.manufactum.de/" }
    ],
    "socials": {
        "linkedin": null,
        "twitter": null,
        "facebook": "https://www.facebook.com/manufactum",
        "instagram": "https://www.instagram.com/manufactum",
        "youtube": null,
        "tiktok": null,
        "github": null,
        "crunchbase": null
    },
    "contactPageUrl": "https://www.manufactum.de/kontakt-c199446/",
    "contactFormUrl": null,
    "address": {
        "streetAddress": "Hiberniastraße 5",
        "locality": "Waltrop",
        "region": null,
        "postalCode": "45731",
        "country": "DE",
        "full": "Hiberniastraße 5, 45731 Waltrop, DE"
    },
    "pagesCrawled": 6,
    "scrapedAt": "2026-09-23T10:12:44.120Z"
}
```

| Field | Description |
|-------|-------------|
| `input` | The website exactly as you entered it |
| `domain` | The company's registrable domain after redirects (e.g. `ritter-sport.de` → `ritter-sport.com`) |
| `websiteUrl` | The home page URL after redirects |
| `companyName` | From `og:site_name`, schema.org Organization or the page title |
| `emails` | `{ email, type, isCompanyDomain, sourceUrl }`; `type` is `generic` or `personal`. Company-domain emails and emails from contact/imprint pages come first |
| `phones` | `{ number, e164, country, sourceUrl }`; `number` is the international format |
| `socials` | Company profile URL per network, or `null` |
| `contactPageUrl` | The contact page (or the imprint page if there is no contact page) |
| `contactFormUrl` | A page with a contact form (textarea + email field, or an embedded HubSpot/Typeform/Jotform/CF7 form) |
| `address` | Postal address from schema.org Organization/LocalBusiness data, when published |
| `pagesCrawled` | Pages loaded for this domain |

With `compactOutput: true` an item looks like this:

```json
{
    "domain": "apify.com",
    "companyName": "Apify",
    "emails": ["support@apify.com", "hello@apify.com"],
    "phones": [],
    "socials": { "linkedin": "https://www.linkedin.com/company/apify", "twitter": "https://x.com/apify", "github": "https://github.com/apify" },
    "contactPageUrl": "https://apify.com/contact"
}
```

The key-value store also contains:

- `SUMMARY` – hit rates (domains with email/phone/social), average pages, requests, KB and seconds per domain, and per-domain stats.
- `FAILED_DOMAINS` – domains that were not saved, with a reason: `unreachable` (DNS, connection or HTTP errors), `blocked` (bot protection; try a proxy), `blocked_by_robots`, `parked_domain`, `not_html`, `invalid_input`, `no_contacts_found`. These are never charged.

### Pricing

This actor uses pay-per-event pricing: a tiny fee per run plus a fee per company website saved to the dataset. **You only pay for domains where contacts were found** – unreachable, blocked, parked and empty domains cost nothing, and there is no per-page fee no matter how many pages are crawled. Set a maximum cost per run in Apify Console and the actor stops cleanly when it is reached. See the **Pricing** tab for current prices.

### FAQ

**Which pages are crawled?**
The home page, then internal links ranked by how likely they are to contain contact details: contact → imprint/Impressum → about → team → support/press → legal/privacy → careers. If nothing is found, common paths such as `/contact`, `/kontakt` and `/impressum` are tried. Blog posts, product pages, files and login pages are skipped. External websites are never crawled.

**Why is a website missing from the results?**
Check `FAILED_DOMAINS`. The most common reasons are a dead domain (`unreachable`), bot protection (`blocked` – try `proxyConfiguration` with Apify Proxy), a robots.txt that disallows crawling (`blocked_by_robots`), or a website that simply publishes no email, phone or social link (`no_contacts_found`).

**Does it work with JavaScript-heavy sites?**
The actor reads the HTML the server returns, without a browser, which makes it fast and cheap. Most company sites (WordPress, Shopify, Webflow, Next.js, Nuxt and other server-rendered sites) work well. Single-page apps that render everything in the browser may return fewer or no results; `FAILED_DOMAINS` then says the home page is almost empty without JavaScript.

**Are the emails verified?**
Emails are syntax-checked and filtered for junk and placeholders, but not verified by SMTP. They are exactly what the company publishes on its own website.

**Why do some emails have `isCompanyDomain: false`?**
Imprint and privacy pages often list third parties such as the web agency, the data-protection authority or a consumer arbitration board. They are kept but flagged and sorted last, so you can filter them out.

**Is this legal? What about GDPR?**
The actor only collects business contact information that the company itself publishes on its own public website. It does not log in, bypass protection, or visit social networks or third-party sites. Pages disallowed by robots.txt are skipped by default. **You are responsible for how you use the data**: personal data (for example a named employee's email) is regulated by GDPR in the EU/UK and by laws such as CAN-SPAM and CCPA in the US. Make sure you have a lawful basis, honor opt-outs, and prefer `emailFilter: "generic_only"` for cold outreach.

### Support

Found a website where contacts are missed or wrong? Open an issue on the actor's **Issues** tab – we usually respond within a day.

### Related actors

- [LinkedIn Company Scraper](https://apify.com/artificially/linkedin-company-scraper): company profiles with size, industry, headquarters, website and more.
- [LinkedIn Company Employees Scraper](https://apify.com/artificially/linkedin-employees-scraper): people working at a company, to find the right decision maker.
- [Career Site Jobs Scraper](https://apify.com/artificially/career-site-jobs-scraper): open jobs from company career sites (Greenhouse, Lever, Ashby, Workday and more) – find companies that are hiring, then get their contacts here.

# Actor input Schema

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

Required. One company website per entry: a bare domain (e.g. stripe.com), a domain with www (e.g. www.hetzner.com) or a full URL (e.g. https://apify.com or https://apify.com/contact to start on a specific page). http/https and www/non-www are resolved automatically and redirects are followed. Only the company's own website is crawled; do not enter LinkedIn, Facebook or Google Maps URLs. Example: \["stripe.com", "https://www.manufactum.de", "fancourier.ro"].

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

How many pages to load per website, from 1 to 50, including the home page. The actor starts on the home page and then opens the most promising internal pages first (contact, imprint/Impressum, about, team, support, legal/privacy, careers; keywords in 20+ languages). Example: 5 for fast runs, 10 (default) for good coverage, 20 for large sites. More pages means more contacts but a slower run.

## `includeEmails` (type: `boolean`):

Collect email addresses from mailto: links, page text (including obfuscated forms like info \[at] example \[dot] com and Cloudflare-protected emails) and schema.org data. Set to false to skip emails.

## `emailFilter` (type: `string`):

Which emails to keep. "all" keeps every plausible email. "generic\_only" keeps role addresses such as info@, sales@, contact@, support@, office@, press@ (safest for GDPR). "exclude\_generic" keeps only addresses that look personal (e.g. jane.doe@). Each email in the output also carries type (generic or personal) so you can filter later.

## `includePhones` (type: `boolean`):

Collect phone numbers from tel: links, schema.org data and labeled text (e.g. "Tel.: 030 1234567", "Phone: +1 415 555 2671"). Numbers are validated and normalized to E.164 with libphonenumber, using the website's country (from the domain ending, address or page language) for local formats. Fax numbers are skipped. Set to false to skip phones.

## `includeSocials` (type: `boolean`):

Find the company's own profiles on LinkedIn, X/Twitter, Facebook, Instagram, YouTube, TikTok, GitHub and Crunchbase. Share buttons and unrelated profiles are ignored; when several profiles exist the one linked in the header/footer, in schema.org sameAs, or matching the domain name wins. Set to false to skip socials.

## `compactOutput` (type: `boolean`):

Set to true to save a slim item per domain: domain, companyName, emails (plain strings), phones (E.164 strings), socials (only the networks found) and contactPageUrl. Source URLs, email types, address and crawl stats are dropped. Recommended when an AI agent or LLM reads the results. Leave false for the full item.

## `sameDomainOnly` (type: `boolean`):

If true (default), only pages on the website's own host are crawled (www and non-www count as the same). Set to false to also follow links to subdomains of the same company domain, e.g. support.example.com or about.example.com. External websites are never crawled.

## `respectRobotsTxt` (type: `boolean`):

If true (default), pages disallowed by the website's robots.txt are not loaded, and domains that disallow everything are reported in FAILED\_DOMAINS with reason blocked\_by\_robots. Set to false only if you have the right to crawl those pages.

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

How many websites are crawled at the same time, from 1 to 50. Each website still gets at most 2 requests at a time with a short delay between them, to stay polite. Example: 10 (default).

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

Optional. Most company websites work without a proxy. If many domains end up in FAILED\_DOMAINS with reason blocked (bot protection), enable Apify Proxy, e.g. {"useApifyProxy": true} for datacenter or {"useApifyProxy": true, "apifyProxyGroups": \["RESIDENTIAL"]} for residential.

## Actor input object example

```json
{
  "websites": [
    "apify.com",
    "plausible.io",
    "hetzner.com"
  ],
  "maxPagesPerDomain": 10,
  "includeEmails": true,
  "emailFilter": "all",
  "includePhones": true,
  "includeSocials": true,
  "compactOutput": false,
  "sameDomainOnly": true,
  "respectRobotsTxt": true,
  "maxConcurrency": 10
}
```

# Actor output Schema

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

One item per domain with emails, phones, social profiles, contact page and address (overview table view)

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

Per-domain hit counts, pages, requests, bytes and time, plus failure reasons

## `failedDomains` (type: `string`):

Websites that were unreachable, blocked, parked or had no public contacts, with a reason (never charged)

# 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",
        "plausible.io",
        "hetzner.com"
    ],
    "maxPagesPerDomain": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("artificially/company-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 = {
    "websites": [
        "apify.com",
        "plausible.io",
        "hetzner.com",
    ],
    "maxPagesPerDomain": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("artificially/company-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 '{
  "websites": [
    "apify.com",
    "plausible.io",
    "hetzner.com"
  ],
  "maxPagesPerDomain": 10
}' |
apify call artificially/company-contact-extractor --silent --output-dataset

```

## MCP server setup

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