# Business Email Enricher - Emails, Phones & Socials (`halvenlabs/business-email-enricher`) Actor

Turn a plain list of business website URLs into enriched B2B leads. Visits each site's homepage and contact/about pages to extract email addresses (incl. Cloudflare-obfuscated), phone numbers, and social media profiles — the perfect second step after a Google Maps or directory scraper.

- **URL**: https://apify.com/halvenlabs/business-email-enricher.md
- **Developed by:** [Halven Labs](https://apify.com/halvenlabs) (community)
- **Categories:** Lead generation, Developer tools, Automation
- **Stats:** 16 total users, 16 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Business Email Enricher — Emails, Phones & Socials from Website URLs

Turn a plain list of **business website URLs into enriched B2B leads**. For each site, this actor visits the homepage and its contact/about pages and extracts **email addresses, phone numbers, and social media profiles** (Facebook, X/Twitter, LinkedIn, Instagram, YouTube, TikTok, Pinterest, Telegram, WhatsApp, Discord, Snapchat, Threads, Reddit).

The perfect **second step after a Google Maps / directory scraper**: feed in the `website` column, get back contactable leads. Export to **CSV, Excel, JSON, or Google Sheets**.

***

### 🎯 Why use this actor

- **Get leads, not just a list of businesses** — turn plain company websites into actual contact points (email, phone, socials) ready for outreach.
- **Skip hours of manual "find the contact page" work** — the actor visits contact/about pages for you, across hundreds of sites in one run.
- **Drop straight into your existing pipeline** — designed to plug directly into Google Maps / directory scraper output, no reformatting needed.

***

### ✨ Features

- **Email extraction that actually works** — finds `mailto:` links, plain-text emails, and even **Cloudflare-obfuscated** addresses. Aggressively filters out junk (image filenames, placeholder/CDN domains).
- **Contact & about page crawling** — most emails aren't on the homepage, so the actor automatically follows likely contact/about/impressum pages.
- **Social profiles** — first profile URL per network, found in links *and* in JS/JSON blobs, ignoring share/embed noise.
- **Phone numbers** — high-precision extraction from `tel:` links.
- **Flexible input** — accepts bare domains, full URLs, or objects with a `website`/`url` field (drop-in for Google Maps scraper output).
- **Robust** — unreachable sites are recorded (not charged) and never crash the run.
- **Bounded** — `maxItems` and `maxPagesPerSite` cap time and cost exactly.

***

### 🚀 Quick start

1. Paste your business website URLs into **Business website URLs**.
2. (Optional) Adjust **Max pages per site** or enable **Only output sites where an email was found**.
3. Click **Start**. The default input runs successfully with zero edits.

#### Example input

```json
{
  "websiteUrls": [
    "https://acme-plumbing.com",
    "https://www.example-dentist.com"
  ],
  "maxItems": 100,
  "maxPagesPerSite": 3,
  "onlyWithEmail": false,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `websiteUrls` | array | *(required)* | Website URLs (bare domain, full URL, or objects with a `website`/`url` field). |
| `maxItems` | integer | `100` | Max websites to enrich. `0` = no limit. |
| `maxPagesPerSite` | integer | `3` | Homepage + up to (this − 1) contact/about pages. |
| `onlyWithEmail` | boolean | `false` | Skip (and don't charge for) sites with no email found. |
| `proxyConfiguration` | object | Apify Proxy (auto) | Proxy settings. |

***

### 📦 Output

One flat row per website:

```json
{
  "inputUrl": "https://www.basecamp.com",
  "finalUrl": "https://basecamp.com/",
  "domain": "basecamp.com",
  "companyName": "Basecamp",
  "primaryEmail": "jason@basecamp.com",
  "emails": "jason@basecamp.com, support@basecamp.com",
  "emailCount": 2,
  "emailFound": true,
  "phones": "+1 312-555-0100",
  "facebook": "https://www.facebook.com/basecamp",
  "twitter": "https://twitter.com/basecamp",
  "linkedin": "https://www.linkedin.com/company/basecamp",
  "instagram": null,
  "youtube": null,
  "tiktok": null,
  "pinterest": null,
  "telegram": null,
  "whatsapp": null,
  "discord": null,
  "snapchat": null,
  "threads": null,
  "reddit": null,
  "pagesCrawled": 3,
  "status": "ok"
}
```

`status` is `ok` for reachable sites and `unreachable` for sites that failed to load (those rows are **not charged**).

#### Output fields

| Field | Type | Description |
|-------|------|-------------|
| `inputUrl` | string | The URL/domain you supplied. |
| `finalUrl` | string | null | URL after redirects, when reachable. |
| `domain` | string | Bare domain. |
| `companyName` | string | null | From `og:site_name` or page title. |
| `primaryEmail` | string | null | Best-guess primary contact email. |
| `emails` | string | All found emails, comma-separated. |
| `emailCount` | number | Count of emails found. |
| `emailFound` | boolean | Whether any email was found. |
| `phones` | string | Phone number(s) found, comma-separated. |
| `facebook` / `twitter` / `linkedin` / `instagram` / `youtube` / `tiktok` / `pinterest` / `telegram` / `whatsapp` / `discord` / `snapchat` / `threads` / `reddit` | string | null | First profile URL per network. |
| `pagesCrawled` | number | Pages actually visited for this site. |
| `status` | string | `ok` or `unreachable`. |

***

### 💡 Use cases

- **Lead generation** — enrich scraped business listings with direct contact details.
- **Cold outreach** — build targeted email/social lists for sales and partnerships.
- **CRM enrichment** — fill missing contact fields for existing accounts.
- **Recruiting & partnerships** — find the right inbox and social profiles fast.

***

### 🔗 Works great with

- **Google Maps scrapers** — pipe the `website` field straight in.
- **Directory / Yellow Pages scrapers** — enrich any list of company sites.

***

### 💳 Pricing (pay-per-event)

| Event | Price |
|-------|-------|
| Actor start | $0.005 per run |
| Website enriched | $0.004 per reachable site |

Enriching 1,000 websites costs about **$4.01**. Unreachable sites are recorded free of charge. Set `maxItems` to cap spend.

***

### ❓ FAQ

**Why didn't it find an email for some sites?**
Many businesses hide emails behind contact forms or images. This actor extracts real, publicly listed addresses (including Cloudflare-protected ones) but can't read data that isn't published as text.

**Can I feed in Google Maps scraper output directly?**
Yes — pass the objects (it reads the `website`/`url` field) or just the website strings.

**How do I get more emails per site?**
Increase `maxPagesPerSite` so the actor crawls more contact/about pages.

***

### ⚖️ Legal

This actor collects only publicly available business contact information from public web pages. You are responsible for using the data in compliance with applicable laws (including GDPR, CAN-SPAM, and local anti-spam rules) and each website's terms. Do not use extracted emails for unsolicited bulk messaging where prohibited.

# Actor input Schema

## `websiteUrls` (type: `array`):

List of business website URLs to enrich (e.g. the 'website' column from a Google Maps scraper export). The actor visits each site's homepage plus likely contact/about pages and extracts emails, phone numbers, and social links.

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

Maximum number of websites to enrich in this run (the input list is capped to this many sites). Use 0 for no limit. Note: with 'Only with email' enabled, the run can return fewer rows than this, since sites without an email are crawled but not output.

## `maxPagesPerSite` (type: `integer`):

How many pages to visit per website: the homepage plus up to (this minus one) contact/about pages. Higher finds more emails but costs more time. 3 is a good balance.

## `onlyWithEmail` (type: `boolean`):

If enabled, sites where no email could be found are skipped (and not charged). If disabled (default), every reachable site produces a row with whatever contact data was found.

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

Proxy settings. Apify Proxy (auto) is recommended and enabled by default to avoid rate limits and geo-blocks.

## Actor input object example

```json
{
  "websiteUrls": [
    "https://acme-plumbing.com",
    "https://www.example-dentist.com"
  ],
  "maxItems": 100,
  "maxPagesPerSite": 3,
  "onlyWithEmail": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One flat row per website: emails, phones, and social profiles found.

# 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 = {
    "websiteUrls": [
        "https://www.basecamp.com",
        "https://www.patagonia.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("halvenlabs/business-email-enricher").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 = { "websiteUrls": [
        "https://www.basecamp.com",
        "https://www.patagonia.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("halvenlabs/business-email-enricher").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "websiteUrls": [
    "https://www.basecamp.com",
    "https://www.patagonia.com"
  ]
}' |
apify call halvenlabs/business-email-enricher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=halvenlabs/business-email-enricher",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/OrLKc5dOVGgZumcqC/builds/UFKSNgTcusK7zRdf0/openapi.json
