# Website Contact Finder — Emails, Phones & Socials (`nobin2k/website-contacts`) Actor

Turn a list of company websites into contact records: emails, phone numbers and social profiles, with each address labelled by how it was found.

- **URL**: https://apify.com/nobin2k/website-contacts.md
- **Developed by:** [Trần Chính](https://apify.com/nobin2k) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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

## Website Contact Finder — Emails, Phones & Socials

Give it a list of company websites; get back a contact record for each one:
emails, phone numbers, social profiles, company name and description.

**Every address is labelled by how it was found.** An address taken from a
`mailto:` link is the company telling you where to write. An address scraped out
of page text is a guess. Most contact scrapers hand you one undifferentiated
column; this one tells you which is which, so your outreach list can be filtered
by confidence instead of hope.

### Why the output is clean

The naive way to build this is an email regex and a phone regex over the HTML.
On real sites that returns image filenames as emails and order IDs as phone
numbers — measured on five well-known sites, the naive approach produced
**78 to 202 phone numbers per site**, none of them real.

This Actor takes phone numbers only from `tel:` links, drops hashes, tracking
addresses, `noreply@`, `example.com` and image filenames, and repairs the escape
debris (`u003esupport@…`) that leaks out of inline scripts. Same five sites:
**zero false phone numbers.**

### Output

```json
{
  "domain": "ahrefs.com",
  "website": "https://ahrefs.com",
  "company_name": "Ahrefs",
  "description": "Ahrefs is an all-in-one SEO toolset.",
  "primary_email": "pr@ahrefs.com",
  "emails": [
    {"email": "pr@ahrefs.com", "source": "mailto", "is_role_address": true,
     "on_company_domain": true, "found_on": "https://ahrefs.com/contact"},
    {"email": "support@ahrefs.com", "source": "page_text", "is_role_address": true,
     "on_company_domain": true, "found_on": "https://ahrefs.com"}
  ],
  "emails_count": 2,
  "phones": [{"phone": "+15125550123", "source": "tel", "found_on": "https://ahrefs.com/contact"}],
  "phones_count": 1,
  "social_profiles": {
    "linkedin": "https://linkedin.com/company/ahrefs",
    "x": "https://x.com/ahrefs",
    "facebook": "https://facebook.com/ahrefs"
  },
  "pages_checked": 4,
  "has_contact": true
}
```

Emails are ranked: declared (`mailto`) before guessed, company domain before
free mail, role addresses (`info@`, `sales@`) before personal ones.

### Use it for

- **Lead generation** — turn a list of companies into an outreach list
- **CRM enrichment** — fill in missing contact fields on accounts you already have
- **Partner and supplier research** — find who to contact at a list of vendors
- **Data cleaning** — check which domains in an old list are still alive

### Input

```json
{
  "domains": ["stripe.com", "https://www.basecamp.com", "ahrefs.com"],
  "extraPages": 4,
  "onlyCompanyDomain": true,
  "skipWithoutContact": true
}
```

| Field | What it does |
|---|---|
| **Company websites** | Any format — bare domain, full URL, with or without `www` |
| **Extra pages to check** | Tries `/contact`, `/about`, `/impressum` and similar |
| **Only company-domain emails** | Drops gmail and agency addresses |
| **Skip sites with no contact** | Keeps dead ends out of your dataset, so you don't pay for them |

### Speed

Dead domains are the tax on every lead list. This Actor treats a DNS failure or
a timeout as final rather than retrying it four times — which took one test run
from **407 seconds down to 30**.

### Reliability

- Retries genuine network errors with exponential backoff; does not retry
  failures that cannot heal
- Unreachable sites are reported and **never charged**
- If every site fails, the run fails loudly instead of returning an empty dataset

### Pricing

Pay per domain returned. No subscription.

### FAQ

**Why do some big companies return no email?**
Many large firms deliberately publish only a contact form. The Actor reports
that honestly rather than inventing an address.

**Can it find a specific person's email?**
No. It returns what the website publishes — usually role addresses. It does not
guess patterns like `firstname.lastname@`, which is how most lists end up full
of bounces.

**Is this legal?**
It reads publicly published contact details. Business contact data is still
personal data under GDPR, so if you email EU recipients you need your own lawful
basis. You are the controller; check your local rules before sending.

# Actor input Schema

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

One company website per line. 'stripe.com', 'https://www.stripe.com' and 'www.stripe.com/pricing' all work — anything is reduced to its domain.

## `extraPages` (type: `integer`):

Besides the homepage, how many likely contact pages to try (/contact, /about, /impressum and so on). More pages find more addresses and cost more time.

## `onlyCompanyDomain` (type: `boolean`):

Drops gmail, outlook and agency addresses that happen to appear on the page.

## `skipWithoutContact` (type: `boolean`):

Leaves dead ends out of your dataset entirely, so you only pay for rows worth having.

## `proxyUrl` (type: `string`):

Optional. Only needed for very large lists.

## Actor input object example

```json
{
  "domains": [
    "stripe.com",
    "basecamp.com",
    "ahrefs.com"
  ],
  "extraPages": 4,
  "onlyCompanyDomain": false,
  "skipWithoutContact": false
}
```

# Actor output Schema

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

One record per website with emails, phones and social profiles.

## `csv` (type: `string`):

The same rows as a spreadsheet-ready CSV download.

## `consoleUrl` (type: `string`):

Browse and filter the results in the 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 = {
    "domains": [
        "stripe.com",
        "basecamp.com",
        "ahrefs.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nobin2k/website-contacts").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": [
        "stripe.com",
        "basecamp.com",
        "ahrefs.com",
    ] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nobin2k/website-contacts"
        }
    }
}
```

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/kiRUTDhr0Ddc9aIyl/builds/VZsGvtZaad4dEv3r2/openapi.json
