# Company Data by Domain (`b2bdata/company-by-domain`) Actor

Moved to https://apify.com/b2bdata/company-profile-by-website (new price, same job). This older copy is deprecated and kept for reference.

- **URL**: https://apify.com/b2bdata/company-by-domain.md
- **Developed by:** [Open Enrich](https://apify.com/b2bdata) (community)
- **Categories:** Lead generation, Marketing
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.10 / 1,000 company delivereds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## Company Data by Domain

Company data by domain: give a list of company domains, get one company per domain, with name, industry, employee count, location and LinkedIn page. No login, no cookies, no start fee. You pay only for a company row you receive.

**No login | Domains, URLs or emails in | One company per row | Shared domains skipped, never guessed | Unknown domains = free | JSON/CSV export**

> **Domain in, company out.** Many company tools start from a company name or a LinkedIn URL. This one starts from the domain you already hold in a CRM, a form or a target list. It returns a slim company card, not a full profile: no description, no funding, no founding year. When several unrelated companies declare the same domain, it returns the one that is clearly the owner or nothing, and the nothing is free.

[See all actors by b2bdata](https://apify.com/b2bdata)

***

### 💳 Pricing and plans

One event, `company-card`, charged once per company row delivered. Prices per 1,000 companies (set on the Pricing tab):

| Event | When it is charged | Free plan | Gold plan |
|---|---|---|---|
| `company-card` | A company row is delivered to your dataset | $1.496 | $1.096 |

Bronze and Silver prices are on the Pricing tab. Higher Apify plans only lower the price. Empty runs, unknown domains, skipped domains, failed lookups, unreadable entries and notices are free, and there is no start fee.

**Plan-credit math.** The free plan's $5 monthly credit covers about 3,340 companies at the Free price.

#### Success-only billing

You are charged only for a company row you receive. A domain with no company on file gets one free notice row (`reason: "unknown_domain"`). A domain that several unrelated companies share, with no clear owner, gets one free notice row (`reason: "no_confident_match"`). An entry that is not a domain, a repeat, or a lookup that fails is listed in `MISSES` with its position and a reason and costs nothing.

#### The free plan

Free Apify accounts get up to 100 domains looked up per run, and as many runs as their Apify credit covers. Nothing is stored on our side. When a list is longer, the first 100 valid domains are looked up and one free notice row (`reason: "free_plan_limit"`) says how many were not looked up; they are not charged. Run again with the rest, or use a paid Apify plan for no per-run limit.

#### Keep a run small while you test

`limit` caps the whole run (default and maximum 2,500). Try one domain with `limit: 1`, read the row, then scale up. A run looks up one domain a second, so 2,500 domains take about 45 minutes.

***

### ⚡ Why this company data actor?

- **Start from the domain.** `stripe.com`, `https://www.stripe.com/about` and `jane@stripe.com` all become `stripe.com`. No company-name matching and no LinkedIn URL needed.
- **It says how it chose.** Every row carries `matchType` and `otherCompaniesOnDomain`, so you can see when a domain is shared and how the company was picked.
- **It does not guess on shared domains.** Public email domains, website builders and blog platforms are declared by many unrelated companies. Those return a free notice, not a random company.
- **Success-only, no start fee.** Unknown domains, skipped domains, bad entries, repeats and notices are free.

***

### 🎯 Use cases: turn a domain column into company records

- **CRM gap fill.** You hold a domain for an account and need the company name, industry and size.
- **Lead routing.** Employee count and industry from a work-email domain at sign-up.
- **List cleaning.** Check which domains in a target list belong to a company with a LinkedIn page.
- **Agent workflows.** An AI agent holds a domain and needs the company behind it in a single call.

***

### 🚀 Quick start: companies for a list of domains

#### 1. One domain

```json
{ "items": ["stripe.com"], "limit": 1 }
```

#### 2. A list, in any form

```json
{ "items": ["openai.com", "https://www.shopify.com/about", "sales@airbnb.com"] }
```

Each entry becomes its bare domain before the lookup.

***

### ⚙️ Inputs

| Key | Type | Default | What it does |
|---|---|---|---|
| `items` | array of strings | required | Company domains, website URLs or email addresses. A company name is not a domain and is listed in `MISSES` as `invalid_domain`. The same domain written twice is looked up once. Free plan: 100 domains per run. Maximum 2,500 entries. |
| `limit` | integer | 2,500 | Most companies delivered in the whole run, which also caps what is charged. Maximum 2,500. Domains not reached are listed in `MISSES`. |
| `includeAudit` | boolean | false | Adds an `audit` object to each row. |

Any other field stops the run before a lookup with `remove unsupported fields: ...`. Nothing is charged.

***

### 📤 Output

One result row per company. Rows keep input order. Empty values are left out.

| Key | Type | Meaning, and when it is missing |
|---|---|---|
| `domain` | string | The domain from your entry, cleaned |
| `name` | string | Company name |
| `linkedinUrl` | string | Public company page URL |
| `industry` | string | Industry label. Missing for many companies |
| `employeeCount` | integer | Employee count on file. Missing when it is not on file |
| `location` | string | Headquarters place as written on the company page |
| `logoUrl` | string | Logo image URL. Missing when there is none |
| `matchType` | string | How the company was chosen: `only_company`, `name_matches_domain` or `largest_by_headcount` |
| `otherCompaniesOnDomain` | integer | How many other companies on file declare the same domain (the data returns at most 10 companies per domain, so this counts up to 9) |
| `audit` | object | Only with `includeAudit`: `requestId`, `latencyMs`, `candidates`, `inputRaw` |

Example output (the shape is real, the values are illustrative):

```json
{
  "domain": "stripe.com",
  "name": "Stripe",
  "linkedinUrl": "https://www.linkedin.com/company/stripe",
  "industry": "Internet",
  "employeeCount": 16694,
  "location": "South San Francisco, California",
  "logoUrl": "https://example.com/logo.png",
  "matchType": "name_matches_domain",
  "otherCompaniesOnDomain": 9
}
```

#### How to read the rows

- **One domain can belong to many companies on file.** In a probe of 16 domains, 13 returned the maximum of 10 companies each (`stripe.com` and `microsoft.com` among them), most of them small unrelated records. The row is the owner, not the largest.
- **`matchType` tells you how sure to be.** `only_company`: exactly one company declares the domain. `name_matches_domain`: the company is named like the domain (Notion for `notion.so`) and is not dwarfed by another. `largest_by_headcount`: no company is named like the domain, but one has at least 50 employees and ten times the runner-up (Alphabet Inc. for `abc.xyz`).
- **`only_company` is the weakest.** A domain declared by one small company is returned as that company. Check `employeeCount` and `linkedinUrl` before you act on it.
- **Refused on purpose.** In the same probe, `gmail.com`, `example.com`, `wordpress.com`, `github.io` and `fb.com` each returned a free notice, because the companies on file for them are unrelated or too close in size.
- **The rule can miss a real owner.** A company whose name differs from its domain and whose size is not ten times the runner-up is skipped (`fb.com` is the example). You are not charged for it.
- **Employee count is a snapshot** of the number on the company page, not a payroll figure.

#### Other records in the run

- **`MISSES`** (key-value store): `[{index, input, reason}]` for every entry without a result row. Reasons: `unknown_domain`, `no_confident_match`, `invalid_domain`, `duplicate_input` (the same domain as an earlier entry; `duplicateOf` names it), `not_looked_up_limit` (the run `limit` was reached first), or `Upstream HTTP <code>` / `Upstream unavailable`.
- **`errors-company-by-domain`** (key-value store): the lookups that failed for a technical reason, so you can re-run only those domains.
- **`RUN_SUMMARY`**: counts (requested, valid, looked up, companies delivered, how many per `matchType`).
- **Notice rows** (`type: "notice"`) appear for an unknown domain, a shared domain with no clear owner, a free-plan list longer than 100 (`free_plan_limit`), a reached `limit` (`limit_reached`), a reached spend limit (`charge_limit_reached`) or invalid input (`invalid-input`). Notices are never charged.

#### What is NOT returned

- Description, funding, founding year or website text (use [company-domain-enrichment-api](https://apify.com/b2bdata/company-domain-enrichment-api) for firmographics)
- People at the company (use [people-at-company](https://apify.com/b2bdata/people-at-company))
- Email addresses or phone numbers (use [email-finder](https://apify.com/b2bdata/email-finder))
- A company from a name (use [company-name-to-domain](https://apify.com/b2bdata/company-name-to-domain) to get the domain first)

***

### 🛡️ Reliable results

**Our data promise.** We work to keep the data current, and we stand behind it. If a company is missing, the wrong company comes back or a row looks wrong, open the Issues tab with your run link. We review every report and sort it out with you, case by case.

- **No data is free and visible.** Every domain without a row is in `MISSES` with its position and a reason and is never charged.
- **No guesses on shared domains.** A domain with no clear owner returns a free notice.
- **Repeats are charged once.** The same domain written twice is one row.
- **Bounded pace.** Lookups run at about 60 a minute, so a long list takes time. The run timeout is one hour.
- **Typos fail early.** An unsupported input field, a bad `limit` or a list above 2,500 entries stops the run before any charge.

***

### 🤖 For AI agents (MCP)

This actor runs through the Apify MCP server. Prompt to copy:

> "Use b2bdata/company-by-domain with items=\["stripe.com"] and limit=1. Return name, industry, employeeCount and linkedinUrl."

**When to use it.** You hold a company domain and need the company name, industry, size and LinkedIn page.
**When not to.** You need a description or funding (use b2bdata/company-domain-enrichment-api), people (use b2bdata/people-at-company) or a domain from a company name (use b2bdata/company-name-to-domain).
**Input contract.** `items` array of domains, URLs or emails (at most 2,500); optional `limit` 1-2,500.
**Output contract.** One row per domain with `domain`, `name`, `linkedinUrl`, `industry`, `employeeCount`, `location`, `matchType`. Output is deterministic and schema-stable. Domains without a credible company are a free notice row and listed in `MISSES`.
**Smoke test.** `limit: 1` on a well-known domain returns one row.
**Error cases.** `No valid domains` means no entry was a domain. `remove unsupported fields`, a bad number or too many entries ends the run SUCCEEDED with one free `invalid-input` notice row and nothing charged.

***

### 🔌 Integrations: send results anywhere

1. **API.** Fetch rows from the run's default dataset: `GET /v2/datasets/{datasetId}/items?format=csv`.
2. **Webhook** on run success to push rows to your own endpoint.
3. **n8n, Make, Zapier.** Use the native Apify nodes: run the actor, then read the dataset.
4. **Google Sheets, Airtable, HubSpot, Salesforce, Clay.** Join on `domain` and map `name`, `industry` and `employeeCount` to account fields.

***

### 🕐 Schedule examples

- **Weekly CRM refresh.** A schedule with a saved task that points at your account-domain list.
- **New-signup enrichment.** A webhook from your sign-up form starts a run with the new domains.

***

### 🔗 Related actors

- `b2bdata/company-domain-enrichment-api`: richer firmographics for a domain, with description, size band, founding year and funding signal. [Open](https://apify.com/b2bdata/company-domain-enrichment-api)
- `b2bdata/people-at-company`: the people at a company, one row per person, by domain. [Open](https://apify.com/b2bdata/people-at-company)
- `b2bdata/company-name-to-domain`: the domain for a company name. [Open](https://apify.com/b2bdata/company-name-to-domain)
- `b2bdata/headcount-by-department`: how many people a company has per team. [Open](https://apify.com/b2bdata/headcount-by-department)

[See all actors by b2bdata](https://apify.com/b2bdata)

***

### ❓ FAQ

#### Data and coverage

**How do I get company data from a domain?**
Put the domain in `items` and run. You get one row with name, industry, employee count, location and LinkedIn page.

**Why did a domain return a notice instead of a company?**
Either no company is on file, or several unrelated companies share the domain and none stands out. Both are free and are in `MISSES` with the reason.

**Can I look up a company by name?**
No. A name is not a domain and is listed as `invalid_domain`. Use `b2bdata/company-name-to-domain` first.

**Why is `industry` missing on some rows?**
Many companies on file have no industry. Empty values are left out of the row.

**Do I need a LinkedIn account or cookies?**
No. It is a lookup without login, cookies or an account to ban.

#### Pricing

**What do I pay when a domain has no data?**
Nothing. There is no start fee, and unknown domains, skipped domains, bad entries, repeats and notices are free.

***

### 🛟 Support

Use the **Issues** tab on this actor's Apify page for bugs, questions and feature requests. We answer within 48 hours on working days. Please include the run ID and the input you used. Published on Apify by b2bdata. Not affiliated with, endorsed by, or sponsored by any company or person named in the examples above.

# Changelog

This Actor's version history is a separate document: https://apify.com/b2bdata/company-by-domain/changelog.md

# Actor input Schema

## `items` (type: `array`):

Company domains to look up. Example: \["stripe.com", "https://www.shopify.com/about", "jane@openai.com"]. A website URL or an email address is reduced to its domain; a company name is not a domain and is listed in the MISSES record as invalid_domain. Each domain is looked up once; repeats are listed in MISSES as duplicate_input. A domain with no company on file, or shared by unrelated companies with no clear owner, returns one free notice row. Free plan: 100 domains per run. Maximum 2500 per run.

## `limit` (type: `integer`):

Most companies delivered in the whole run, which also caps what is charged. Domains not reached are listed in MISSES and are not charged. Default and maximum 2500.

## `includeAudit` (type: `boolean`):

Adds requestId, latencyMs, candidates (how many companies the data holds for the domain) and inputRaw to each row under audit. Omit for clean rows.

## Actor input object example

```json
{
  "items": [
    "stripe.com"
  ],
  "limit": 2500,
  "includeAudit": false
}
```

# Actor output Schema

## `companies` (type: `string`):

One row per domain with a credible company: name, industry, employee count, location, LinkedIn page

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

Counts, match types and stop reason for this run

# 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 = {
    "items": [
        "stripe.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("b2bdata/company-by-domain").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 = { "items": ["stripe.com"] }

# Run the Actor and wait for it to finish
run = client.actor("b2bdata/company-by-domain").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 '{
  "items": [
    "stripe.com"
  ]
}' |
apify call b2bdata/company-by-domain --silent --output-dataset

```

## MCP server setup

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

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/ffmqbltmOnydulFIs/builds/waPiLNgkM2E646lxj/openapi.json
