# Company Enrichment (`jcwilk/company-website-enrichment`) Actor

Company enrichment API: turn domains into one row each with business emails, phones (E.164), socials, company name, address, tech stack, email provider (MX/SPF/DMARC), SSL and domain age. $3 per 1,000 domains; failed domains are free.

- **URL**: https://apify.com/jcwilk/company-website-enrichment.md
- **Developed by:** [John Wilkinson](https://apify.com/jcwilk) (community)
- **Categories:** Lead generation, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.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

## Company Enrichment API: Website Emails, Phones, Tech Stack, DNS & Domain Age

**Domain in, company profile out.** A low-cost **company enrichment API** and **website email extractor**: send company domains (or URLs) and get one clean JSON/CSV row per domain with emails, phones, socials, tech stack, email provider, SSL and domain age. **$3 per 1,000 enriched domains**; unreachable or robots-blocked domains are free.

Give it a list of **company domains** and get back **one clean row per domain** with:

- 📧 **Business emails** from the company's own site (mailto links, Cloudflare-protected emails, `info [at] acme [dot] com`-style obfuscation, with junk, placeholder and image-filename false positives filtered out)
- 📞 **Phone numbers** normalized to **E.164** (`+14155552671`)
- 🔗 **Social links**: LinkedIn, X/Twitter, Facebook, Instagram, YouTube, GitHub, TikTok
- 🏢 **Company name** and **postal address** (JSON-LD, microdata, `<address>`)
- 🧰 **Tech stack** (Wappalyzer-style detection of 7,600+ technologies: CMS, ecommerce, analytics, CDN, frameworks, chat widgets…)
- ✉️ **DNS & email provider**: MX, SPF, DMARC policy, nameservers, and the email provider (Google Workspace, Microsoft 365, Zoho, Proofpoint…)
- 🔒 **SSL certificate**: issuer, validity and days until expiry
- 📅 **Domain registration (WHOIS via RDAP)**: registration date, domain age, registrar and expiry

It's a fast, cheap **website email extractor**, **contact finder**, **tech stack lookup** and **domain enrichment API** in one Actor. It uses plain HTTP (Cheerio) with no browser by default, crawls only the target's own pages (home, contact, about, imprint/Impressum, team), respects `robots.txt`, and rate-limits itself to about 1 request per second per site.

### Use cases

- **Lead generation and enrichment**: turn a domain list from a CRM, a spreadsheet or another scraper into contactable leads.
- **Sales intelligence**: find companies that use Shopify, HubSpot or WordPress, or that run Google Workspace vs. Microsoft 365.
- **Data cleaning**: check that domains are alive, find out how old they are, and catch expiring SSL certificates.
- **Security and IT audits**: check DMARC/SPF posture across many domains.

### Input

| Field | Default | Description |
|---|---|---|
| `domains` | *(required)* | Domains or URLs (`stripe.com`, `https://www.notion.so/about`). Duplicates are merged. |
| `maxPagesPerDomain` | 4 | Home page plus up to N-1 contact/about/imprint pages (max 20) |
| `includeTechStack` | true | Detect technologies |
| `includeDns` | true | MX/SPF/DMARC/NS and email provider |
| `includeSsl` | true | SSL issuer and expiry |
| `includeRdap` | true | Registration date via RDAP |
| `respectRobotsTxt` | true | Skip disallowed pages |
| `useBrowserFallback` | false | Re-render JavaScript-only home pages in headless Chrome |
| `defaultPhoneCountry` | "" | ISO code (US, GB, DE…) used to normalize local numbers |
| `maxConcurrency` | 20 | Parallel requests across all sites |

```json
{
  "domains": ["apify.com", "stripe.com", "https://basecamp.com/about"],
  "maxPagesPerDomain": 4,
  "defaultPhoneCountry": "US"
}
```

### Output (one row per domain)

`status` is one of `ok`, `partial` (the site was reached but a sub-lookup failed; details are in `error`), `failed`, `blocked_by_robots`, or `invalid_input`.

```json
{
  "input": "apify.com",
  "domain": "apify.com",
  "url": "https://apify.com/",
  "finalUrl": "https://apify.com/",
  "status": "ok",
  "error": null,
  "companyName": "Apify",
  "emails": [
    "hello@apify.com",
    "support@apify.com"
  ],
  "phones": [],
  "socials": {
    "github": [
      "https://github.com/apify"
    ],
    "linkedin": [
      "https://linkedin.com/company/apify",
      "https://www.linkedin.com/company/apify"
    ],
    "x": [
      "https://x.com/apify"
    ],
    "tiktok": [
      "https://www.tiktok.com/@apifytech",
      "https://www.tiktok.com/@apifyoffice"
    ]
  },
  "address": {
    "full": "Na P\u0159\u00edkop\u011b 959/27, Prague, 11000, CZ",
    "street": "Na P\u0159\u00edkop\u011b 959/27",
    "city": "Prague",
    "postalCode": "11000",
    "country": "CZ",
    "source": "json-ld"
  },
  "pagesCrawled": [
    "https://apify.com/",
    "https://apify.com/contact",
    "https://apify.com/contact-sales"
  ],
  "usedBrowser": false,
  "durationMs": 18006,
  "scrapedAt": "2026-10-25T19:21:15.066Z",
  "techStack": [
    {
      "name": "Algolia",
      "categories": [
        "Search engines"
      ],
      "confidence": 100,
      "website": "https://www.algolia.com"
    },
    {
      "name": "Amazon CloudFront",
      "categories": [
        "CDN"
      ],
      "confidence": 100,
      "website": "https://aws.amazon.com/cloudfront/"
    },
    {
      "name": "Amazon S3",
      "categories": [
        "CDN"
      ],
      "confidence": 100,
      "website": "https://aws.amazon.com/s3/"
    }
  ],
  "dns": {
    "mx": [
      {
        "priority": 1,
        "exchange": "aspmx.l.google.com"
      },
      {
        "priority": 5,
        "exchange": "alt1.aspmx.l.google.com"
      }
    ],
    "spf": "v=spf1 a mx include:_spf.google.com include:mailgun.org include:amazonses.com include:19497222.spf05.hubspotemail.net -all",
    "dmarc": "v=DMARC1; p=reject; sp=reject; pct=100; rua=mailto:dmarc-reports@apify.com; ri=604800",
    "dmarcPolicy": "reject",
    "emailProvider": "Google Workspace",
    "nameservers": [
      "ns-1225.awsdns-25.org",
      "ns-1928.awsdns-49.co.uk"
    ],
    "a": [
      "18.65.238.33"
    ]
  },
  "ssl": {
    "issuer": "Amazon",
    "subject": "*.apify.com",
    "validFrom": "2026-07-03T00:00:00.000Z",
    "validTo": "2027-01-16T23:59:59.000Z",
    "daysRemaining": 83,
    "altNames": [
      "*.apify.com",
      "apifier.com"
    ],
    "protocol": "TLSv1.3",
    "authorized": true
  },
  "rdap": {
    "registered": "2009-06-02T17:14:10Z",
    "expires": "2035-06-02T17:14:10Z",
    "lastChanged": "2026-05-16T16:53:04Z",
    "registrar": "Amazon Registrar, Inc.",
    "ageYears": 17.4,
    "status": [
      "client transfer prohibited"
    ],
    "rdapUrl": "https://rdap.verisign.com/com/v1/domain/apify.com"
  }
}
```

Download results as JSON, CSV, Excel or HTML, or call the Actor through the Apify API, its MCP server, Make, Zapier or n8n.

### Pricing

**Pay per event, no subscription:**

| Event | Price |
|---|---|
| Actor start (charged by Apify, per GB of run memory) | $0.0005 per GB |
| Domain enriched (`ok` or `partial`) | **$0.003** ($3 per 1,000) |

Failed, invalid and robots-blocked domains are **free**. Example: 1 domain at 1 GB = $0.0035; 1,000 domains in one run = about $3.0005. Batch many domains per run to make the start fee negligible, and set a maximum charge per run in Apify to cap spend.

### Call it from code

```bash
curl -X POST "https://api.apify.com/v2/acts/jcwilk~company-website-enrichment/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' -d '{"domains":["stripe.com","apify.com"]}'
```

### FAQ

**Is this a Clearbit / Apollo / BuiltWith alternative?** For data a company publishes on its own website and in public DNS/TLS/RDAP records, yes, and at a fraction of the price. It doesn't have a people database or private firmographics such as revenue or headcount.
**Does it scrape LinkedIn, Google or other third-party sites?** No. It only visits the company's own website, plus public DNS, TLS and RDAP infrastructure.

**Why are there no emails for some big companies?** Many large sites use contact forms instead of publishing addresses. The Actor never guesses or generates emails. Off-site addresses are kept only when the site links them explicitly with `mailto:`.

**Is it GDPR-compliant?** It collects business contact details that companies publish on their own websites. If you process personal data, such as named employee emails, you are responsible for having a lawful basis (for example legitimate interest) and for honoring opt-outs. Respect anti-spam laws such as CAN-SPAM and ePrivacy.

**Why is the domain registration date empty for .io, .de and some other TLDs?** Those registries don't run a public RDAP server. The Actor uses the official IANA RDAP bootstrap and skips unsupported TLDs without failing the row.

**How accurate is tech detection?** It uses the open-source webappanalyzer fingerprints on the HTML, headers, cookies, meta tags, scripts and DOM of up to 2 pages. It doesn't execute JavaScript unless browser fallback is on, so technologies that are only visible at runtime may be missed. Low-confidence matches (under 50) are dropped.

**What about sites that block bots or are JavaScript-only?** Turn on `useBrowserFallback`. A site that disallows all crawling in `robots.txt` returns `blocked_by_robots` and isn't charged.

**How fast is it?** In local tests a 10-domain batch took about 20 seconds (around 2 seconds per domain thanks to parallelism), using under 1 GB of memory.

### Notes

- Tech fingerprints: [enthec/webappanalyzer](https://github.com/enthec/webappanalyzer) (GPL-3.0). They are downloaded at build time into `data/` and kept as separate data files. The Actor's code is MIT.
- Run it locally without an Apify account: `npm ci && npm run fingerprints && npm run build && npm start` (input goes in `storage/key_value_stores/default/INPUT.json`), or `apify run` if you have the Apify CLI.

# Actor input Schema

## `domains` (type: `array`):

Company domains or website URLs, e.g. stripe.com or https://www.notion.so/about. Duplicates are merged.

## `maxPagesPerDomain` (type: `integer`):

Home page plus up to N-1 contact/about/imprint/team pages found by link text.

## `includeTechStack` (type: `boolean`):

Wappalyzer-style detection (CMS, analytics, frameworks, CDN, ecommerce…) using the open webappanalyzer fingerprints.

## `includeDns` (type: `boolean`):

Look up MX/TXT/NS and infer the email provider (Google Workspace, Microsoft 365…).

## `includeSsl` (type: `boolean`):

Issuer, validity dates and days until expiry.

## `includeRdap` (type: `boolean`):

Registration date, expiry, registrar and domain age via the official RDAP protocol.

## `respectRobotsTxt` (type: `boolean`):

Skip pages disallowed by the site's robots.txt.

## `useBrowserFallback` (type: `boolean`):

Re-render the home page in headless Chrome when plain HTTP finds nothing. Slower; same price.

## `defaultPhoneCountry` (type: `string`):

ISO country code (e.g. US, GB, DE) used to normalize local phone numbers without a + prefix to E.164.

## `maxConcurrency` (type: `integer`):

Parallel requests across all sites (each site is still rate-limited to ~1 request/second).

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

Per-page navigation timeout.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "stripe.com",
    "basecamp.com"
  ],
  "maxPagesPerDomain": 4,
  "includeTechStack": true,
  "includeDns": true,
  "includeSsl": true,
  "includeRdap": true,
  "respectRobotsTxt": true,
  "useBrowserFallback": false,
  "defaultPhoneCountry": "",
  "maxConcurrency": 20,
  "requestTimeoutSecs": 15
}
```

# Actor output Schema

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

One row per domain: emails, phones, socials, tech stack, DNS, SSL, RDAP.

## `contacts` (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 = {
    "domains": [
        "apify.com",
        "stripe.com",
        "basecamp.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jcwilk/company-website-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 = { "domains": [
        "apify.com",
        "stripe.com",
        "basecamp.com",
    ] }

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

```

## MCP server setup

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