# Verified Website Contact Finder (`al_mansouri/verified-website-contact-finder`) Actor

Turn company websites into outreach-ready emails, phones, and social profiles, each with the page it came from and an honest deliverability score.

- **URL**: https://apify.com/al\_mansouri/verified-website-contact-finder.md
- **Developed by:** [Hussein Al-Mansori](https://apify.com/al_mansouri) (community)
- **Categories:** Lead generation, AI, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 site enricheds

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

## Verified Website Contact Finder

Give it a list of company websites. Get back **emails, phone numbers, and social profiles** — each
one carrying the exact page it came from and an honest score for whether the address can actually
receive mail.

Built for the step after a Google Maps export or a CRM dump: you already have the websites, you
need the contacts.

### What you get

One result per website, whether or not anything was found. Never a silent failure.

```json
{
  "website": "https://example-company.com/",
  "status": "verified",
  "companyName": "Example Company Ltd",
  "companyAddress": "1 High Street, London, EC1A 1BB, GB",
  "emails": [
    {
      "address": "hello@example-company.com",
      "kind": "role",
      "sourceUrl": "https://example-company.com/contact",
      "foundIn": "mailto",
      "context": "Prefer email? Write to hello@example-company.com and we reply within a day.",
      "verification": {
        "syntaxValid": true,
        "domainHasMx": true,
        "smtp": "skipped",
        "confidence": 60,
        "limitation": "The domain can receive mail, but the individual mailbox was not checked."
      }
    }
  ],
  "phones": [
    {"e164": "+441234567890", "raw": "01234 567890", "region": "GB",
     "sourceUrl": "https://example-company.com/contact", "foundIn": "telLink"}
  ],
  "socials": [
    {"platform": "linkedin", "url": "https://www.linkedin.com/company/example",
     "sourceUrl": "https://example-company.com/"}
  ],
  "pagesCrawled": 8,
  "pagesNotRead": 3,
  "robotsRespected": true,
  "warnings": []
}
```

### Why this one

**Every contact shows its evidence.** You get the page it came from, how it was found (`mailto`
link, page text, JSON-LD, microdata, obfuscated text, or Cloudflare-protected), and the surrounding
words. Any contact can be re-checked by hand in one click.

**The confidence score is honest.** Gmail, Microsoft 365, and Yahoo refuse mailbox checks from data
centres. Tools that report those addresses as "verified" are guessing. This Actor caps the score,
writes a plain `limitation` saying exactly what could not be established, and marks the result
`warning` rather than pretending. Here, `verified` means *the source is proven and a deliverability
signal was obtained* — never *this mailbox is guaranteed to accept mail*.

**Role and personal addresses are labelled.** `info@` and `sales@` come back as `role`;
`firstname.lastname@` as `personal`, so you can apply your own policy to each.

**Fast by default, thorough when it matters.** Pages are read with a plain request; only a page
that hides its contacts behind JavaScript is escalated to a real browser. You are not paying
browser prices for sites that never needed one.

**Non-English sites work.** Phone numbers come back in international `+` format whatever the local
convention, and company details are read from structured data in any language.

### Quick start

1. Paste your website URLs into **Website URLs**.
2. Leave everything else alone and click **Start**.
3. Take the results from the dataset, or open the **Contacts** view for a flat table.

### Common uses

- Turn a Google Maps or directory export into an outreach list.
- Fill missing contact fields on CRM records you already own.
- Find the right inbox for accounts payable, press, or support at a supplier.
- Enrich inbound signups with company name, address, and social profiles.
- Give an AI agent a contact record whose source it can cite.

### Input options

| Option | Default | What it does |
|---|---|---|
| `websites` | — | Company websites to scan, up to 50 per run |
| `maxPagesPerSite` | 12 | Pages read per website (1–40) |
| `collectPhones` | true | Return phone numbers in international format |
| `collectSocials` | true | LinkedIn, X, Facebook, Instagram, YouTube, TikTok, GitHub, Pinterest, Threads |
| `verifyEmails` | true | Check each address and score it |
| `smtpProbe` | false | Also open a mail-server handshake (see FAQ) |
| `respectRobots` | true | Skip pages the site asks crawlers not to read |
| `browserFallback` | true | Use a browser on pages that need one |
| `proxyConfiguration` | Apify Proxy | Many sites refuse data-centre addresses; leave this on |

### Reading the result

`status` is:

- **`verified`** — the crawl completed cleanly and everything reported was established.
- **`warning`** — something was uncertain. The reason is always in `warnings`.
- **`failed`** — the site could not be read at all. Never charged.

Reaching your page budget is *not* a warning. It is normal, and `pagesNotRead` tells you how many
more pages were found, so you can raise the budget if you want them.

### Using it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/al_mansouri~verified-website-contact-finder/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"websites": ["https://example-company.com"], "maxPagesPerSite": 12}'
```

The Actor publishes a full input and dataset schema, so an AI agent can also discover and run it
through Apify's MCP server without extra glue.

### Pricing

Provisional, and not yet frozen — final prices are set from a measured benchmark.

| Event | When it applies | Price |
|---|---|---:|
| `site-enriched` | An email address or phone number was returned | $0.010 |
| `site-scanned` | The website was read, but published no email or phone | $0.004 |

No per-run start fee. You are charged once per website, never per contact, and never for a website
that could not be read.

**Social profiles alone do not trigger the higher price.** A LinkedIn URL is worth having, but it
is not a way to contact anyone and you could have found it yourself, so a site that yields only
social links bills as a scan.

**Send websites in batches.** Every run pays a fixed container start of roughly 28 seconds, so one
website per run costs several times more per site than fifty.

- 50 websites, two thirds with an email or phone: about **$0.40**
- 25 websites, half with an email or phone: about **$0.18**
- 1 website: **$0.004–$0.010**, most of it the container start

### Limits

| Limit | Value |
|---|---|
| Websites per run | 50 |
| Pages read per website | 12 by default, 40 maximum |
| Bytes per page / per website | 2 MB / 16 MB |
| Time per page / per website | 15 s / 90 s |
| Emails / phones / socials per website | 50 / 25 / 25 |
| Redirects followed | 5 |

Contact, about, and imprint pages are always read first, so a small page budget still finds most
contacts.

### Errors

| Code | Meaning | Worth retrying? |
|---|---|---|
| `SITE_UNREACHABLE` | No page on the site could be read | Yes |
| `SITE_TIMEOUT` | The site took too long | Yes |
| `DNS_FAILURE` | The hostname does not resolve | Yes |
| `ROBOTS_DISALLOWED` | The site's `robots.txt` forbids its own homepage | No |
| `BLOCKED_DESTINATION` | Resolves to a private or internal address | No |
| `INVALID_URL` | Not a usable `http`/`https` URL | No |
| `BUDGET_EXHAUSTED` | The run's maximum charge was reached | No |

A failed website is still published as a result with the reason attached, and is never charged.

### Privacy and lawful use

Only public pages are read, and only pages `robots.txt` permits unless you turn that off yourself —
which is recorded in the result.

Business contact details are personal data under the GDPR. Every record carries the page it came
from so you can answer a source-disclosure request, addresses that look personal rather than
role-based are labelled, and nothing is kept beyond your own run storage. Establishing a lawful
basis for your outreach remains your responsibility.

Every URL is checked before it is requested, including each redirect hop and every link followed
inside a site, so a site that redirects to a private or internal address is refused rather than read.

### FAQ

**Why is an address only scored 60?**
Its domain accepts mail, but the individual mailbox was not checked. That is the honest ceiling
without a mail-server handshake.

**Should I turn on the mail-server check?**
Usually not. Gmail, Microsoft 365 and Yahoo refuse those checks from data centres, and outbound
mail ports are commonly blocked in cloud containers, so it often proves nothing. When it cannot
establish anything, the result says so rather than inflating the score.

**Why did a site return no emails?**
Either it publishes none, or it hides them behind a contact form. This Actor tells you that instead
of inventing an address. Raising `maxPagesPerSite` sometimes reaches a contact page a small budget
missed.

**Does it guess addresses like `firstname@company.com`?**
No. Guessed addresses are how bounce rates and spam complaints happen. If it is not published, it
is not returned.

**What is not supported?**
Logins, paywalled pages, and CAPTCHA solving.

### Support

Questions and bug reports go to the Issues tab on this Actor. The Changelog tab lists what changed
in each version.

# Actor input Schema

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

Company websites to scan, up to 50 per run. Paste the homepage; contact and about pages are found automatically.

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

How many pages to read on each website. Contact, about, and imprint pages are always read first, so a low number still finds most contacts.

## `collectPhones` (type: `boolean`):

Return phone numbers in international format alongside the page each one was found on.

## `collectSocials` (type: `boolean`):

Return LinkedIn, X, Facebook, Instagram, YouTube, TikTok, GitHub, Pinterest, and Threads profile links.

## `verifyEmails` (type: `boolean`):

Check that each address is correctly formed and that its domain can receive mail, then report a confidence score.

## `smtpProbe` (type: `boolean`):

Additionally open a mail-server handshake. Gmail, Microsoft 365, and Yahoo refuse these from data centres, so those addresses stay unconfirmed and say so in the result.

## `respectRobots` (type: `boolean`):

Skip any page the website asks crawlers not to read. Turning this off is your decision and is recorded in the result.

## `browserFallback` (type: `boolean`):

Most pages are read with a fast plain request. When a page hides its contacts behind JavaScript, a real browser is used for that page only.

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

Proxy used for page requests. Some websites block data-centre addresses; residential proxy costs more but reaches more sites.

## Actor input object example

```json
{
  "websites": [
    "https://example-company.com"
  ],
  "maxPagesPerSite": 12,
  "collectPhones": true,
  "collectSocials": true,
  "verifyEmails": true,
  "smtpProbe": false,
  "respectRobots": true,
  "browserFallback": true,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

One machine-readable result per website, including websites where nothing was found.

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

No description

# 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": [
        "https://www.apify.com",
        "https://www.python.org"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("al_mansouri/verified-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": [
        "https://www.apify.com",
        "https://www.python.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("al_mansouri/verified-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": [
    "https://www.apify.com",
    "https://www.python.org"
  ]
}' |
apify call al_mansouri/verified-website-contact-finder --silent --output-dataset

```

## MCP server setup

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