# Website Contact Enrichment — Emails, Phones & Socials (`logical_vivacity/website-contact-enrichment`) Actor

Turn a list of websites into contactable companies. Crawls the pages that matter and returns the best email to write to, plus phones, social profiles, named people and mail signals (MX, SPF, DMARC). Charged only when a record carries a real contact.

- **URL**: https://apify.com/logical\_vivacity/website-contact-enrichment.md
- **Developed by:** [Logical Vivacity](https://apify.com/logical_vivacity) (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

$30.00 / 1,000 domain 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/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 Enrichment — Emails, Phones, Socials & Decision Makers from a Domain

**Paste a list of websites. Get back one finished contact record per company — with the single address you should actually write to.**

Most contact scrapers hand you a pile of strings: every `mailto:` on the page, every number that looked like a phone, the tracking pixel's domain and a `logo@2x.png`. Then you do the real work — deciding which of those is a mailbox a human reads.

This Actor does that part. One domain in, one record out: the emails that are real, labelled by what kind of mailbox they are, the phone numbers in E.164, the postal address, the social profiles, the people the site names, whether the domain can even receive mail — and `bestEmail`, the one address to use.

**You pay per enriched domain.** A website that publishes no contact at all costs nothing.

***

### Try it in 30 seconds

Put these in **Websites** and hit Start:

```
stripe.com
sipgate.de
```

One US SaaS, one German company with an Impressum. No configuration, two finished records.

***

### What you get per domain

```jsonc
{
  "domain": "sipgate.de",
  "website": "https://sipgate.de",
  "companyName": "sipgate",
  "description": "Cloud-Telefonanlage, Contact Center und AI…",
  "logoUrl": "https://sipgate.de/og-image.png",
  "country": "Germany",
  "language": "de",

  "bestEmail": "info@sipgate.de",        // the one address to write to
  "bestEmailType": "general",
  "confidence": 94,                       // 0-100, how sure we are it's live

  "emails": [
    { "email": "info@sipgate.de",
      "type": "general",                  // general | sales | support | careers | personal
      "source": "https://sipgate.de",     // the page it came from
      "pageType": "home" }
  ],

  "phones": ["+4921163553355", "+492116355550"],   // E.164 where it parses
  "address": "Gladbacher Straße 74 40219 Düsseldorf",

  "socials": {
    "linkedin": "https://www.linkedin.com/company/sipgate-gmbh",
    "facebook": "https://www.facebook.com/sipgate",
    "instagram": "https://www.instagram.com/sipgate",
    "youtube": "https://www.youtube.com/@sipgate"
  },

  "people": [
    { "name": "Till Lienhoop", "role": "Geschäftsführer", "email": null }
  ],

  "mailSignals": {                        // can this domain receive mail at all?
    "hasMx": true,
    "mailProvider": "google",
    "hasSpf": true,
    "hasDmarc": true
  },

  "pagesScanned": 8,
  "status": "ok",
  "scrapedAt": "2026-09-17T21:40:02+00:00"
}
```

Export as JSON, CSV, Excel, XML or HTML, or pull it straight from the API.

***

### Who uses this

**Outbound sales teams** — you bought a list of 5,000 domains and it has no email column. Run it through this and you get one contactable address per company, with a confidence score you can filter on before you spend a send.

**Agencies and freelancers building prospect lists** — local businesses, agencies and shops publish a contact address and a phone number and nothing else. This reads both, plus the owner's name from the about page.

**CRM and data teams enriching accounts** — company name, tagline, logo, country, address and social profiles arrive in the same record as the contacts, so one run fills a whole account row.

**Recruiters and partnerships** — `people` gives you who the site names and what they do, so you know whether the company even has a Head of anything before you write.

**Anyone cleaning an old list** — `mailSignals.hasMx` tells you whether a domain can still receive mail. A domain with no MX record is a bounce you don't have to pay for.

***

### What makes it different

**It picks the address for you.** `bestEmail` is chosen, not just listed: a mailbox on the company's own domain beats a Gmail, a general or sales mailbox beats a support or careers queue, and an address found on the contact page beats one found in a privacy policy. That single field is the product.

**Junk is filtered before you see it.** `example.com`, `yourdomain.com`, the error-tracker's address, the template placeholder `ihre@firma.de`, the CDN's, `sprite@2x.png`, hex-string addresses from analytics scripts — all dropped. What's left is what a person could write to.

**Emails come with an origin and a type.** Every address carries the URL it was found on and a label — general, sales, support, careers or a named person — so you can route a sales pitch away from a careers inbox.

**Obfuscated addresses still get read.** `hello [at] acme [dot] com`, entity-encoded and JSON-embedded addresses are decoded like any other.

**Phone numbers you can dial.** Normalised to E.164 using the country the site itself suggests, deduplicated, with years, prices and order numbers rejected rather than shipped as phone numbers.

**Mail signals nobody else returns.** MX provider, SPF and DMARC for the domain, from live DNS. Useful for deliverability and brutally effective at spotting dead domains.

**It only reads pages that carry contacts.** The homepage, then contact, about, team, imprint/Impressum, support, careers and legal — picked from the site's own navigation and capped by you. Not a whole-site crawl, so a run stays fast and cheap.

**Empty is free.** A site with no email and no phone is reported with a reason and costs nothing.

***

### Settings that matter

| Setting | What it does |
|---|---|
| **Websites** | Domains or URLs, one per line. `acme.com`, `www.acme.com` and `https://acme.com/pricing` all mean the same company |
| **Maximum pages per website** | How deep to look. 8 finds almost everything; 3 is a fast, cheap pass |
| **Find named people** | Reads team and about pages for names, roles and personal addresses |
| **Include social profiles** | LinkedIn, X, Facebook, Instagram, YouTube, TikTok |
| **Only keep websites with an email address** | Skips — and never charges for — companies that publish a phone but no email |

Connection handling, pacing, retries and blocking are managed for you — there's nothing to configure and no proxy to set up.

### Automate it

```bash
curl -X POST "https://api.apify.com/v2/acts/YOUR_USERNAME~website-contact-enrichment/runs?token=YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{ "websites": ["stripe.com", "sipgate.de", "katzsdelicatessen.com"],
        "maxPagesPerSite": 8,
        "findPeople": true,
        "includeSocials": true,
        "requireEmail": true }'
```

Works with Make, Zapier, n8n, Google Sheets and the Apify API, and as an MCP tool for AI agents. Point it at the new domains in your CRM on a schedule and the contact column fills itself.

### Results you can trust

Every website you submit comes back with a row, so nothing fails silently:

| `status` | Meaning |
|---|---|
| `ok` | At least one real contact was found — charged |
| `no_contacts` | The site was read fine but publishes no email or phone (or no email, when **Only keep websites with an email address** is on) — not charged |
| `error` | The input wasn't a website, or the site was unreachable during the run — not charged |

`note` says in plain English what happened on every row.

***

### FAQ

**What exactly is `confidence`?**
A 0-100 read on whether `bestEmail` will reach the company: it goes up for an address on the company's own domain, found on a contact or imprint page, on a domain whose DNS accepts mail, backed by a phone number, address and LinkedIn profile — and sharply down when the domain has no MX record at all.

**Do you guess or generate email addresses?**
No. Every address in the output was published somewhere on the company's own website, and `source` tells you which page. Nothing is pattern-guessed.

**Do you verify that the mailbox exists?**
Not per mailbox. We check the domain: whether it has MX records, who runs the mailbox, and whether SPF and DMARC are set. That catches dead domains, not full inboxes.

**Why did a well-known company come back with no contacts?**
Plenty of companies publish only a contact form. That's a real answer about that company, and you aren't charged for it.

**Can I feed it URLs with paths, or messy rows from a CRM export?**
Yes. Anything that contains a domain is reduced to that domain, and duplicates in one run are read once.

**Does it handle non-English sites?**
Yes — Kontakt, Impressum, Über uns, Chi siamo, Nosotros and their neighbours are all recognised, and `language` and `country` come back on the record.

**How many pages does it read?**
The homepage plus up to your **Maximum pages per website**, chosen by relevance. It never crawls a whole site.

**Will it find personal addresses for individual staff?**
Where the site publishes them — many imprint and team pages do. It never invents `firstname.lastname@` combinations.

**Can I run 10,000 domains?**
Yes. Work runs in parallel with polite per-site pacing, and you can cap spend with the run's maximum charge limit.

***

### Terms of Use

This Actor reads pages a company publishes openly on its own website, plus public DNS records for that domain. You are responsible for using the results lawfully: contact data about individuals is personal data, and obligations under the GDPR, ePrivacy rules, CAN-SPAM, CASL and any other marketing, telemarketing and data-protection rules in your jurisdiction and your recipients' fall on you, including lawful basis, disclosure and opt-out handling. Do not use the results to send unsolicited mail where that is unlawful. Websites are returned as they were published and may be incomplete, outdated or changed after your run — verify before acting on a result. This Actor is provided "as is", without warranty of accuracy, deliverability or fitness for a particular purpose, and is not affiliated with, endorsed by, or sponsored by any company, mailbox provider or social network whose public pages or profiles appear in your results.

***

*Found a site where the contact page is obviously there but came back empty?* Open an issue on the Actor's Issues tab with the domain.

# Actor input Schema

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

One website or domain per line. A bare domain, a full URL or a link with a path all work — acme.com, www.acme.com and https://acme.com/pricing are the same company.

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

How deep to look. The homepage is always read, then the pages most likely to carry contacts — contact, about, team, imprint, support, careers. 8 finds almost everything; lower it for a faster, cheaper pass.

## `findPeople` (type: `boolean`):

Also read team and about pages for named people with their roles, and their email where the site shows it.

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

Collect the company's LinkedIn, X, Facebook, Instagram, YouTube and TikTok profiles.

## `requireEmail` (type: `boolean`):

Skip and never charge for companies that publish a phone number but no email. Turn this on when the list is going straight into an email sequence.

## Actor input object example

```json
{
  "websites": [
    "stripe.com",
    "sipgate.de"
  ],
  "maxPagesPerSite": 8,
  "findPeople": true,
  "includeSocials": true,
  "requireEmail": false
}
```

# Actor output Schema

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

Every company with its best email, phones, socials and named people.

## `overview` (type: `string`):

The same rows as a spreadsheet-style table, with the most useful columns first.

# 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": [
        "stripe.com",
        "sipgate.de"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("logical_vivacity/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": [
        "stripe.com",
        "sipgate.de",
    ] }

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

```

## MCP server setup

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