# Website Lead Enricher – Emails, Phones, Tech & EU Company IDs (`teakkaet/website-lead-enricher`) Actor

Turn a list of company websites (or a Google Maps Scraper dataset) into enriched B2B leads: emails, phones, social profiles, tech stack, email provider, domain age and EU legal IDs (SIREN/SIRET, VAT, Handelsregister, UK company number).

- **URL**: https://apify.com/teakkaet/website-lead-enricher.md
- **Developed by:** [theo](https://apify.com/teakkaet) (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 Lead Enricher: emails, phones, socials, tech stack and EU company IDs

**Give it a list of company websites, or the dataset from a Google Maps Scraper run. You get back one clean, enriched lead per website:**

- 📧 **Emails**: `mailto:` links, plain text, Cloudflare-protected emails (`[email protected]`) and obfuscated ones (`contact [at] acme [dot] com`). Each email is tagged *role* (`info@`, `sales@`) or *personal*, *on the company domain* or not, and *free provider* (Gmail…) or not.
- 🇪🇺 **GDPR-friendly mode**: one switch keeps only generic addresses (`contact@`, `info@`…) and drops emails of named people.
- 📞 **Phones**: `tel:` links, schema.org data and text, normalized to international format (`+33142345020`).
- 🔗 **Social profiles**: LinkedIn, Facebook, Instagram, X/Twitter, YouTube, TikTok, Pinterest, GitHub, WhatsApp and Telegram. Share buttons are filtered out.
- 🏛️ **EU company identifiers**, taken from legal notice / *mentions légales* / *Impressum* pages and checksum-validated:
  - 🇫🇷 SIREN, SIRET and the intra-EU VAT number (derived automatically from the SIREN)
  - 🇩🇪 Handelsregister number (HRB/HRA) and register court, USt-IdNr
  - 🇬🇧 Companies House number, VAT
  - VAT numbers for 20+ European countries
- 🧰 **Tech stack** (60+ technologies): WordPress, Shopify, Wix, Webflow, PrestaShop, HubSpot, Google Analytics, Meta Pixel, Google Ads, LinkedIn Insight, Klaviyo, Intercom, Axeptio/Didomi/Cookiebot…
- ✉️ **Email provider** from MX records: Google Workspace, Microsoft 365, OVHcloud, IONOS, Zoho…
- 📅 **Domain age, expiry date and registrar** from RDAP, the official WHOIS successor.
- 🏢 **schema.org organization data**: legal name, address, founding date.
- ⭐ **Contactability score (0–100)**: a single number to sort and prioritize your leads.

No browser, no login and no API key. It is fast and cheap.

### Why this enricher?

| | Website Lead Enricher | Typical contact scrapers |
|---|---|---|
| Emails, phones, socials | ✅ | ✅ |
| Cloudflare-protected / obfuscated emails | ✅ | often ❌ |
| Email type (role vs personal, on-domain) | ✅ | ❌ |
| EU legal IDs (SIREN/SIRET/VAT/HRB/UK CRN) | ✅ | ❌ |
| Tech stack + ad pixels | ✅ | ❌ (separate actor) |
| Email provider (MX) + domain age | ✅ | ❌ (separate actor) |
| One row per website, ready for your CRM | ✅ | one row per page |
| **You only pay for websites that answered** | ✅ | pay per page, even errors |

### Typical use cases

- **Enrich Google Maps leads**: run [Google Maps Scraper](https://apify.com/compass/crawler-google-places) and paste its dataset ID here. The original fields (`title`, `placeId`, `phone`, `address`…) are kept under `source`.
- **Agencies selling websites, SEO or ads**: find businesses running WordPress without analytics, shops without the Meta Pixel, or sites on outdated builders.
- **B2B prospecting in Europe**: get the SIREN or Handelsregister number to join with official registries (financials, directors).
- **KYB / supplier onboarding**: check that a website matches a legal entity and VAT number.
- **CRM hygiene**: refresh emails, phones and social links for a list of domains.

### Input

```json
{
  "websites": ["acme.com", "https://www.boulangerie-dupont.fr", "mueller-maschinenbau.de"],
  "maxPagesPerWebsite": 4,
  "detectTechnologies": true,
  "lookupEmailProvider": true,
  "lookupDomainAge": true
}
```

You can also give `"datasetId": "<ID of a Google Maps Scraper run dataset>"`. Any dataset whose items have a `website`, `url` or `domain` field works. Duplicate domains are removed automatically.

The actor scans the homepage plus up to `maxPagesPerWebsite` pages that most likely hold contact data: *contact*, *legal notice / mentions légales / Impressum*, *about*, *privacy*.

### Output (one item per website)

Example for a fictional company:

```json
{
  "input": "boulangerie-dupont.fr",
  "domain": "boulangerie-dupont.fr",
  "status": "ok",
  "url": "https://www.boulangerie-dupont.fr/",
  "title": "Boulangerie Dupont – Pains artisanaux à Lyon",
  "language": "fr",
  "country": "FR",
  "emails": [
    { "email": "contact@boulangerie-dupont.fr", "type": "role", "onSiteDomain": true, "freeProvider": false },
    { "email": "jean.dupont@boulangerie-dupont.fr", "type": "personal", "onSiteDomain": true, "freeProvider": false }
  ],
  "phones": ["+33478000001"],
  "socials": {
    "instagram": ["https://www.instagram.com/boulangeriedupont"],
    "linkedin": ["https://www.linkedin.com/company/boulangerie-dupont"]
  },
  "legalIds": { "siren": ["552032534"], "siret": ["55203253400018"], "vat": ["FR27552032534"] },
  "organization": { "name": "Boulangerie Dupont", "address": "12 rue de la Paix, 69002, Lyon, FR" },
  "technologies": [
    { "name": "Google Analytics", "category": "analytics" },
    { "name": "Meta Pixel", "category": "advertising" },
    { "name": "WordPress", "category": "cms" },
    { "name": "Axeptio", "category": "consent" }
  ],
  "mxRecords": ["mx1.mail.ovh.net", "mx2.mail.ovh.net"],
  "emailProvider": "OVHcloud",
  "domainCreatedAt": "2009-04-02",
  "domainAgeYears": 17.6,
  "registrar": "OVH sas",
  "contactabilityScore": 100,
  "pagesScanned": [
    "https://www.boulangerie-dupont.fr/",
    "https://www.boulangerie-dupont.fr/contact/",
    "https://www.boulangerie-dupont.fr/mentions-legales/"
  ],
  "scrapedAt": "2026-10-22T19:00:00+00:00"
}
```

Every item also carries **flat, CSV-friendly columns** for spreadsheets and CRM imports: `primaryEmail`, `allEmails`, `primaryPhone`, `allPhones`, `linkedinUrl`, `facebookUrl`, `instagramUrl`, `twitterUrl`, `youtubeUrl`, `tiktokUrl`, `companyId`, `vatNumber` and `techStack`. The dataset's default *Leads overview* view shows exactly these columns.

Websites that could not be enriched still get a row with a `status` (`unreachable`, `blocked`, `http-403`, `http-429`, `timeout`, `invalid-input`) and an `error` message, so you can see exactly what happened. **These rows are not charged.**

Export everything as JSON, CSV, Excel or HTML, or get it through the API. It also connects to Make, Zapier, n8n, Google Sheets and other integrations.

### Pricing

Pay per result: **you are only charged for websites that were successfully enriched**. All data points are included: there are no add-ons to unlock.

### Tips

- **Speed**: about 1,000 websites in a few minutes with the default concurrency of 10. Raise it to 30–50 for big lists.
- **Blocked sites**: a few large websites use bot protection (Cloudflare challenge, DataDome). Enable a proxy in *Proxy configuration* if many of your sites return `blocked` or `http-403`. Most small-business websites never need one.
- **Cheaper and faster runs**: turn off tech detection, MX or RDAP if you don't need them, or set `maxPagesPerWebsite` to 1–2.

### Legal and data protection

This actor only reads information that companies publish on their own public websites (contact pages, legal notices required by law). It does not log in and does not bypass paywalls. Turn on **GDPR-friendly mode** (`roleEmailsOnly`) to collect only generic company addresses. If you process personal data, such as named employees' emails, you are responsible for having a legal basis under GDPR / CCPA for your use case (for example legitimate interest for B2B prospecting, with an easy opt-out). Respect local rules on direct marketing.

### Support

Found a website where an email or company ID is missed? Open an issue with the URL: extraction rules are improved continuously.

# Actor input Schema

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

Company websites or bare domains, one per line (e.g. 'acme.com', 'https://www.acme.fr/contact'). Duplicates are removed automatically.

## `datasetId` (type: `string`):

Pick an Apify dataset (or paste its ID) whose items contain a 'website' (or 'url' / 'domain') field. Perfect to enrich the output of Google Maps Scraper or any lead list.

## `datasetFieldsToKeep` (type: `array`):

When enriching a dataset, these fields of the original item are kept under 'source' so you can join results back.

## `maxWebsites` (type: `integer`):

Stop after this many websites (0 = no limit).

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

Besides the homepage, how many contact / legal notice / about pages to scan per website. 4 finds most emails and company IDs.

## `roleEmailsOnly` (type: `boolean`):

Keep only role-based addresses (contact@, info@, sales@…) and drop emails of named people (jean.dupont@…). Recommended for cold outreach in the EU.

## `detectTechnologies` (type: `boolean`):

CMS, e-commerce platform, analytics, ad pixels, chat, consent tools… (60+ technologies).

## `lookupEmailProvider` (type: `boolean`):

Google Workspace, Microsoft 365, OVH, IONOS… from the domain's MX records.

## `lookupDomainAge` (type: `boolean`):

Domain creation date, age in years, expiry date and registrar from RDAP (the official WHOIS successor).

## `concurrency` (type: `integer`):

How many websites are processed in parallel.

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

Usually not needed: company websites rarely block. Enable if many sites fail.

## Actor input object example

```json
{
  "websites": [
    "apify.com",
    "doctolib.fr",
    "basecamp.com"
  ],
  "datasetFieldsToKeep": [
    "title",
    "placeId",
    "phone",
    "address",
    "city",
    "categoryName",
    "advertiserName",
    "advertiserId",
    "totalAdsMax",
    "activeRecently",
    "leadInsight"
  ],
  "maxWebsites": 0,
  "maxPagesPerWebsite": 4,
  "roleEmailsOnly": false,
  "detectTechnologies": true,
  "lookupEmailProvider": true,
  "lookupDomainAge": true,
  "concurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `leads` (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": [
        "apify.com",
        "doctolib.fr",
        "basecamp.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("teakkaet/website-lead-enricher").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": [
        "apify.com",
        "doctolib.fr",
        "basecamp.com",
    ] }

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

```

## MCP server setup

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

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/cwGWigf0qLKOvuura/builds/BHcofYKuX18VsQIRA/openapi.json
