# Dun & Bradstreet Scraper - Companies, Revenue & Contacts (`abotapi/dnb-com-scraper`) Actor

Scrape Dun & Bradstreet (dnb.com) business directory by company name, country, size, role or industry. Extract company profiles, revenue, employee counts, key executives, principals, contact details and stock information. Ideal for B2B lead generation, company research and market intelligence.

- **URL**: https://apify.com/abotapi/dnb-com-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Security:** Limited permissions
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 company records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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

**Dun & Bradstreet company data for lead generation, firmographic enrichment, and market mapping.** This actor searches the D\&B business directory by company name, walks its industry listings, and returns structured company records with revenue, employee counts, principals, contact details and stock listing data.

### Why This Scraper?

- **The definitive firmographic source.** Dun & Bradstreet maintains profiles on hundreds of millions of businesses with revenue, employee counts, corporate family roles and industry classification that most data providers resell.
- **Search the way you think.** Type a company name keyword plus an optional country, employee size range and corporate role; the directory applies every filter before results come back.
- **Browse industries directly.** Paste any directory industry page (country, region or city scoped) and the actor walks its listings page by page.
- **Rich company profiles.** Each record can be enriched with formatted revenue, exact employee counts with reliability metadata, key principals, phone, website, stock exchange, Fortune-style rankings, corporate family and similar companies.
- **Recurring-run friendly.** Incremental mode compares every scan against a saved baseline: unchanged companies are skipped, changed ones ship with the fields that moved, and disappeared companies can be reported.
- **Clean structured output.** Flat records with stable IDs, ready for spreadsheets, CRM imports, or direct API consumption.

### Use Cases

- **Who:** Sales and GTM teams building targeted prospect lists filtered by industry, size and corporate role.
- **Who:** Data teams enriching an existing company list with revenue bands, employee counts and executive names.
- **Who:** Market researchers mapping an industry across a country, region or city.
- **Who:** Ops teams keeping a CRM in sync: scheduled incremental runs flag new, changed and vanished companies.

### Data You Get

> Sample shape: values are illustrative placeholders, not from a live record.

| Field | Example |
| --- | --- |
| `companyName` | Sample Industries Inc |
| `encryptedDuns` | 53890f4828e079d340ea27fd3cfdd0ff |
| `url` | https://www.dnb.com/business-directory/company-profiles/sample-industries-inc.00000000000000000000000000000000 |
| `companyRole` | Parent |
| `industryName` | Computer Systems Design Services |
| `revenueFormatted` | $12.5 M |
| `employeesConsolidatedValue` | 412 |
| `employeesConsolidatedScope` | Consolidated |
| `keyPrincipal` | Jane Doe |
| `principals` | \[{"name": "Jane Doe", "position": "President"}] |
| `totalContactsOnFile` | 1,204 |
| `phone` | (000) 000-0000 |
| `website` | www.sampleindustries.example |
| `stockExchange` | NASDAQ:SMP |
| `industries` | \["Computer Systems Design Services", "Data Processing"] |
| `parentIndustry` | Information |
| `ownershipType` | Public |
| `isPrivate` | false |
| `ranks` | \[{"rank": 500, "list": "Fortune 1000 Revenue Rank", "year": "2026"}] |
| `corporateFamily` | {"globalHeadquarters": "Sample Industries Inc", "totalSubsidiaries": 12} |
| `similarCompanies` | \[{"name": "Peer Company LLC", "industry": "IT Services"}] |
| `addressCity` | Austin |
| `addressCountry` | United States |
| `changeType` | NEW |
| `scrapedAt` | 2026-01-01T00:00:00Z |

Enriched records also carry annual revenue history, financial statement lines, employee trends, similar-company lists and the full principals table in the Enriched companies output tab.

### How to Use

1. Pick a mode. **Search** looks companies up by name; **links** walks directory pages you paste.
2. In search mode add a country code and, optionally, an employee size range or corporate role filter.
3. Set the record limit and whether to enrich each company with its profile data.
4. Run the actor. Records land in the dataset as flat company rows.

#### Search by keyword with filters

**Search for software companies in the US with 501 to 1000 employees:**

```json
{
  "mode": "search",
  "queries": ["software"],
  "country": "us",
  "employeesMin": 501,
  "employeesMax": 1000,
  "companyRole": "parent",
  "fetchDetails": true,
  "maxItems": 20
}
```

#### Browse an industry page

**Walk a country-scoped industry listing:**

```json
{
  "mode": "urls",
  "urls": ["https://www.dnb.com/business-directory/us/software_publishers/companies"],
  "fetchDetails": true,
  "maxItems": 50
}
```

#### Browse a city-scoped listing plus a profile

**Links mode accepts region pages, city pages and company profile pages together:**

```json
{
  "mode": "urls",
  "urls": [
    "https://www.dnb.com/business-directory/us/california/los_angeles/construction/companies",
    "https://www.dnb.com/business-directory/company-profiles/sample-industries-inc.00000000000000000000000000000000"
  ],
  "maxItems": 50
}
```

#### Scheduled incremental monitoring

**Keep a watchlist in sync: unchanged rows are skipped:**

```json
{
  "mode": "search",
  "queries": ["logistics"],
  "country": "us",
  "maxItems": 200,
  "incrementalMode": true,
  "stateKey": "logistics-watchlist",
  "emitExpired": true,
  "fetchDetails": true
}
```

#### Run it from your code

**Python:**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("abotapi/dnb-com-scraper").call(run_input={
    "mode": "search",
    "queries": ["software"],
    "country": "us",
    "maxItems": 20,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["companyName"], item.get("revenueFormatted"))
```

**JavaScript:**

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('abotapi/dnb-com-scraper').call({
    mode: 'search',
    queries: ['software'],
    country: 'us',
    maxItems: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => console.log(item.companyName, item.revenueFormatted));
```

#### Tips

- Each search or browse scope serves its first 1,000 matches; scope tighter (add a region, city, or employee filter) instead of paging deeper.
- Leave enrichment on for the fullest records; turn it off for cheap, fast name-and-location sweeps.
- Incremental mode needs a complete scan to report disappeared companies, so pair it with a record limit comfortably above the scope size.

### Send results into your apps (MCP connectors)

This actor supports Apify MCP connectors. Name connectors in the `mcpConnectors` input and every collected record is sent to them after the run, so your spreadsheet, Notion workspace or agent workflow receives results without a separate export step. Set `notionParentPageUrl` to file each record as a Notion page under a parent of your choice.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | select | search | Search by company name, or walk directory links you paste. |
| `queries` | array | \["software"] | Company name keywords; each runs its own search and shares the record limit. |
| `country` | string | us | Two-letter country code the search is scoped to. |
| `employeesMin` | integer | (empty) | Optional minimum employee count, applied by the directory server-side. |
| `employeesMax` | integer | (empty) | Optional maximum employee count, applied by the directory server-side. |
| `companyRole` | select | any | Corporate family role filter: any, branch, parent, subsidiary. |
| `urls` | array | three sample links | Links mode: industry, region or city browse pages plus company profile pages. |
| `fetchDetails` | boolean | true | Read each company's profile to add revenue, employees, principals, contacts and stock data. |
| `maxPages` | integer | (empty) | Page walk limit per scope; empty means no page limit and defers to the record limit. |
| `maxItems` | integer | 20 | Maximum company records per run across all searches and links; 0 means unlimited. |
| `resumeFromRunId` | string | (empty) | Pick up an unfinished run: already-collected records are skipped. |
| `incrementalMode` | boolean | false | Compare scans against a saved baseline; unchanged companies are skipped. |
| `stateKey` | string | (empty) | Name for the saved baseline; use one key per recurring scope. |
| `emitUnchanged` | boolean | false | Also push records whose data did not change. |
| `emitExpired` | boolean | false | Push an EXPIRED row for baseline records missing from a complete scan. |
| `ignoreFieldsForChanges` | array | (empty) | Extra field names change detection should disregard. |
| `proxy` | object | automatic | Which Apify proxy the run connects through (a paid plan with proxy access is needed). The default was measured to serve the directory; choose residential exits only when you need a specific country. Proxy URLs you enter are used exactly as given. |
| `mcpConnectors` | array | (empty) | Connector IDs to receive collected records after the run. |
| `notionParentPageUrl` | string | (empty) | Notion parent page for per-record child pages. |
| `maxNotifyListings` | integer | 50 | Cap on records per connector export. |

### Output Example

> Sample shape: values are illustrative placeholders, not from a live record.

**One enriched company record:**

```json
{
  "companyName": "Sample Industries Inc",
  "encryptedDuns": "00000000000000000000000000000000",
  "url": "https://www.dnb.com/business-directory/company-profiles/sample-industries-inc.00000000000000000000000000000000",
  "companyRole": "Parent",
  "industryName": "Computer Systems Design Services",
  "revenueFormatted": "$12.5 M",
  "sales": 12500000,
  "salesCurrency": "USD",
  "revenueYear": "2025",
  "revenueReliability": "Actual",
  "employeesConsolidatedValue": 412,
  "employeesConsolidatedScope": "Consolidated",
  "employeesConsolidatedReliability": "Actual",
  "employeesThisSiteValue": 250,
  "keyPrincipal": "Jane Doe",
  "keyPrincipalPosition": "President and Chief Executive Officer",
  "principals": [{ "name": "Jane Doe", "position": "President and Chief Executive Officer" }],
  "totalPrincipals": 4,
  "totalContactsOnFile": "1,204",
  "phone": "(000) 000-0000",
  "website": "www.sampleindustries.example",
  "stockExchange": "NASDAQ:SMP",
  "tradeStyleName": "Sample Industries",
  "industries": ["Computer Systems Design Services"],
  "parentIndustry": "Information",
  "ownershipType": "Public",
  "entityType": "Parent",
  "isPrivate": false,
  "ranks": [{ "rank": 500, "list": "Fortune 1000 Revenue Rank", "year": "2026" }],
  "corporateFamily": { "globalHeadquarters": "Sample Industries Inc" },
  "addressStreet": "100 Example Pkwy Ste 300",
  "addressCity": "Austin",
  "addressRegion": "Texas",
  "addressPostalCode": "78701",
  "addressCountry": "United States",
  "changeType": "NEW",
  "detailFetched": true,
  "scrapedAt": "2026-01-01T00:00:00Z"
}
```

### Plan Requirement

This actor is priced per event: each pushed company record is a dataset result, each enriched record carries a detail surcharge, and every run carries a start charge. The directory checks every connection, so each run needs an Apify plan with proxy access; free plans do not include it, and such a run stops at once with a message that says so (you can enter your own proxy URLs instead). If the selected connection cannot be used, the run moves once to a backup connection and says so in the log; rows read that way carry the directory listing fields and the profile summary values (employee size bands instead of exact counts, no principals table or financial history), and the proxy usage of that backup connection is billed to your Apify account.

### FAQ

#### How much does a run cost?

A default run of 20 enriched records bills 20 dataset results, up to 20 detail enrichments and one start charge. Enrichment off bills results plus the start charge only.

#### Is it legal to scrape Dun & Bradstreet?

The actor collects publicly viewable directory pages the same way a browser does, at a modest request rate. Review the site's terms of service and your jurisdiction's data-protection rules before commercial use, and do not resell the data as your own directory product.

#### Can I schedule recurring runs?

Yes. Pair a schedule with incremental mode and a fixed state key: the first run saves a baseline, later runs push only new or changed companies, and optional EXPIRED rows report companies that left the scope.

#### Why did a run return fewer records than the directory shows for my search?

Each scope serves its first 1,000 matches. Add a region, city, employee range or role filter to scope tighter instead of paging deeper.

#### Why did a run fail with a connection message?

The directory checks every connection and occasionally refuses an exit. The run opens a fresh connection and retries a bounded number of times, then uses the backup connection once; when that fails too it ends with an honest failure instead of an empty result. Re-running later usually resolves it.

#### Can an AI agent use this actor?

Yes. The dataset is flat JSON with stable record IDs, and MCP connectors hand results straight to agent workflows.

### 🔗 More scrapers you might like

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>📇 <a href="https://apify.com/abotapi/jobstreet-companies-reviews-scraper"><b>JobStreet</b></a><br>Pull JobStreet company profiles and employee reviews across Malaysia, Singapore...</td><td>📱 <a href="https://apify.com/abotapi/clutch-directory-scraper"><b>Clutch Scraper</b></a><br>Scrape Clutch company directories and profiles. Get names, ratings, review counts, hourly...</td></tr>
<tr><td>📇 <a href="https://apify.com/abotapi/comparably-scraper"><b>Comparably</b></a><br>Extract rich company data from comparably.com using company names or profile URLs. Get...</td><td>💼 <a href="https://apify.com/abotapi/seek-companies-reviews-scraper"><b>SEEK Company Reviews</b></a><br>Scrape SEEK Australia and New Zealand company profiles and employee reviews. Choose...</td></tr>
<tr><td>💼 <a href="https://apify.com/abotapi/repvue-scraper"><b>RepVue Scraper</b></a><br>Scrape RepVue company profiles, RepVue Score, sales-rep reviews, and compensation by role...</td><td>🧩 <a href="https://apify.com/abotapi/naukri-com-scraper"><b>Naukri.com Scraper</b></a><br>Scrape Naukri.com jobs by keyword or URL. Extract job title, company, skills, experience...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/dnb-com-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `mode` (type: `string`):

Search looks companies up by name with optional filters. Links mode walks any page the directory publishes: industry browse pages (with region or city), and company profile pages.

## `queries` (type: `array`):

One or more company name keywords. Each keyword runs its own search; the record limit is shared between them.

## `country` (type: `string`):

Two-letter country code the search is scoped to, for example us, gb, de, in, cn. Leave as us for the United States.

## `employeesMin` (type: `integer`):

Optional lower bound on employee count, applied by the directory before results return.

## `employeesMax` (type: `integer`):

Optional upper bound on employee count, applied by the directory before results return.

## `companyRole` (type: `string`):

Optional role in the corporate family tree. The directory only narrows its role counts, so this is applied to the collected results.

## `urls` (type: `array`):

Links mode: paste industry browse pages, region or city browse pages, company profile pages, or legacy listing links. Multi-URL, filter fields ignored, pagination walks forward.

## `fetchDetails` (type: `boolean`):

Read each company's profile page to add revenue, employee counts, principals, contacts, stock listing, corporate family and similar companies. Turning this off ships search rows only and costs less.

## `maxPages` (type: `integer`):

How many result pages to walk per search or browse scope at most. Leave empty or 0 for no page limit: the record limit below is what stops a run. The directory serves the first 1,000 matches per scope.

## `maxItems` (type: `integer`):

Maximum company records to collect per run across all searches and links. 0 means unlimited.

## `proxy` (type: `object`):

Which Apify proxy the run connects through; it needs a paid Apify plan with proxy access. The default (automatic) was measured to serve the directory; pick residential exits only if you need a specific country. If the chosen connection cannot serve, the run falls back once to a backup connection and says so in the log. Proxy URLs you enter are used exactly as given.

## `resumeFromRunId` (type: `string`):

ID of an unfinished run to pick up from: records already collected by that run are skipped and the walk continues where it stopped.

## `incrementalMode` (type: `boolean`):

Compare every scanned record against the saved baseline: unchanged companies are skipped (no cost), changed ones ship with changeType and changedFields, and records that disappeared can be reported as EXPIRED.

## `stateKey` (type: `string`):

Optional name for the saved baseline. Use one key per recurring scope so scheduled runs compare like with like.

## `emitUnchanged` (type: `boolean`):

Incremental mode: also push records whose data did not change (they keep changeType UNCHANGED and are charged as dataset rows).

## `emitExpired` (type: `boolean`):

Incremental mode: push an EXPIRED row for every baseline record missing from a complete scan. Skipped automatically when a run stopped early.

## `ignoreFieldsForChanges` (type: `array`):

Field names change detection should disregard (yours are added to the built-in noise list, which already covers result position and run bookkeeping).

## `mcpConnectors` (type: `array`):

Connector IDs to send collected records to after the run, through the Apify MCP proxy.

## `notionParentPageUrl` (type: `string`):

Optional Notion page URL: each collected record becomes a child page under it.

## `maxNotifyListings` (type: `integer`):

Cap on how many records a connector export carries.

## Actor input object example

```json
{
  "mode": "search",
  "queries": [
    "software"
  ],
  "country": "us",
  "companyRole": "any",
  "urls": [
    "https://www.dnb.com/business-directory/us/software_publishers/companies",
    "https://www.dnb.com/business-directory/us/california/los_angeles/construction/companies",
    "https://www.dnb.com/business-directory/company-profiles/dr-horton-inc.53890f4828e079d340ea27fd3cfdd0ff"
  ],
  "fetchDetails": true,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}
```

# Actor output Schema

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

No description

## `detail` (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 = {
    "mode": "search",
    "queries": [
        "software"
    ],
    "country": "us",
    "companyRole": "any",
    "urls": [
        "https://www.dnb.com/business-directory/us/software_publishers/companies",
        "https://www.dnb.com/business-directory/us/california/los_angeles/construction/companies",
        "https://www.dnb.com/business-directory/company-profiles/dr-horton-inc.53890f4828e079d340ea27fd3cfdd0ff"
    ],
    "fetchDetails": true,
    "maxItems": 20,
    "proxy": {
        "useApifyProxy": true
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false,
    "maxNotifyListings": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/dnb-com-scraper").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 = {
    "mode": "search",
    "queries": ["software"],
    "country": "us",
    "companyRole": "any",
    "urls": [
        "https://www.dnb.com/business-directory/us/software_publishers/companies",
        "https://www.dnb.com/business-directory/us/california/los_angeles/construction/companies",
        "https://www.dnb.com/business-directory/company-profiles/dr-horton-inc.53890f4828e079d340ea27fd3cfdd0ff",
    ],
    "fetchDetails": True,
    "maxItems": 20,
    "proxy": { "useApifyProxy": True },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
    "maxNotifyListings": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/dnb-com-scraper").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 '{
  "mode": "search",
  "queries": [
    "software"
  ],
  "country": "us",
  "companyRole": "any",
  "urls": [
    "https://www.dnb.com/business-directory/us/software_publishers/companies",
    "https://www.dnb.com/business-directory/us/california/los_angeles/construction/companies",
    "https://www.dnb.com/business-directory/company-profiles/dr-horton-inc.53890f4828e079d340ea27fd3cfdd0ff"
  ],
  "fetchDetails": true,
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "maxNotifyListings": 50
}' |
apify call abotapi/dnb-com-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/dnb-com-scraper"
        }
    }
}
```

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/GVVdbARgRtYruI9we/builds/uL55ys61Yx49HV10o/openapi.json
