# Website Contact Enrichment - Emails, Phones & Sources (`maydit/website-contact-enrichment`) Actor

Extract published emails, declared phones, company addresses and social profiles from supplied websites. Source evidence per contact, bounded contact-page crawl, no API key or guessed emails.

- **URL**: https://apify.com/maydit/website-contact-enrichment.md
- **Developed by:** [Brandt May](https://apify.com/maydit) (community)
- **Categories:** Lead generation, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.40 / 1,000 website contact records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

![Published contacts with evidence — illustrative workflow](https://api.apify.com/v2/key-value-stores/YGxD9JRpduom8Q5Zd/records/website-contact-enrichment-7acd491d4220.png?signature=1MioixDHpivHdNSWOV9zZ)

### Published contacts with evidence

For CRM cleanup and supplier research, gather published contact signals from a bounded crawl with a source page and extraction method.

**Coverage:** Static public HTML, declared phone links, supported social links and matching structured data. No guessed emails or form submissions.

[Open this Actor in Console](https://console.apify.com/actors/TRZRB1Qh71jtfVEUz/input) · [First run](#try-this-actor) · [Results](#result-preview) · [Cost](#usage-and-pricing) · [Full guide](#full-guide)

### Try this Actor

1. Use the existing Apify contact-page example below with one page attempt and up to ten saved website records.
2. Open the run's dataset; JSON retains nested contacts and their source evidence. Check `SUMMARY` for failed pages and missing results.

**Read the results correctly:** Published contact details are not verified for deliverability, ownership or consent. A saved row can contain only a social profile or contact-form URL.

**Extract Apify Public Contact Details** — copy this input into the JSON editor in Console.

```json
{"websites":["https://apify.com/contact"],"maxPagesPerSite":1}
```

### Result preview

The dataset view highlights these columns:

- **Resolved website** · `url`
- **Domain** · `domain`
- **Published organization names** · `companyNames`
- **Published emails and evidence** · `emails`
- **Declared phones and evidence** · `phones`
- **Published social links** · `socialProfiles`

Use the original source links and the field definitions below when interpreting the results. CSV works well for flat columns; JSON preserves nested values.

### Usage and pricing

Base result rate on the FREE tier: **$4 per 1,000 website contact records**. The [Pricing tab](https://apify.com/maydit/website-contact-enrichment/pricing) shows your plan's result rate and any Actor Start charge. Set a small result limit for the first run; the requested limit is not a guarantee of that many results.

***

### Full guide

Turn supplied public business websites into structured, evidence-linked contact records. Extract published emails, phone links, social profiles, Organization structured addresses and contact-form page URLs from a small, bounded crawl.

Useful for CRM enrichment, supplier research, website audits and contact-data cleanup. Each extracted signal retains its source page and extraction method so you can check it before use.

#### Quick start

Run with empty input for a real example using the public Apify contact page. No account, API key or proxy is required.

```json
{"websites":["https://apify.com/contact"],"maxPagesPerSite":1,"maxResults":10}
```

#### Inputs

| Field | Default | Meaning |
|---|---|---|
| `websites` | Apify contact page | Up to 1,000 HTTP(S) website/page URL strings. Empty array also uses the demo. |
| `maxPagesPerSite` | 3 | Maximum request attempts per website, from 1–10. Follows existing contact/about/support links. |
| `maxResults` | 100 | Maximum website records saved, from 1–1,000. |
| `includeSubdomains` | false | Allow discovered links on child subdomains of the resolved starting host. |
| `maxRunSeconds` | 240 | Internal deadline, 30–3,600 seconds, also bounded by the platform deadline. |

The first page can redirect to the site's canonical public host. Discovered page links stay on that host, with optional child subdomains. The crawler uses static HTML, respects robots.txt, limits each page to 3 MiB decoded content and checks public network addresses on every redirect. It never submits forms.

#### Output

One dataset row per supplied URL with at least one contact signal. Two different seed URLs on the same domain remain separate observations.

| Field | Contents |
|---|---|
| `websiteId`, `inputUrl`, `url`, `domain`, `title` | Stable seed identity and resolved website context. |
| `companyNames` | Names from matching Organization JSON-LD. May be empty. |
| `emails` | Email, deterministic `isRoleAddress`, `onSiteDomain`, and source URLs/methods. |
| `phones` | Published raw number, explicit international number when present, extension and sources. |
| `socialProfiles` | Supported public social profile links with source pages. |
| `addresses` | Published structured postal fields and sources, when available. |
| `contactPageUrls` | Pages actually read, including the seed. |
| `contactFormUrls` | Pages containing a likely contact form. No messages are sent. |
| `signalCount` | Total unique emails, phones, profiles, addresses and form-page signals. |
| `pagesCrawled`, `pagesAttempted`, `crawlTruncated`, `incomplete` | Crawl coverage and source-failure indicators. |
| `observedAt` | Retrieval time. |

Email sources are mailto links, visible page text and matching Organization/ContactPoint JSON-LD. Phones come from tel links and matching structured data; arbitrary number strings are not guessed to be phone numbers. Social links support LinkedIn companies/schools, Facebook, Instagram, X, YouTube, TikTok, GitHub and Bluesky. A published social link can still be outdated or point to someone other than the site's owner.

`isRoleAddress` describes the address prefix; `onSiteDomain` describes its domain. Neither verifies ownership or deliverability. Non-role addresses may appear if the website publishes them. International prefixes are not inferred, and obfuscated, image-only or JavaScript-rendered contacts may be missed. Addresses and names depend on matching structured data. Form detection is a heuristic.

#### Three runnable examples

##### 1. Apify contact page

Use the [copyable first-run input](#try-this-actor) above.

##### 2. Mozilla contact page

```json
{"websites":["https://www.mozilla.org/en-US/contact/"],"maxPagesPerSite":1}
```

##### 3. Django Software Foundation

```json
{"websites":["https://www.djangoproject.com/foundation/"],"maxPagesPerSite":2}
```

#### Coverage and failures

Read the `SUMMARY` key-value record for every requested website, skipped or failed pages, missing results and stop reasons. A bounded crawl does not imply the site has no other contacts. `crawlTruncated` means discovered links remain beyond the selected page limit; `incomplete` means a source failed or the run stopped early.

A successfully fetched site with no contact signals yields no paid result. Source errors also yield no fabricated error rows. If every source fails, the run fails with details in `SUMMARY`. A website with some usable signals and a failed secondary page can produce a paid row marked incomplete. HTTP 429 is reported without an immediate retry; transient network/server failures receive at most one retry. Dataset charge limits stop further writes; only confirmed saved rows count.

#### Pricing

Base price: **$4 per 1,000 saved website records** ($0.004 each), plus the $0.00005 Actor Start event per GB of memory, minimum one event. Silver receives 20% off result events; Gold and higher receive 40% off. A record can contain only a social profile or form URL when no email/phone is published. Review the current Store pricing for the charge applied to your account.

#### Responsible use and support

Use public business contact information for lawful, relevant purposes. This Actor does not verify consent, send outreach or provide private profile access. Retain only data you need and honor correction or deletion requests. Questions or removal requests: use the Actor Issues tab or bmay@mayd-it.com.

### Help with your run

Open the **Issues** tab on this Actor with the run URL, the input field that caused trouble and what you expected to receive. Remove API keys and private information before posting.

[Explore more Mayd-It Actors](https://apify.com/maydit)

### Understand your run

Open **Run report** in the run’s Output tab for saved-record counts, reported source issues and limits, and suggested next steps. Use **CSV export** to take the saved results into a spreadsheet. The existing JSON results and detailed machine-readable summary remain available.

The report reflects this run’s recorded coverage. A successful run or a saved result does not establish that every possible source record was collected.

# Actor input Schema

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

Public homepages or contact-page URLs, up to 1000. Each supplied URL defines one website observation. Omitted or empty input uses Apify's public contact page.

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

Hard page-attempt cap including the supplied page. Follow only observed contact, about, support, company and imprint links.

## `maxResults` (type: `integer`):

Stop after this many website rows with at least one contact signal. Websites with no usable signals create no paid dataset row.

## `includeSubdomains` (type: `boolean`):

Allow observed contact links below the final root hostname. Does not allow unrelated domains. Redirects on later pages are scope checked.

## `maxRunSeconds` (type: `integer`):

Time budget, also constrained by the platform deadline. Partial coverage is reported in SUMMARY and each row.

## Actor input object example

```json
{
  "websites": [
    "https://apify.com/contact"
  ],
  "maxPagesPerSite": 3,
  "maxResults": 100,
  "includeSubdomains": false,
  "maxRunSeconds": 240
}
```

# Actor output Schema

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

Websites with declared contact signals. Each datum includes its source page.

## `runReport` (type: `string`):

Readable summary of saved records, reported source coverage, limits and next steps. Available when this run saves its SUMMARY.

## `csvExport` (type: `string`):

Download saved dataset records as a CSV file for spreadsheets and other tools.

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

Saved count, unsuccessful sources, contact-free websites and limits.

# 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://apify.com/contact"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maydit/website-contact-enrichment").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://apify.com/contact"] }

# Run the Actor and wait for it to finish
run = client.actor("maydit/website-contact-enrichment").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://apify.com/contact"
  ]
}' |
apify call maydit/website-contact-enrichment --silent --output-dataset

```

## MCP server setup

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

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/TRZRB1Qh71jtfVEUz/builds/ub3FJ2ljU88qow4b7/openapi.json
