# Company Contact & Enrichment: Emails, Phones, Socials, LEI (`clearfeedlabs/company-contact-enrichment`) Actor

AI-agent & MCP ready: turn company domains into one JSON record each with business emails (MX-checked), E.164 phones, social profiles, LEI and SEC CIK, each with confidence and source URL. Domains with no contacts are free.

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

## Pricing

from $3.00 / 1,000 domain enricheds

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

## Company Contact & Enrichment: emails, phones, socials and LEI from company websites

Paste a list of company domains and get **one clean row per company**:

- business emails, with role addresses like info@ and sales@ by default
- phone numbers in **E.164 format with a country**
- company social profiles
- schema.org company data, address and description
- tech hints
- **GLEIF LEI** and **SEC CIK and ticker** matches

Every value comes with a **confidence score and the page it was found on**. **Domains with no contacts are free**, and incremental mode bills **only companies whose contacts changed**.

### For AI agents & MCP

**Tool summary:** given company domains, read each company's own website (up to 6 pages, robots.txt respected) and return one JSON record of its published business contacts.

**When to call it:** "Get contact info for these companies", "Enrich this lead list", "What's the LEI for this company?"

**Input (key fields):**

- `domains` (array, required)
- `maxPagesPerDomain`, `checkMx`, `matchGleif`, `matchSec`, `defaultCountry`, `maxDomains`
- `suppressionList`; `includePersonalEmails` and `includePersonalLinkedIn` are off by default

**Output (one item per domain):**

- `status` (`ok`, `no_contacts`, `needs_js`, `blocked`, ...), `companyName`, `legalName`, `country`
- `primaryEmail`, `primaryPhone` (E.164)
- `emails[]`, each with `type`, `mx` and `confidence`
- `phones[]`, each with `e164`, `country` and `confidence`
- `linkedin`, `x`, `facebook`, `instagram`, `youtube`, `tiktok`, `github`
- `lei`, `secCik`, `secTickers`
- `thirdPartyEmails` (other organizations' addresses, kept separate)

Every value carries its source URL.

**Call it through Apify's hosted MCP server:** connect your MCP client to `https://mcp.apify.com?tools=clearfeedlabs/company-contact-enrichment` (Apify's server; you'll need your own Apify account). Then:

```json
call-actor { "actor": "clearfeedlabs/company-contact-enrichment",
  "input": { "domains": ["n26.com", "stripe.com"], "checkMx": true, "matchGleif": true } }
```

`call-actor` returns the run and its `datasetId`. Fetch the records with `get-dataset-items { "datasetId": "<id>" }`. You're billed only for domains where contacts are found.

### Why switch

| | This Actor | Typical contact scrapers |
|---|---|---|
| Output shape | One row per company, deduplicated | Often one row per page, so merging is a separate step |
| Billing unit | Per company with contacts found; empty domains free | Often per page crawled |
| Re-checks | Incremental: unchanged companies not billed | Re-bill every run |
| Phones | E.164 plus country; fictional, repeated and sequential numbers dropped | Raw strings, "uncertain" lists |
| Emails | Image, placeholder and tracking addresses dropped; role vs personal labelled; MX checked via DNS | Raw matches |
| Trust signals | Confidence and source URL for every value | Usually a list of pages visited |
| Company data | Name, legal name, address, description, logo, founding date, VAT ID from the site's own structured data | Usually only via paid lead databases |
| Identifiers | GLEIF LEI and SEC CIK/ticker, attached only on unambiguous matches | Rare |
| Privacy defaults | Personal-name emails and personal LinkedIn profiles withheld unless you opt in; suppression list | Everything found is returned |

### What you get

| Field | Example |
|---|---|
| `domain`, `status`, `changeStatus` | `acme.com`, `ok`, `new` |
| `companyName`, `legalName`, `country` | `Acme`, `Acme Inc.`, `US` |
| `primaryEmail`, `emailsJoined` | `sales@acme.com`, `sales@acme.com; support@acme.com` |
| `primaryPhone`, `phonesJoined` | `+14155552671` |
| `linkedin`, `x`, `facebook`, `instagram`, `youtube`, `tiktok`, `github` | company profile URLs |
| `addressText` | `1 Main St, Austin, TX, 78701, US` |
| `lei`, `secCik`, `secTickers` | LEI code, 10-digit CIK, tickers |
| `emails[]` | `{ email, type: role/personal, onCompanyDomain, freemail, mx, confidence, sources[] }` |
| `phones[]` | `{ e164, country, raw, confidence, sources[] }` |
| `socials{}` | per network: `{ url, confidence, sources[] }` |
| `tech` | e.g. `WordPress`, `HubSpot`, `Google Tag Manager` |
| `personalEmailsWithheld` | count of personal-name addresses not returned |

There are three dataset views:

- **Companies**, which is flat and CSV-ready
- **Details**, with confidence and sources
- **Per-domain status**

The run also saves `RUN_SUMMARY` and `DOMAIN_STATUS` records.

#### Status values

| Status | Meaning |
|---|---|
| `ok` | Contacts found |
| `no_contacts` | The site was read but publishes no contacts. Not billed. |
| `robots_disallowed` | The site's robots.txt asks crawlers not to visit, so we didn't |
| `blocked` / `captcha` | The site refused access or showed a challenge. We stop and don't retry around it. |
| `needs_js` | The site only shows content with JavaScript. This version reads HTML only. |
| `unreachable` | DNS, TLS, timeout or a server error |
| `suppressed` | The domain is on your suppression list |
| `not_processed` | Your run spending limit was reached. Not billed; re-run to continue. |

### Popular uses

Ready-made examples you can run as-is or copy with your own domains:

- [SaaS company emails & phones](https://apify.com/clearfeedlabs/company-contact-enrichment/examples/saas-company-emails-phones): Atlassian, HubSpot, Stripe, Xero, Plausible, Buffer
- [Restaurant contact info](https://apify.com/clearfeedlabs/company-contact-enrichment/examples/restaurant-contact-info): emails, phones and socials from restaurant and cafe sites
- [B2B lead enrichment from a domain list](https://apify.com/clearfeedlabs/company-contact-enrichment/examples/b2b-lead-enrichment-domain-list): one row per company for your CRM
- [Company LEI & registry lookup](https://apify.com/clearfeedlabs/company-contact-enrichment/examples/company-lei-registry-lookup): GLEIF LEI and SEC CIK, checked against each site's legal name
- [EU & UK company contacts](https://apify.com/clearfeedlabs/company-contact-enrichment/examples/eu-company-contacts): N26, Zalando, Sennheiser, Monzo, Octopus Energy

### How to use

**Enrich a CRM export**

```json
{ "domains": ["acme.com", "globex.com, Globex Corporation", "https://initech.com/about"] }
```

**Weekly watchlist, billed only for changes**

```json
{ "domains": ["acme.com", "globex.com"], "incremental": true, "stateKey": "q4-accounts" }
```

**US public-company matching** is on by default (SEC CIK and tickers). Turn it off with `"matchSec": false`.

**Honor opt-outs**

```json
{ "domains": ["acme.com"], "suppressionList": ["ceo@acme.com", "do-not-contact.com"] }
```

Use cases:

- enriching CRM accounts
- filling out lead lists from the ATS Jobs Feed or Form D filings
- vendor due diligence (LEI)
- agency prospecting
- research datasets

### Pricing

Pay per event:

- **One event per company returned with at least one contact.** Companies with no contacts, and blocked or unreachable sites, are free.
- Duplicate inputs are merged, so each company is billed once per run.
- In incremental mode, unchanged companies are free.
- Set a maximum cost per run in Apify Console, and the Actor stops cleanly when it's reached.

See the Pricing tab for the current price.

### API and AI agents

Call the Actor from the Apify API, the JavaScript or Python clients, or the Apify MCP server. With MCP, an agent can say "Get contact details for these 20 domains and list the ones with a sales@ address." Read results from the `overview` view.

### Responsible use and compliance

- **We only collect what companies publish on their own public websites.** That means public pages only, no logins, and a small number of pages per site.
- **We respect each site's crawling preferences.** We follow robots.txt, identify ourselves honestly, keep the request rate low, and stop when a site refuses access.
- **We use no proxies and no CAPTCHA solving.** We don't circumvent sites' anti-harvesting measures.
- **Privacy-first defaults.** Only role addresses are returned unless you opt in. We support a suppression list. Mail domains are checked by DNS only, and we never probe mail servers.
- **You're responsible for how you use the data.** Business contact data can still be personal data under the GDPR, the CCPA and similar laws. You need a lawful basis, and you must give notice where required and honor opt-out and deletion requests. Follow CAN-SPAM, CASL, PECR and other anti-spam rules, and respect the terms of the websites you process.
- This README is **not legal advice**.
- We're not affiliated with GLEIF, the U.S. SEC, or any website processed.
- Registry matches are only attached when the name match is unambiguous. They are provided as-is.

### FAQ

**Is it legal to scrape contact details?** Collecting publicly published business contact data is generally lower risk than collecting personal data, but the rules depend on your country and use. That's why personal-name data is off by default. Ask your own counsel.

**Why are some fields empty?** Many sites publish only a contact form. The row still shows the socials, address and company data the site publishes.

**Why was a domain skipped?** Check `status` and `statusReason`. For example, the site's robots.txt asked crawlers to stay out.

***

Built and maintained by **Clearfeed Labs**: clean, compliant data feeds. Questions or bugs? Use the Issues tab.

# Actor input Schema

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

One per line: a domain (acme.com), a URL, or 'domain, Company Name' to help registry matching. Duplicates are merged, so each company is processed and billed once.

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

Homepage plus the most relevant contact, about, imprint and team pages. Capped at 10 to keep the load on each site light.

## `includePersonalEmails` (type: `boolean`):

Off by default: only role addresses such as info@, sales@ or support@ are returned, and named-person addresses are counted but withheld. Turn on only if you have a lawful basis to process personal data (GDPR/CCPA).

## `includePersonalLinkedIn` (type: `boolean`):

Off by default: only LinkedIn company pages are returned.

## `includeThirdPartyEmails` (type: `boolean`):

Off by default: only addresses on the company's own domain (or free-mail addresses it publishes) go in the email fields. Addresses on other domains, such as vendors, regulators or charities linked from the site, are listed separately in thirdPartyEmails.

## `suppressionList` (type: `array`):

Emails or domains that must never be returned (for example people or companies who opted out). Matching domains are not crawled at all.

## `checkMx` (type: `boolean`):

DNS lookup only. The Actor never connects to mail servers and never sends SMTP probes.

## `matchGleif` (type: `boolean`):

Look up the company's Legal Entity Identifier in GLEIF's public register. Only exact, unambiguous name matches are attached.

## `secContactEmail` (type: `string`):

Optional. The SEC asks automated users to declare a contact in the User-Agent; Clearfeed Labs' operational address is used if you leave this empty.

## `incremental` (type: `boolean`):

Remembers each domain's contact fingerprint between runs. Unchanged domains are not billed.

## `stateKey` (type: `string`):

Name for this watchlist's memory, so separate lists don't mix.

## `outputUnchanged` (type: `boolean`):

In incremental mode, also write unchanged rows (not billed).

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

Two-letter code (US, GB, DE...) used to read national-format numbers when a site gives no country signal.

## `maxDomains` (type: `integer`):

Hard cap on domains processed in this run.

## `matchSec` (type: `boolean`):

Match US public companies to their SEC CIK and tickers using the SEC's published company list (one download per run).

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "basecamp.com, Basecamp",
    "stripe.com"
  ],
  "maxPagesPerDomain": 6,
  "includePersonalEmails": false,
  "includePersonalLinkedIn": false,
  "includeThirdPartyEmails": false,
  "suppressionList": [],
  "checkMx": true,
  "matchGleif": true,
  "incremental": false,
  "stateKey": "default",
  "outputUnchanged": false,
  "maxDomains": 1000,
  "matchSec": true
}
```

# Actor output Schema

## `companies` (type: `string`):

No description

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

No description

## `domainStatus` (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 = {
    "domains": [
        "apify.com",
        "basecamp.com, Basecamp",
        "stripe.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("clearfeedlabs/company-contact-enrichment").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": [
        "apify.com",
        "basecamp.com, Basecamp",
        "stripe.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("clearfeedlabs/company-contact-enrichment").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": [
    "apify.com",
    "basecamp.com, Basecamp",
    "stripe.com"
  ]
}' |
apify call clearfeedlabs/company-contact-enrichment --silent --output-dataset

```

## MCP server setup

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

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/YwS1HQzwWa475bWzD/builds/4sS5TGAznVlugqguk/openapi.json
