# Contact Enrichment ✅ Bulk Email & Phone Finder ✅ Any Field (`lead_king/contact-enrichment`) Actor

🔥 Enrich any list by matching on the fields you ALREADY have — name + company, email, phone, address or LinkedIn. Get verified ☎️ mobile numbers ✅ work & personal emails. Pay only for contacts found. Apollo, ZoomInfo, Lusha, Clay & Seamless alternative.

- **URL**: https://apify.com/lead_king/contact-enrichment.md
- **Developed by:** [Lead King](https://apify.com/lead_king) (community)
- **Categories:** Lead generation, Agents
- **Features:** Limited permissions
- **Stats:** 435 total users, 135 monthly users, 97.8% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $35.00 / 1,000 contact matches

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

## Contact Enrichment ✅ Bulk Email & Phone Finder — LinkedIn, Email or Phone 🎯

**Enrich the list you already have.** LinkedIn URLs but no emails? A
column of phone numbers with no names? A half-finished CRM export? Send it in
and get back **☎️ direct phone numbers, ✅ verified work emails**, job titles,
and company data — matched against a database of **hundreds of
millions of professional profiles**.

A pay-as-you-go alternative to **Apollo, ZoomInfo, Lusha, Clay, Seamless,
Hunter, Dropcontact and Clearbit** — no subscription, no seats, no export
credits, no API key. **You pay only for contacts actually found.**

### 🧑‍💼 What does this Contact Enrichment Actor do?

Real lists are messy: some rows have a LinkedIn URL, some an email, some only
a phone number. This Actor takes **whichever identifier each row has** —
LinkedIn URL, email, phone, or name + company domain — finds the person, and
then **checks the match against the other columns you supplied** (name,
company, city, state) so you're never billed for the wrong person.

Export to **CSV, Excel, or JSON**, or push straight into your CRM.

### ⚖️ Why use this instead of Apollo, ZoomInfo, or Clay?

| | This Actor | Apollo / ZoomInfo / Clay |
| --- | --- | --- |
| **Pricing** | Pay per contact found | Monthly subscription + credits |
| **Minimum spend** | Cents | $50–$15,000+/year |
| **Lookup by** | LinkedIn URL, email, phone, or name + domain | Usually one fixed identifier |
| **Failed matches** | **Free** — you're never charged | Often burns a credit anyway |
| **Setup** | Click Start | Sales calls, seats, contracts |
| **Export limits** | None — it's your dataset | Credit-capped exports |

### 🔑 What can I match on?

Each record needs **one lookup identifier** (strongest is tried first):

| Lookup field | Example |
| --- | --- |
| `linkedin_url` | `https://linkedin.com/in/janedoe` |
| `email` | `jane@acme.com` |
| `phone` | `+15555550123` |
| `first_name` + `last_name` + `company_domain` | `Jane`, `Doe`, `acme.com` |

Any of these extra fields **verify** the person found:

| Verification field | Example |
| --- | --- |
| `first_name` / `last_name` | `Jane` / `Doe` |
| `company_name` | `Acme Corp` |
| `company_domain` / `email_domain` | `acme.com` |
| `personal_city` | `Austin` |
| `personal_state` | `TX` |

✨ **Your existing column names usually just work.** `Full Name`, `Company`,
`Work Email`, `Mobile`, `LinkedIn`, `State` and dozens more are recognized
automatically. Anything unusual can be pointed at the right field with the
**Field mapping** input. Extra columns are ignored — paste a whole CRM export
without cleaning it up first.

### 📥 Example input

```json
{
  "records": [
    { "first_name": "Jane", "last_name": "Doe", "company_domain": "acme.com" },
    { "linkedin_url": "https://linkedin.com/in/johnsmith", "Company": "Globex" },
    { "phone": "+15555550123" },
    { "Work Email": "maria@globex.com", "Full Name": "Maria Garcia" }
  ],
  "requireEmail": true
}
```

### 🕵️ What data do I get for each contact?

- 👤 **Full name** (first & last) and LinkedIn headline
- 💼 **Verified work email** — never pattern-guessed
- 📞 **Direct / mobile phone** (US numbers)
- 🎯 **Job title** (current role)
- 🏢 **Company**, company domain, company LinkedIn page
- 📍 **City, state, country**
- 🔗 **LinkedIn URL**

Output sample:

```json
{
  "matched": true,
  "fullName": "Jane Doe",
  "email": "jdoe@acmecorp.com",
  "businessEmail": "jdoe@acmecorp.com",
  "phone": "+15550101234",
  "jobTitle": "VP of Marketing",
  "company": "Acme Corp",
  "companyDomain": "acmecorp.com",
  "linkedinUrl": "https://linkedin.com/in/janedoe",
  "city": "Austin",
  "state": "TX",
  "country": "US",
  "input": { "first_name": "Jane", "last_name": "Doe", "company_domain": "acme.com" }
}
```

Every row carries the `input` filter that produced it, so you can join results
straight back onto your source list. Records that match nothing stay in the
dataset with `matched: false` — you can see exactly what didn't resolve.

### 🎚️ Match verification

- **On (default)** — if the person found for a row's LinkedIn URL / email /
  phone contradicts another field you supplied (a different first name, a
  different company), the row is reported as `matched: false` and you are
  **not charged**. Fields the profile doesn't have are never held against it.
- **Off** (`matchAny: true`) — accept the person found for the identifier
  regardless of the other columns. Useful when your names or companies are
  stale (people change jobs).

### 💰 Pricing — you only pay for what you find

Pay-per-event: you're charged **only for contacts actually returned**.

- ❌ Input records that match nothing → **free**
- ✅ Set `requireEmail: true` → never pay for phone-only records
- ✅ Set `requirePhone: true` → never pay for email-only records
- 🎯 One row in, at most one contact out — no paying for "alternates"

Rows without a lookup identifier (e.g. only a company domain) are answered
with a clear message, free, instead of guessing at strangers.

### 💡 Tips for the best match rate

- **LinkedIn URL matches best**, then work email, then phone.
- **Any LinkedIn URL form works** — `www.`, no `www.`, trailing slash or not.
- **Add a name or company** to have every match double-checked for free.
- **Turn verification off** for rows that fail on stale data — e.g. someone
  who has since changed companies.

### ❓ FAQ

**Do I need an API key?** No. Just Apify credits — everything else is handled
for you.

**What if a record doesn't match?** It's returned with `matched: false` and an
explanation, and you are not charged for it.

**Can I run a whole CSV through this?** Yes. Upload it as the `records` input;
unrecognized columns are ignored, so most exports work as-is.

**Is this GDPR/CCPA compliant to use?** You are responsible for having a lawful
basis for processing and contacting the people you enrich. Use it for
legitimate B2B outreach and honor opt-outs.

# Actor input Schema

## `records` (type: `array`):

One object per person to look up. Each record needs a lookup identifier: linkedin_url, email or phone (or first_name + last_name + company_domain). Any other fields you include — first_name, last_name, company_name, company_domain, email_domain, personal_city, personal_state — are used to verify that the person found is the right one. Common column names (Full Name, Company, Mobile, LinkedIn…) are recognized automatically; anything else can be mapped with Field mapping below. Unrecognized columns are ignored.

## `fieldMapping` (type: `object`):

Map your own column names onto database match fields, e.g. {"Work Email": "email", "Acct": "company_name"}. Only needed when a column isn't recognized automatically.

## `matchAny` (type: `boolean`):

Off (default): if the person found for a record's LinkedIn URL / email / phone contradicts another field you supplied (e.g. a different first name or company), the record is reported as not matched and you are not charged. On: accept the person found for the identifier regardless of the other fields.

## `requireEmail` (type: `boolean`):

Skip (and don't charge for) matched contacts that have no email address.

## `requirePhone` (type: `boolean`):

Skip (and don't charge for) matched contacts that have no phone number.

## Actor input object example

```json
{
  "records": [
    {
      "linkedin_url": "https://www.linkedin.com/in/satyanadella",
      "first_name": "Satya",
      "last_name": "Nadella",
      "company_name": "Microsoft"
    }
  ],
  "fieldMapping": {},
  "matchAny": false,
  "requireEmail": false,
  "requirePhone": false
}
```

# Actor output Schema

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

Open the dataset of matched contacts.

## `resultsConsole` (type: `string`):

Browse the matched contacts in the Apify Console.

# 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 = {
    "records": [
        {
            "linkedin_url": "https://www.linkedin.com/in/satyanadella",
            "first_name": "Satya",
            "last_name": "Nadella",
            "company_name": "Microsoft"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("lead_king/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 = { "records": [{
            "linkedin_url": "https://www.linkedin.com/in/satyanadella",
            "first_name": "Satya",
            "last_name": "Nadella",
            "company_name": "Microsoft",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("lead_king/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 '{
  "records": [
    {
      "linkedin_url": "https://www.linkedin.com/in/satyanadella",
      "first_name": "Satya",
      "last_name": "Nadella",
      "company_name": "Microsoft"
    }
  ]
}' |
apify call lead_king/contact-enrichment --silent --output-dataset

```

## MCP server setup

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