# Company Website Contact Extractor (`vex_workflow/company-contact-extractor`) Actor

Get company emails, phone numbers, social profiles and address from any list of business websites. Reads the home, contact, about and imprint pages. Business inboxes only (info@, sales@...). Pay only for websites where contacts were found.

- **URL**: https://apify.com/vex_workflow/company-contact-extractor.md
- **Developed by:** [Ian McCann](https://apify.com/vex_workflow) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 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/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

### What does Company Website Contact Extractor do?

Give it a list of company websites. For each one it reads the home page and the pages most likely to hold contact details (contact, about, imprint, support, locations) and returns **one clean row per company** with:

- **Business emails** such as info@, sales@, support@, hello@
- **Phone numbers** from click-to-call links and the site's structured data
- **Social profiles** (company pages on the major networks, code hosting and video channels)
- **Postal address** when the site publishes it in structured data
- Company name, description and the contact page URL

You pay **only for websites where at least one contact was found**. Dead sites, empty sites and sites that ask crawlers to stay out cost nothing beyond the small start fee.

### Who is it for?

- Sales and agency teams enriching a list of target accounts
- Marketers building outreach lists from a domain export
- CRM cleanup: fill missing phone numbers and social links for existing accounts
- AI agents that need a company's contact channels from a domain in one call

### How to use it

1. Paste websites or bare domains into **Websites**, one per line (`acme.com`, `https://www.acme.com`).
2. Optional: change **Max pages per website** (default 6) and **Websites in parallel** (default 10).
3. Click **Start**. Download results as JSON, CSV, Excel or HTML, or read them through the API.

#### Input example

```json
{
  "websites": ["apify.com", "wordpress.org", "mozilla.org"],
  "maxPagesPerSite": 6
}
```

#### Output example

```json
{
  "inputUrl": "acme.com",
  "website": "https://www.acme.com/",
  "domain": "acme.com",
  "companyName": "Acme Inc.",
  "emails": ["info@acme.com", "sales@acme.com"],
  "phones": ["+1 512 555 0100"],
  "socialProfiles": { "linkedin": "https://linkedin.com/company/acme", "x": "https://x.com/acme" },
  "address": "1 Main St, Austin, TX, 78701, US",
  "contactPageUrl": "https://www.acme.com/contact",
  "pagesChecked": 4,
  "personalEmailsWithheld": 1,
  "status": "ok"
}
```

### How much does it cost?

Pay per event:

| Event | Price |
|---|---|
| Actor start | $0.001 per run |
| Website with contacts | **$0.004** per website where something was found |

1,000 websites where contacts are found cost about **$4**. Websites with no contacts, unreachable websites and websites blocked by robots.txt are not charged. You can set a maximum cost per run in the run options and the Actor stops cleanly when it is reached.

### Privacy by design

- Only **role-based business inboxes** are returned (info@, sales@, support@ and similar). Addresses that look like a named person's email are counted in `personalEmailsWithheld` and **not output**.
- Phone numbers come only from click-to-call links and structured data that the business publishes for customers.
- robots.txt is respected by default. No logins, no form submissions, no anti-bot circumvention.
- You are responsible for using the contacts in line with the laws that apply to you, such as anti-spam and data-protection rules.

### Tips

- Bare domains are fine. The Actor follows redirects to the real home page.
- Raise **Max pages per website** to 10-15 for large corporate sites with many regional contact pages.
- Run it on a schedule against your CRM export to keep contact data fresh.

### FAQ

**Why is a website marked `no-contacts-found`?** The pages read had no business email, click-to-call phone or social link. Some sites only offer a contact form.

**Why `unreachable`?** The site did not answer, returned an error, or blocks automated visitors. We do not try to get around blocks.

**Does it find personal emails of employees?** No, on purpose.

# Actor input Schema

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

Company websites or domains, one per line. Example: acme.com or https://www.acme.com

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

The home page plus contact, about, imprint and support pages found on it.

## `concurrency` (type: `integer`):

How many websites to process at the same time.

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

Skip pages the website asks crawlers not to visit.

## Actor input object example

```json
{
  "websites": [
    "apify.com",
    "wordpress.org"
  ],
  "maxPagesPerSite": 6,
  "concurrency": 10,
  "respectRobotsTxt": true
}
```

# Actor output Schema

## `dataset` (type: `string`):

One row per website with business emails, phone numbers, social profiles and address.

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

Run summary with counts of websites processed, with contacts, with none and unreachable.

# 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",
        "wordpress.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("vex_workflow/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",
        "wordpress.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("vex_workflow/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",
    "wordpress.org"
  ]
}' |
apify call vex_workflow/company-contact-extractor --silent --output-dataset

```

## MCP server setup

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