# BBB Business Directory Scraper (US & Canada) (`b2b_leads/bbb-real-time-data-scraper`) Actor

Scrape BBB.org in real time: business names, phones, websites, emails, addresses, accreditation, ratings, complaints and reviews across the US and Canada. Search by keyword and location, enrich full profiles, or paste URLs — streaming dataset, webhooks, pay per result, MCP-ready.

- **URL**: https://apify.com/b2b_leads/bbb-real-time-data-scraper.md
- **Developed by:** [Emmanuel](https://apify.com/b2b_leads) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.00 / 1,000 results

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

## BBB Real Time Data

Turn the Better Business Bureau directory into clean, real-time business intelligence. Search any US or Canadian market by keyword and location, and get structured JSON with **name, phone, website, email, address, BBB accreditation status, BBB letter rating, complaint counts, review counts and average star rating** — streamed to your dataset as it is collected.

Built for agencies, local-SEO teams, B2B sales researchers, due-diligence analysts, and outreach/CRM pipelines that need trustworthy business records without manual lookups.

> **Free-tier notice:** on a free Apify plan this Actor returns a **2-result sample per run** so you can test it instantly. Upgrade to a paid Apify plan for full, uncapped exports.

***

### What you can do with it

- **Local SEO & agency prospecting** — pull every plumber, roofer, or dentist in a city and rank them by BBB rating, accreditation, and complaint volume.
- **B2B lead lists** — enrich outreach with verified phone, website, email, and full mailing address.
- **Due diligence & vendor screening** — check accreditation status, complaint history, and time in business before you sign or buy.
- **Trust-signal monitoring** — watch complaint counts and star ratings for your own brand or a competitor set over time.
- **Market research** — size a trade in a region, compare accredited vs. non-accredited, and map category coverage.
- **CRM & workflow automation** — stream every record to Slack, Zapier, Make, or n8n the moment it is saved.

***

### Features (checkbox matrix)

| Checkbox | Default | What it gives you |
| --- | --- | --- |
| **Business Search** | ✅ on | Keyword + location search. One row per business: name, phone, address, category, BBB rating, accreditation, and profile URL. |
| — Enrich with full business profile | off | Keeps the **same** search row (`detailsFetched: true`) and adds website, email, accreditation date, years in business, complaint counts, review counts, and average star rating. Adds a little extra time per business. |
| — Find emails on business websites | on | When a full profile is fetched, also reads the business's website (homepage + contact page) for published email addresses and merges them into the same row. |
| — BBB Accredited businesses only | off | Optional lead filter: save only accredited businesses. |
| **Business Details** | off | Full profile for specific business profile URLs. |
| **Reviews & Complaints** | off | Reputation summary + capped list of latest reviews for the profile URLs. |
| **Scrape By URL** | off | Paste any BBB search, category, or business-profile URL. Auto-detects the page type. |

Every discovered business is always saved — enrichment adds fields to the same row, it never drops or duplicates records.

***

### Input reference

#### 🌍 Market

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `region` | select | `US` | `US` or `CA`. Sets the directory region and the recommended connection country. |

#### 🔍 Business Search

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `enableBusinessSearch` | boolean | `true` | Primary discovery feature. |
| `searchTasks` | array of objects | demo task | Each row: `keyword` + `location` (+ optional `maxResults`). |
| `searchTasks[].keyword` | string | — | Business type, trade, or name, e.g. `"plumbers"`, `"roofing contractors"`, `"auto repair"`. |
| `searchTasks[].location` | string | — | City + state/province or postal code, e.g. `"New York, NY"`, `"90210"`, `"Toronto, ON"`. |
| `searchTasks[].maxResults` | integer | inherits | Max businesses for that task. |
| `searchMaxResults` | integer | `10` | Default max businesses per task (1–200). |
| `searchSort` | select | `relevance` | `relevance`, `distance`, `rating`, `a_to_z`, `z_to_a`. |
| `searchAccreditedOnly` | boolean | `false` | Save only BBB Accredited businesses. |
| `searchFetchFullDetails` | boolean | `false` | Enrich each search row in place. |
| `discoverWebsiteEmails` | boolean | `true` | Look for email addresses on each business's website when a full profile is fetched. |

Example:

```json
{
    "enableBusinessSearch": true,
    "searchTasks": [
        { "keyword": "plumbers", "location": "New York, NY", "maxResults": 10 },
        { "keyword": "roofing contractors", "location": "Los Angeles, CA", "maxResults": 10 }
    ],
    "searchSort": "rating",
    "searchFetchFullDetails": true
}
```

#### 🏢 Business Details

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `enableBusinessDetails` | boolean | `false` | Full profile per URL. |
| `profileUrls` | string array | demo URL | BBB business profile URLs (shared with Reviews & Complaints). |

#### ⭐ Reviews & Complaints

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `enableReviewsComplaints` | boolean | `false` | Reputation summary + latest reviews. |
| `reviewsMaxItems` | integer | `10` | Max latest reviews per business (1–200). |

#### 🔗 Scrape By URL

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `enableScrapeByUrl` | boolean | `false` | Auto-detects search/category vs. business profile URLs. |
| `scrapeUrls` | string array | demo URL | Any BBB URL. |

#### 🔔 Delivery

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `webhookUrl` | string | `""` | Optional additional real-time POST per record. |
| `webhookFormat` | select | `json` | `json` = full record; `slack` = Slack message payload. |

#### 🌐 Connection

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `proxyConfiguration` | proxy | Residential, US | Residential connections give the most reliable results. Match the country to `region`. |

***

### Output field reference

One dataset row per business. Filter by `featureType` (`business_search`, `business_details`, `reviews_complaints`, `scrape_by_url`).

**Identity & contact:** `businessId`, `bbbId`, `bbbName`, `name`, `alternateNames`, `phone`, `phoneNumbers`, `website`, `websites`, `email`, `emails` (directory addresses plus addresses found on the business website), `socials`.

**Location:** `street`, `addressLine2`, `city`, `state`, `postalCode`, `country`, `formattedAddress`, `latitude`, `longitude`.

**Categorization:** `category`, `categories`, `tobId`.

**Trust signals:** `rating` (e.g. `A+`), `accredited`, `accreditationStatus`, `accreditedSince`, `yearsInBusiness`, `outOfBusiness`.

**Reputation:** `reviewsTotal`, `averageRating`, `complaintsTotal`, `complaintsClosedPast3Years`, `complaintsClosedPast12Months`, `latestReviews[]`.

**Profile detail:** `description`, `typeOfEntity`, `bbbFileOpened`, `businessStart`, `incorporated`, `managementContacts`, `logoUrl`.

**Provenance:** `featureType`, `scrapedAt`, `url`, `source`, `searchKeyword`, `searchLocation`, `searchTaskLabel`, `position`, `detailsFetched`.

***

### Webhooks (real-time alerts)

Set `webhookUrl` to also POST every saved record. The dataset write always happens first; the webhook is an additional push and its failures never stop the run.

- `webhookFormat: "json"` — the full record object.
- `webhookFormat: "slack"` — a Slack-ready `{ "text": ... }` message with rating, accreditation, phone, address, website, reviews, and complaints.

Works with Slack, Discord, Zapier, Make, n8n, or your own service.

***

### Use it from AI agents (Apify MCP)

This Actor exposes a structured dataset, so AI agents can call it through the **Apify MCP server** and reason over the results.

Example question to your agent:

> "Use BBB Real Time Data to find the highest-rated accredited plumbers in New York, NY and list their phone, website, and complaint counts."

The agent runs the Actor, waits for the dataset, and answers from the structured rows.

***

### FAQ

**Do I need a proxy?** Residential connections are recommended and enabled by default. They keep results reliable across regions; match the connection country to your `region`.

**What does the free tier include?** A 2-result sample per run on a free Apify plan, with a clear notice. Paid plans are uncapped.

**How fresh is the data?** Every record is collected live during your run and streamed to the dataset as it is gathered — there is no cached snapshot.

**How are results billed?** Pay-per-event: one charge per saved result (event name `result`).

**Does enrichment change my row count?** No. "Enrich with full business profile" adds fields to the same search row (`detailsFetched: true`). One business is always one row.

**Can I get reviews and complaints?** Yes — enable **Reviews & Complaints** for the aggregate complaint counts, complaint history windows, review totals, average star rating, and the latest reviews.

**US and Canada?** Yes. UK is not part of the BBB directory.

# Actor input Schema

## `region` (type: `string`):

BBB directory region. US and Canada are supported.

## `enableBusinessSearch` (type: `boolean`):

Find live businesses by keyword and location. On by default and prefilled so you can click Start and get results in seconds.

## `searchTasks` (type: `array`):

One row per search: pair a keyword (business type, trade, or name) with a location. Leave empty to run the built-in demo task.

## `searchMaxResults` (type: `integer`):

Maximum businesses per search task when a task does not set its own (1–200). Default 10 — perfect for instant demo runs.

## `searchSort` (type: `string`):

How to order search results. Best match is ideal for discovery; Rating surfaces the strongest trust signals first.

## `searchAccreditedOnly` (type: `boolean`):

When on, only businesses that are BBB Accredited are saved. Off by default — every discovered business is saved otherwise.

## `searchFetchFullDetails` (type: `boolean`):

When on, each search result stays ONE row but is enriched with the full profile: website, email, address, accreditation date, years in business, complaint counts, review counts, and star rating. Adds a little extra time per business. When off, you get fast search cards with name, phone, address, rating, accreditation, and category. Every discovered business is always saved — never filtered out.

## `discoverWebsiteEmails` (type: `boolean`):

When a full profile is fetched and the business has a website, also look for email addresses on that website (homepage and contact page). Found addresses are merged into the same business row. Adds a moment per business.

## `enableBusinessDetails` (type: `boolean`):

Collect the full record for specific businesses by profile URL.

## `profileUrls` (type: `array`):

BBB business profile URLs. Shared by Business Details and Reviews & Complaints.

## `enableReviewsComplaints` (type: `boolean`):

Collect the reputation summary for the profile URLs above: total complaints, complaints closed in the last 3 years and 12 months, total reviews, average star rating, and the latest reviews.

## `reviewsMaxItems` (type: `integer`):

Maximum latest reviews to include per business (1–200). Default 10.

## `enableScrapeByUrl` (type: `boolean`):

Paste any BBB URL — a search results page, a category page, or a single business profile.

## `scrapeUrls` (type: `array`):

Any BBB search, category, or business profile URL.

## `webhookUrl` (type: `string`):

Optional. Every record is always saved to the run dataset — this webhook is an ADDITIONAL real-time push. Each new row is also POSTed to this URL (Slack, Discord, Zapier, Make, n8n, custom outreach bot).

## `webhookFormat` (type: `string`):

json = full record object; slack = Slack-friendly message payload.

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

Residential proxy recommended. Match the country to the Market region above (US by default).

## Actor input object example

```json
{
  "region": "US",
  "enableBusinessSearch": true,
  "searchTasks": [
    {
      "keyword": "plumbers",
      "location": "New York, NY",
      "maxResults": 10
    },
    {
      "keyword": "roofing contractors",
      "location": "Los Angeles, CA",
      "maxResults": 10
    }
  ],
  "searchMaxResults": 10,
  "searchSort": "relevance",
  "searchAccreditedOnly": false,
  "searchFetchFullDetails": false,
  "discoverWebsiteEmails": true,
  "enableBusinessDetails": false,
  "profileUrls": [
    "https://www.bbb.org/us/ny/new-york/profile/plumber/daniels-plumbing-services-0121-87144493"
  ],
  "enableReviewsComplaints": false,
  "reviewsMaxItems": 10,
  "enableScrapeByUrl": false,
  "scrapeUrls": [
    "https://www.bbb.org/search?find_country=USA&find_loc=New+York%2C+NY&find_text=plumbers"
  ],
  "webhookUrl": "",
  "webhookFormat": "json",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `allResults` (type: `string`):

Full dataset for this run (every featureType).

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

Core fields across features, including rating, accreditation, complaints and detailsFetched.

## `search` (type: `string`):

featureType=business_search only. One business = one row; the full profile is merged when "Enrich with full business profile" is enabled.

## `details` (type: `string`):

featureType=business_details — full profiles from the Business Details feature.

## `reviews_complaints` (type: `string`):

featureType=reviews_complaints — reputation summary and latest reviews.

## `scrape_by_url` (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 = {
    "region": "US",
    "enableBusinessSearch": true,
    "searchTasks": [
        {
            "keyword": "plumbers",
            "location": "New York, NY",
            "maxResults": 10
        },
        {
            "keyword": "roofing contractors",
            "location": "Los Angeles, CA",
            "maxResults": 10
        }
    ],
    "searchMaxResults": 10,
    "searchSort": "relevance",
    "searchAccreditedOnly": false,
    "searchFetchFullDetails": false,
    "discoverWebsiteEmails": true,
    "enableBusinessDetails": false,
    "profileUrls": [
        "https://www.bbb.org/us/ny/new-york/profile/plumber/daniels-plumbing-services-0121-87144493"
    ],
    "enableReviewsComplaints": false,
    "reviewsMaxItems": 10,
    "enableScrapeByUrl": false,
    "scrapeUrls": [
        "https://www.bbb.org/search?find_country=USA&find_loc=New+York%2C+NY&find_text=plumbers"
    ],
    "webhookFormat": "json",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("b2b_leads/bbb-real-time-data-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 = {
    "region": "US",
    "enableBusinessSearch": True,
    "searchTasks": [
        {
            "keyword": "plumbers",
            "location": "New York, NY",
            "maxResults": 10,
        },
        {
            "keyword": "roofing contractors",
            "location": "Los Angeles, CA",
            "maxResults": 10,
        },
    ],
    "searchMaxResults": 10,
    "searchSort": "relevance",
    "searchAccreditedOnly": False,
    "searchFetchFullDetails": False,
    "discoverWebsiteEmails": True,
    "enableBusinessDetails": False,
    "profileUrls": ["https://www.bbb.org/us/ny/new-york/profile/plumber/daniels-plumbing-services-0121-87144493"],
    "enableReviewsComplaints": False,
    "reviewsMaxItems": 10,
    "enableScrapeByUrl": False,
    "scrapeUrls": ["https://www.bbb.org/search?find_country=USA&find_loc=New+York%2C+NY&find_text=plumbers"],
    "webhookFormat": "json",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("b2b_leads/bbb-real-time-data-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 '{
  "region": "US",
  "enableBusinessSearch": true,
  "searchTasks": [
    {
      "keyword": "plumbers",
      "location": "New York, NY",
      "maxResults": 10
    },
    {
      "keyword": "roofing contractors",
      "location": "Los Angeles, CA",
      "maxResults": 10
    }
  ],
  "searchMaxResults": 10,
  "searchSort": "relevance",
  "searchAccreditedOnly": false,
  "searchFetchFullDetails": false,
  "discoverWebsiteEmails": true,
  "enableBusinessDetails": false,
  "profileUrls": [
    "https://www.bbb.org/us/ny/new-york/profile/plumber/daniels-plumbing-services-0121-87144493"
  ],
  "enableReviewsComplaints": false,
  "reviewsMaxItems": 10,
  "enableScrapeByUrl": false,
  "scrapeUrls": [
    "https://www.bbb.org/search?find_country=USA&find_loc=New+York%2C+NY&find_text=plumbers"
  ],
  "webhookFormat": "json",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call b2b_leads/bbb-real-time-data-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,b2b_leads/bbb-real-time-data-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/9XDXoh2CKCS4na2eF/builds/MTYjOD88SlQeq03UW/openapi.json
