# Website Contact Finder: Role Emails, Business Phones, Socials (`ethical_acumen/website-contact-finder`) Actor

Finds the organization-level contact points a company publishes on its own website: generic role mailboxes (info@, sales@, support@), business phone lines and company social pages, with a DNS/MX pre-check. Personal emails, mobiles and personal profiles are excluded by design.

- **URL**: https://apify.com/ethical_acumen/website-contact-finder.md
- **Developed by:** [ITEC Consulting](https://apify.com/ethical_acumen) (community)
- **Categories:** Business, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 website with company contact founds

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

## Website Contact Finder: Role Emails, Business Phones, Socials

Get a company's published contact points (info@/sales@/support@ role mailboxes, business phone lines and company social pages) from websites you list, each with the page it came from. You pay $0.004 only when a role email or business phone is found.

Find the contact points a company publishes on its own website. Give it a list of company websites. For each site it returns:

- generic role mailboxes such as `info@`, `sales@` and `support@`, each with a DNS/MX pre-check;
- business phone lines, both switchboard and toll-free;
- the company's social pages;
- the page where each item was found.

**What it returns:** organization-level contact points only. These are generic role mailboxes (info@ and similar), business phone lines and company social pages, published on the websites you supply. It intentionally excludes personal email addresses, personal mobiles and personal profiles.

### What you can use it for

- **Vendor and partner research.** Find the right sales, support or partnerships channel for a list of companies.
- **CRM and company-record hygiene.** Fill in or check the main email, phone and social links on company records.
- **Support or press contact discovery.** Find where to reach a company's customer service or press team.
- **Compliance and KYB contact discovery.** Collect a counterparty's published contact points and imprint page.

### Input

| Field | What it does |
|---|---|
| **Websites** (required) | One per line: `acme.com`, `www.acme.com` or `https://acme.com/en/`. Duplicates are merged and not charged twice. |
| Max pages per website | The homepage plus up to 5 contact, about, imprint/impressum or legal pages on the same site. 6 is the maximum. |
| Include business phone numbers | On by default. Mobile numbers are always excluded. |
| Include company social links | On by default. Links are read from the website. Social networks are never visited. |
| MX pre-check emails | On by default. Checks syntax and DNS MX and flags disposable domains. |
| Max emails per website | Default 10. |
| Request timeout | Up to 15 seconds per page. |

### Output

One dataset row per website.

| Field | Notes |
|---|---|
| `domain`, `homepageUrl`, `organizationName` | `organizationName` is the site name the website declares (`og:site_name`) when present. |
| `status` | `ok` (company email or phone found) · `socials_only` · `no_contacts` · `blocked` · `robots_disallowed` · `unreachable` · `not_html` · `excluded` · `invalid_input` · `duplicate` · `skipped` |
| `emails` | Role mailboxes, each with `email`, `type: "role"`, `onSiteDomain`, `mxPreCheck` (`mail_domain_ok`, `no_mail_domain`, `disposable`, `unknown`), `mailDomain`, `disposable`, `freeProvider` and `sourcePages`. |
| `emailList` | The same addresses as a plain list. |
| `phones` | Each with `phone` (as published), `e164`, `lineType` (`fixed_line`, `toll_free`, `uan`, `fixed_line_or_mobile`), `mayBeMobile` and `sourcePages`. |
| `phoneList` | The same numbers in E.164 as a plain list. |
| `socials` | `network`, `url`, `sourcePages`. The `linkedin`, `x`, `facebook`, `instagram` and `youtube` fields hold the first link found for each network. |
| `jurisdictionHint` | `EU/EEA`, `UK`, `CA`, `US` or `other`, a hint from the ccTLD, page language, imprint page and phone country codes. |
| `skippedReason` | `site-notice` when the site publishes a no-solicitation or no-harvesting notice. Emails are then not returned. |
| `pagesFetched` | Every page read, with its kind and result. |
| `source`, `retrievedAt`, `emailAllowlist` | Provenance and the role-allowlist version. |

A **Run summary** record holds counts per status and request totals. It contains no contact values.

#### Example (fictional data)

```json
{"domain":"example.com","homepageUrl":"https://example.com/","organizationName":"Example Co","status":"ok","emails":[{"email":"info@example.com","type":"role","mxPreCheck":"mail_domain_ok","sourcePages":["https://example.com/contact"]}],"emailList":["info@example.com"],"phones":[{"phone":"+1-555-0100","lineType":"fixed_line","mayBeMobile":false,"sourcePages":["https://example.com/contact"]}],"socials":[{"network":"linkedin","url":"https://example.com/social/linkedin"}],"jurisdictionHint":"US"}
```

#### What is deliberately not returned

- **Emails that are not on a fixed role-mailbox allowlist.** That includes named addresses such as `jane.doe@`, initials, first names, and business-named addresses at free providers. They are dropped and never output.
- **Mobile, pager and personal numbers.** Imprint phones listed in an owner's or managing director's block are dropped as well.
- **Personal social profiles**, such as `linkedin.com/in/...`.
- **People's names, job titles, postal addresses and photos.**
- **Team, people, staff or leadership pages.** These are never read.

### Speed and run time

The Actor visits at most 2 websites at a time, with at least 1 second between requests to the same site, so it processes roughly **500 websites per hour** (measured in our 200-site QA run: about 7 seconds per website). The default run timeout is 4 hours, which covers about 2,000 websites. For larger lists, raise the run timeout in the run options (10,000 websites take about 20 hours), or split the list into several runs.

### Pricing (pay per event)

- **Website with company contact found: $0.004.** Charged once per website where at least one role email or business phone was found.
- **Free:** websites with social links only or no contacts, and websites that are blocked, robots-disallowed, unreachable, excluded, invalid or duplicate.
- No start fee and no per-item fee. Your *max charge per run* is respected.

Example: 1,000 websites with about 600 contact hits ≈ $2.40.

### How it reads websites

- Reads only the websites you list, plus pages on that same site that are linked from its homepage or sit at standard paths (`/contact`, `/about`, and `/impressum` on DE/AT/CH sites).
- It never runs a sitemap walk, search-engine discovery, or a look-up on another site.
- **robots.txt is obeyed** for this Actor's user agent and for `*`. If robots.txt can't be read (5xx), the site is treated as disallowed.
- **Pacing:** one request at a time per site, at least 1 second apart (longer if robots.txt asks), and at most 2 sites in parallel.
- Identifying user agent: `WebsiteContactFinder/1.0 (Apify Actor by ethical_acumen; +https://apify.com/ethical_acumen/website-contact-finder)`. No proxies, no browser, no logins and no cookies.
- If a site answers 401, 403 or 429, or shows a challenge or CAPTCHA page, it is reported as `blocked`, not charged, and not retried from any other IP or identity.
- Emails hidden with "email protection" scripts are not decoded.
- **The email check is a DNS/MX pre-check, not mailbox verification.** No mail server is contacted (no SMTP).
- Sites that publish a no-solicitation or no-harvesting notice, or that disallow crawling, are skipped.

### Limits (tested 2026-10-19)

- Pages that build their content with JavaScript may show fewer contacts, because no browser is used.
- US and Canadian numbers can't be reliably told apart from mobiles. They are returned with `mayBeMobile: true`. Treat `mayBeMobile` numbers as possibly wireless under the TCPA.
- `jurisdictionHint` is a heuristic, not a legal determination.

### Acceptable use: your responsibilities

**You are the controller of the output.** Before contacting anyone, you are responsible for:

- having a lawful basis and meeting notice duties (e.g. GDPR/UK GDPR Art. 14);
- complying with CAN-SPAM, the TCPA and do-not-call rules, CASL/PIPEDA, the EU ePrivacy rules/PECR, and local law.

Do not use the output for unsolicited bulk messaging, for autodialed or prerecorded calls, or for texts sent without the required consent.

Contacts at EU/EEA, UK and Canadian organizations carry consent and notice duties, so check `jurisdictionHint`.

The publisher stores no results. Your data goes only to your own run dataset and is never sold, shared or reused.

### Removal requests

To request removal of a website or a role address, open an Issue on this Actor. Suppressed websites are never read, and suppressed addresses are never returned. We act within 5 business days.

Questions or problems: open an Issue on the Actor page. We answer within 14 days.

### Notices

- Not affiliated with, endorsed by or sponsored by any website it reads, or by LinkedIn, X, Meta (Facebook, Instagram) or Google (YouTube). Those names are trademarks of their owners and are used only to identify link types.
- Contact details are published by each organization and may change at any time. Always check the `sourcePages` link.

# Actor input Schema

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

One company website per line: a domain (acme.com), a host (www.acme.com) or a URL (https://acme.com/en/). The Actor reads the homepage plus up to 5 contact, about, imprint or legal pages on the same site. Duplicates (www., http/https) are merged and not charged twice.

## `maxPagesPerWebsite` (type: `integer`):

Homepage plus up to 5 named pages (contact, about, imprint/impressum, legal). Lower it for faster, cheaper runs. 6 is the hard maximum.

## `includePhones` (type: `boolean`):

Return business landline, switchboard and toll-free numbers. Mobile numbers are always excluded. US/Canada numbers that can't be told apart from mobiles are flagged mayBeMobile.

## `includeSocials` (type: `boolean`):

Return company pages on LinkedIn, X, Facebook, Instagram and YouTube that the website links to. Social sites are never visited; personal profiles are excluded.

## `checkEmails` (type: `boolean`):

Check each email's syntax and whether its domain accepts mail (DNS MX, over DNS-over-HTTPS), and flag disposable domains. This is not mailbox verification: no mail server is contacted.

## `maxEmailsPerWebsite` (type: `integer`):

Cap on role emails returned per website. On-site-domain addresses come first.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each page request. 15 seconds is the maximum.

## Actor input object example

```json
{
  "websites": [
    "zingermans.com",
    "kingarthurbaking.com",
    "ankerkraut.de"
  ],
  "maxPagesPerWebsite": 6,
  "includePhones": true,
  "includeSocials": true,
  "checkEmails": true,
  "maxEmailsPerWebsite": 10,
  "requestTimeoutSecs": 15
}
```

# Actor output Schema

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

One dataset item per website: status, role emails with MX pre-check and source pages, business phones with line type and source pages, company social links, jurisdictionHint and the pages read.

## `runSummary` (type: `string`):

Counts per status (ok, socials_only, no_contacts, blocked, robots_disallowed, unreachable, excluded, invalid_input, duplicate, skipped), websites charged and request totals. Contains no contact values.

# 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": [
        "zingermans.com",
        "kingarthurbaking.com",
        "ankerkraut.de"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("ethical_acumen/website-contact-finder").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": [
        "zingermans.com",
        "kingarthurbaking.com",
        "ankerkraut.de",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("ethical_acumen/website-contact-finder").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": [
    "zingermans.com",
    "kingarthurbaking.com",
    "ankerkraut.de"
  ]
}' |
apify call ethical_acumen/website-contact-finder --silent --output-dataset

```

## MCP server setup

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

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/10LwaShiOFPIn5McU/builds/zpyKchlHpoP0Qve6Q/openapi.json
