# Company Enrichment by Domain: Logo, Emails, Socials, Tech (`charlesmarkette/company-enrichment-by-domain-logo-emails-socials`) Actor

Turn a list of company domains into rich rows: company name, description, logo, emails, phones, LinkedIn and other socials, address, country, technologies, email provider and domain age. Read from each company's own website and public registry data.

- **URL**: https://apify.com/charlesmarkette/company-enrichment-by-domain-logo-emails-socials.md
- **Developed by:** [Charles Markette](https://apify.com/charlesmarkette) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 company 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 by Domain** turns a list of company domains or websites into one company profile per row: **company name**, **description**, **logo** and **favicon**, **emails**, **phone numbers** (E.164), **social profiles** (LinkedIn, X, Facebook, Instagram, YouTube, TikTok, GitHub, Pinterest, Crunchbase), **postal address**, **founding year**, **language**, a **country hint**, the **technologies** the site runs on, the **email provider** behind the domain (Google Workspace, Microsoft 365…) and the **domain's age and registrar**. Paste domains, URLs or work email addresses, or point it at any Apify dataset of leads and the columns are added next to each item.

Everything comes from **the company's own public website** and **public DNS / registry (RDAP) data**. No third-party data vendors, no LinkedIn scraping (it only records the LinkedIn link the company puts on its own site), no guessing.

### What it reads, per company

1. The **home page**.
2. Up to 3 (configurable, 0–10) **company pages** linked from it: about, contact, imprint and similar pages, found by their link text and URL in many languages (About us, Contact, Impressum, Über uns, Qui sommes-nous, Quiénes somos, Chi siamo…). Blog posts, product pages, carts and logins are never read.
3. The domain's **MX records** (email provider) and its **RDAP** record (registration date, registrar).

At most 2 requests go to one website at a time, busy answers (429/5xx) are retried with backoff (honouring `Retry-After`), and every request identifies the tool in its User-Agent. Addresses that resolve to private or internal networks are never visited, including on redirects.

### Use cases

- **Lead enrichment:** add logo, description, LinkedIn page and a contact email to every company a Google Maps or directory scraper found.
- **CRM clean-up:** fill in missing company names, logos, social links and countries for the domains already in your CRM.
- **Lead scoring:** domain age, email provider (Google Workspace vs Microsoft 365), technologies (Shopify, WordPress, HubSpot…) and country in one pass.
- **Market maps:** turn a list of competitor or partner domains into a table with names, descriptions, logos and tech stacks.
- **Outreach prep:** the published company emails and phones, plus the social profiles to follow.

### How to use it

1. Add **Company domains or websites** (`acme.com`, `https://www.acme.com/en/`, `sales@acme.com`), and/or pick a **Dataset to enrich**. For datasets, set **Domain fields** if your website column isn't named website, url, domain, companyWebsite or email.
2. Choose what to collect: **Company pages per domain**, **Technologies** and **Email provider and domain age** (all on by default).
3. Run it. Export the rows as CSV, Excel or JSON, or chain the run with an integration.

**Input example**

```json
{
  "domains": ["acme-widgets.com", "https://www.boulangerie-martin.fr", "sales@globex.io"],
  "maxPagesPerDomain": 3,
  "includeTechnologies": true,
  "includeDomainInfo": true
}
```

**Enrich a dataset of leads**

```json
{
  "datasetId": "<your dataset ID or {{resource.defaultDatasetId}}>",
  "domainFields": ["website", "company.url", "email"],
  "keepItemFields": true
}
```

**Output example** (one row, lists shortened)

```json
{
  "inputUrl": "acme-widgets.com",
  "domain": "acme-widgets.com",
  "finalUrl": "https://acme-widgets.com/",
  "statusCode": 200,
  "companyName": "Acme Widgets Inc.",
  "description": "Acme Widgets makes industrial widgets for factories worldwide.",
  "logoUrl": "https://acme-widgets.com/img/acme-logo.svg",
  "logoSource": "schema",
  "faviconUrl": "https://acme-widgets.com/favicon-32.png",
  "primaryEmail": "press@acme-widgets.com",
  "emails": ["info@acme-widgets.com", "press@acme-widgets.com", "support@acme-widgets.com", "sales@acme-widgets.com"],
  "primaryPhone": "+14155550100",
  "phones": ["+14155550100", "+14155550132"],
  "socials": {
    "linkedin": "https://www.linkedin.com/company/acme-widgets",
    "x": "https://x.com/acmewidgets",
    "facebook": "https://www.facebook.com/acmewidgets",
    "instagram": "https://www.instagram.com/acme.widgets",
    "youtube": "https://www.youtube.com/@acmewidgets",
    "tiktok": null,
    "github": "https://github.com/acme-dev",
    "pinterest": null,
    "crunchbase": "https://www.crunchbase.com/organization/acme-widgets"
  },
  "address": {"streetAddress": "1 Main St", "addressLocality": "Springfield", "addressRegion": "IL", "postalCode": "62701", "addressCountry": "United States"},
  "addressText": "1 Main St, Springfield, IL 62701, United States",
  "foundingYear": 2009,
  "language": "en-US",
  "countryHint": "US",
  "countryHintSource": "schemaAddress",
  "technologies": ["WordPress", "Google Tag Manager", "Nginx"],
  "techCategories": {"CMS": ["WordPress"], "Tag manager": ["Google Tag Manager"], "Web server": ["Nginx"]},
  "emailProvider": "Google Workspace",
  "mxRecords": ["aspmx.l.google.com", "alt1.aspmx.l.google.com"],
  "domainCreatedAt": "2009-03-12T10:00:00Z",
  "domainAgeYears": 17.6,
  "registrar": "Example Registrar, LLC",
  "domainInfoNote": null,
  "pagesFetched": 4,
  "pageUrls": ["https://acme-widgets.com/", "https://acme-widgets.com/about-us", "https://acme-widgets.com/contact", "https://acme-widgets.com/privacy"],
  "enrichedAt": "2026-10-22T12:00:00Z",
  "error": null
}
```

**Where each field comes from**

| Field | Source, in order of preference |
|---|---|
| `companyName` | schema.org Organization `name` (JSON-LD) → `og:site_name` → the home page `<title>`, cleaned ("Home | Acme Widgets" → "Acme Widgets") |
| `description` | `<meta name="description">` → `og:description` → schema.org `description` (home page first) |
| `logoUrl`, `logoSource` | schema.org `logo` (`schema`) → the largest `apple-touch-icon` (`appleTouchIcon`) → `og:image` as a fallback (`ogImage`; often a social banner rather than a logo) |
| `faviconUrl` | the largest declared `<link rel="icon">`; `null` when the site declares none |
| `emails` | `mailto:` links, page text (including `name [at] domain [dot] com` and Cloudflare-protected addresses) and JSON-LD; deduplicated; addresses on the company's domain first. Placeholders, image file names and no-reply addresses are dropped. |
| `phones` | `tel:` links, JSON-LD `telephone` and labelled numbers ("Phone:", "Tel.", "Tél :"…) in page text, as E.164. Numbers without a + code are read with the domain's country (acme.de → DE), else your **Default country**, else US. |
| `socials` | one company-level link per platform from the site's links and JSON-LD `sameAs`. Share/intent buttons, posts, videos and personal LinkedIn profiles (`/in/…`) are skipped. |
| `address`, `addressText` | schema.org `PostalAddress` in the site's JSON-LD only |
| `foundingYear` | schema.org `foundingDate` only; never guessed from page text |
| `language` | the home page's `<html lang>` |
| `countryHint`, `countryHintSource` | the schema.org address country (`schemaAddress`) → the country of the phone numbers written with a + code (`phone`) → the country-code TLD (`ccTLD`; generic-use TLDs such as .io, .co, .ai don't count) |
| `technologies`, `techCategories` | 221 technology fingerprints matched against the home page's HTML, scripts, headers and cookies |
| `emailProvider` | the MX records: `Google Workspace`, `Microsoft 365`, `Zoho`, `Proton`, `Other`, or `None` when the domain has no MX records; `null` when not looked up |
| `domainCreatedAt`, `domainAgeYears`, `registrar` | the registry's RDAP record; `null` when unavailable (`domainInfoNote` says why) |

Rows for companies that couldn't be enriched have every company field empty and an `error` in plain English. A run summary (companies enriched and failed, pages read, why the run stopped) is saved as `OUTPUT` in the key-value store.

### How much does it cost?

Pay per event: **$5.00 per 1,000 companies** ($0.005 per company whose website was reached), **Apify platform usage included**. A company counts when its home page answered with a web page, however few fields it publishes. **Unreachable sites are free**: domains that don't resolve, connection failures, error or bot-protection answers (403, 429, 503…), private addresses, input that isn't a domain, and free-email domains (gmail.com…) all give a free row with an `error`. Repeats skipped by **Enrich each domain once** are free too. Each run also has Apify's run start fee of **$0.005** (one start event per GB of run memory; the default 512 MB run is charged one).

**Worked examples:**

- 1,000 company websites, all reachable: 1,000 × $0.005 = **$5.00**.
- 500 leads from a Google Maps run, 60 of which have a dead website: 440 × $0.005 = **$2.20**.

If you set a maximum cost per run, the Actor stops cleanly at that limit, and a resumed run continues after the rows already stored.

### FAQ and limits

#### Does it return employee counts, revenue or funding?

No. It returns only what the company publishes on its own website plus public DNS and registry data. It doesn't use data vendors, doesn't estimate company size, and doesn't log in to or scrape LinkedIn, Crunchbase or any other platform (it records the links the company itself publishes).

#### Why are some fields empty?

Because the site doesn't publish them where the Actor looks. Many sites have no schema.org data (so no address or founding year), no apple-touch-icon (so the logo falls back to `og:image`, or is empty), or a contact form instead of an email address. Sites that build their pages with JavaScript in the browser may show little to a plain HTTP reader. Emails or phones shown as images can't be read.

#### Why is the registration date or registrar missing?

Some registries don't offer RDAP (for example several country-code TLDs), and some publish less in it, or rate-limit it. `domainInfoNote` says what happened. For full WHOIS fallback on those TLDs, use [Domain WHOIS & DNS Lookup](https://apify.com/charlesmarkette/domain-whois-dns-lookup-bulk-rdap).

#### How reliable is the country hint?

It's a hint, and `countryHintSource` says what it's based on. A schema.org address is the company's own statement; a phone country or ccTLD is a signal, not proof (a .de domain can belong to a US company).

#### Is the logo always a logo?

`schema` and `appleTouchIcon` logos almost always are. `ogImage` is the page's social sharing image: often a logo, sometimes a banner or photo. Filter on `logoSource` if that matters.

#### Does it respect robots.txt?

It reads at most the home page and a few company pages per site (4 pages at the default), like a visitor who checks a company's About and Contact pages, and doesn't crawl beyond that. It doesn't read robots.txt. If you need robots.txt-aware crawling of more pages, use [Website Contact Info Scraper](https://apify.com/charlesmarkette/website-contact-info-scraper-emails-phones-socials).

#### What does "Enrich each domain once" do with a dataset?

With it on (the default), the second lead at the same company domain is skipped and not output. Turn it off to get one row per item, each charged as its own company.

### Use responsibly

The emails and phones are **business contact details the companies publish publicly**. How you use them is up to you and the law where you and your contacts are: privacy and anti-spam rules such as the **GDPR** (EU/UK) and **CAN-SPAM** (US) apply to storing and emailing them. Respect opt-outs and don't use the results for unsolicited bulk messaging where that's not allowed.

### Related Actors

| Actor | Use it to |
|---|---|
| [Website Contact Info Scraper](https://apify.com/charlesmarkette/website-contact-info-scraper-emails-phones-socials) | Crawl more pages per site (up to 30, robots.txt-aware) for every published email, phone and social profile. |
| [Website Tech Stack Detector](https://apify.com/charlesmarkette/website-tech-stack-detector-shopify-cms-analytics) | Get every detected technology with confidence, version and evidence, plus Shopify store details and tracking IDs. |
| [Domain WHOIS & DNS Lookup](https://apify.com/charlesmarkette/domain-whois-dns-lookup-bulk-rdap) | Full registration data (expiry, nameservers, DNSSEC, WHOIS fallback) and SPF/DMARC for the same domains. |
| [Phone Number Validator & Formatter](https://apify.com/charlesmarkette/phone-number-validator-formatter-bulk-e164) | Get the type (mobile, landline), carrier and region of the phones found. |
| [Merge & Deduplicate Datasets](https://apify.com/charlesmarkette/merge-deduplicate-datasets-only-new-items) | Keep only new companies between runs before enriching them. |
| [Google Sheets Sync](https://apify.com/charlesmarkette/google-sheets-sync) | Send the enriched rows to a Google Sheet. |

Phone parsing: [phonenumbers](https://github.com/daviddrysdale/python-phonenumbers) (Google's libphonenumber). Domain parsing: [tldextract](https://github.com/john-kurkowski/tldextract) with the Public Suffix List. RDAP servers: [IANA bootstrap list](https://data.iana.org/rdap/dns.json).

# Actor input Schema

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

One per line. Domains (acme.com), website URLs (https://www.acme.com/en/) or email addresses on the company's own domain (sales@acme.com) all work. Each company becomes one output row.

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

Optional. A dataset of leads or companies (from Google Maps, a directory scraper, a CSV import…). For each item, the first field below that holds a domain, URL or email is enriched and the company columns are added next to the item's fields. Use {{resource.defaultDatasetId}} in an integration.

## `domainFields` (type: `array`):

Item fields to take the website from, in order of preference. Dotted paths work (company.website). Default: website, url, domain, companyWebsite, email.

## `keepItemFields` (type: `boolean`):

On: each output row is the original item plus the company columns. Off: only the company columns.

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

How many about / contact / company pages to read after the home page (0–10). They are found by their link text and URL (About us, Contact, Impressum, Über uns, Qui sommes-nous…); blog posts and product pages are never read. 0 = home page only.

## `includeTechnologies` (type: `boolean`):

Detect the technologies on the home page (CMS, e-commerce platform, analytics, tag managers, CDN, frameworks…) from its HTML, scripts, response headers and cookies. 221 technologies.

## `includeDomainInfo` (type: `boolean`):

Look up the domain's MX records (email provider: Google Workspace, Microsoft 365, Zoho, Proton, other) and its registration date and registrar from the registry's public RDAP service.

## `onlySiteDomainEmails` (type: `boolean`):

Drop email addresses that aren't on the company's domain (for example a web agency's address in the footer).

## `defaultCountry` (type: `string`):

Optional two-letter ISO code (US, GB, DE…) used to read phone numbers written without a + country code. Leave empty to use the domain's country (acme.de → DE), else US.

## `dedupe` (type: `boolean`):

Skip repeats of a domain already enriched in this run (for example many leads at the same company). Skipped repeats are free and not output.

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

How many companies to enrich at the same time (1–20). Each website still gets at most 2 requests at a time.

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

Optional cap on output rows (each row is one company).

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "https://www.python.org"
  ],
  "keepItemFields": true,
  "maxPagesPerDomain": 3,
  "includeTechnologies": true,
  "includeDomainInfo": true,
  "onlySiteDomainEmails": false,
  "dedupe": true,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `items` (type: `string`):

No description

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

// Run the Actor and wait for it to finish
const run = await client.actor("charlesmarkette/company-enrichment-by-domain-logo-emails-socials").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",
        "https://www.python.org",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("charlesmarkette/company-enrichment-by-domain-logo-emails-socials").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",
    "https://www.python.org"
  ]
}' |
apify call charlesmarkette/company-enrichment-by-domain-logo-emails-socials --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,charlesmarkette/company-enrichment-by-domain-logo-emails-socials"
        }
    }
}
```

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/wlFIf0YgdfwPetZQE/builds/G9HUkW0RxzFN6Ed9F/openapi.json
