# BBB Scraper (`haketa/bbb-scraper`) Actor

Better Business Bureau (BBB) scraper & API: export US & Canada company profiles, BBB ratings & accreditation status, customer reviews & complaints, phone, address, website, category and years in business. B2B lead generation, due diligence and business reputation data — fast, no login.

- **URL**: https://apify.com/haketa/bbb-scraper.md
- **Developed by:** [Haketa](https://apify.com/haketa) (community)
- **Categories:** Developer tools, Lead generation, Automation
- **Features:** Limited permissions
- **Stats:** 150 total users, 13 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## BBB Scraper 🏛️ — Better Business Bureau Profiles, Ratings, Complaints & Accreditation (US + Canada)

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-blue?logo=apify)](https://apify.com/haketa/bbb-scraper)
[![Coverage](https://img.shields.io/badge/Coverage-USA%20%2B%20Canada-purple)]()
[![Scale](https://img.shields.io/badge/Scale-1%2C000%2B%20Businesses-orange)]()
[![Data Freshness](https://img.shields.io/badge/Data-Live%20Extraction-success)]()
[![No Login](https://img.shields.io/badge/Auth-No%20Login%20Required-brightgreen)]()
[![Export](https://img.shields.io/badge/Export-JSON%20%7C%20CSV%20%7C%20Excel%20%7C%20API-blue)]()

**Extract full business profiles from the [Better Business Bureau (BBB.org)](https://www.bbb.org) across the United States and Canada.** This **BBB scraper** and **BBB.org data extractor** turns any business category, company name, city, state, or ZIP code into a clean, structured dataset of companies — complete with **BBB letter-grade ratings (`A+` through `F`), accreditation status & start date, complaint counts, customer review scores, owner/principal names, phone numbers, websites, categories, and firmographics.**

Export your results in bulk to **JSON, CSV, Excel, XML, or via the Apify API** for **B2B lead generation, contractor & vendor vetting, KYB / business-credit risk analysis, M\&A roll-up sourcing, and reputation monitoring**.

> 💡 **Built for:** B2B sales and outbound teams, KYB / credit-risk analysts, contractor & procurement vetting teams, M\&A due-diligence and home-services roll-up operators, reputation-management agencies, and market researchers who need verified BBB trust signals at scale.

***

### ⚡ At a glance

| Feature | Details |
|---|---|
| **Target directory** | [BBB.org](https://www.bbb.org) — 5M+ accredited and non-accredited businesses across the **United States (`USA`)** and **Canada (`CAN`)** |
| **Search & discovery** | Search by `keyword` + `location` (city, state/province, or ZIP/postal code), custom `searchUrls`, or built-in multi-metro discovery |
| **Sorting & filtering** | Sort by `Relevance`, `Rating` (highest BBB grade first), `Distance`, or `Name`; optional `accreditedOnly: true` filter |
| **Fast search-card mode** | Extracts `businessName`, `profileUrl`, `bbbId`, `bbbRating`, `phone`, `categories`, `city`, `state`, `zipCode` directly from result pages |
| **Deep profile enrichment** | Optional `scrapeDetails: true` adds `isAccredited`, `accreditationSince`, `ownerName`, `website`, `email`, `complaintsTotal`, `complaintsLast3Yrs`, `complaintsLast12Mo`, `reviewCount`, `averageReviewRating`, `yearsInBusiness`, `businessStartDate`, `businessType`, `numberOfEmployees`, `licenseNumbers`, `socialMedia`, and `description` |
| **Pagination & 1,000+ scale** | Automatic page traversal (`maxPages: 0` auto mode) + automatic multi-metro expansion to collect **1,000+ unique businesses** per run (`0` duplicates) |
| **Ad & noise removal** | Automatically strips sponsored ad links and collapses sub-pages (`/complaints`, `/customer-reviews`, `/details`) to one canonical profile |
| **Authentication** | None required — 100% public directory extraction with no login or API keys |
| **Export & integrations** | JSON, CSV, Excel (XLSX), XML, HTML, RSS, Apify API, Google Sheets, Make, Zapier, n8n, HubSpot, Clay & webhooks |

***

### 📋 Table of contents

- [Why scrape BBB.org?](#-why-scrape-bbborg)
- [What this BBB scraper does](#-what-this-bbb-scraper-does)
- [High-value use cases](#-high-value-use-cases)
- [Input configuration](#-input-configuration)
- [Output dataset & examples](#-output-dataset--examples)
- [Field reference & coverage](#-field-reference--coverage)
- [Pagination & 1,000+ business scaling](#-pagination--1000-business-scaling)
- [How to use step by step](#️-how-to-use-step-by-step)
- [API & automation integration](#-api--automation-integration)
- [Pro tips for best results](#-pro-tips-for-best-results)
- [Frequently asked questions](#-frequently-asked-questions)
- [Limitations](#-limitations)
- [Related scrapers](#-related-scrapers)
- [Changelog](#-changelog)

***

### 🔎 Why scrape BBB.org?

The **Better Business Bureau (BBB)** is the largest business trust and reputation directory in North America, profiling more than **5 million companies across the United States and Canada**. For local and regional B2B and consumer-facing industries — roofing contractors, HVAC installers, plumbers, electricians, solar companies, moving companies, auto repair shops, home builders, property managers, and financial services — a BBB profile is a primary trust benchmark.

What makes **BBB data** uniquely valuable is that it combines **hard firmographics** (company name, address, phone, website, owner/principal, entity type, start date, years in business, state licenses) with **verified reputation and risk metrics** (`A+` to `F` letter rating, accreditation status, 12-month and 3-year closed complaint counts, and customer star ratings) that general map scrapers do not carry.

Collecting that data manually across dozens of cities and pages is slow and repetitive. This **BBB scraper** automates search, pagination, ad filtering, and optional profile enrichment so you can export hundreds or thousands of clean, deduplicated business records in a single run.

**Common reasons teams scrape BBB:**

- 🎯 **High-trust B2B lead generation** — build outbound lists of established local-service companies filtered by BBB rating (`A+` / `A`) and accreditation status.
- 🛡️ **KYB & commercial underwriting** — enrich merchant onboarding and credit checks with BBB letter grades, `complaintsLast12Mo`, `yearsInBusiness`, and `ownerName`.
- 🤝 **M\&A roll-up & private equity sourcing** — screen home-services, construction, and specialty trade acquisition targets by longevity (`yearsInBusiness >= 10`), clean complaint records, and principal contact names.
- 👷 **Contractor & vendor panel vetting** — verify that third-party contractors hold an acceptable BBB rating and active accreditation before awarding work.
- 📉 **Brand & franchise reputation monitoring** — track rating changes, complaint spikes, and review scores across multi-location franchises on a weekly schedule.
- 📊 **Local-services market sizing (TAM)** — count and map active, rated businesses across US and Canadian metropolitan areas by category.

***

### ✨ What this BBB scraper does

- ✅ **Flexible search modes** — search by `keyword` + `location` + `country` (`USA` or `CAN`), paste custom **BBB search URLs** in `searchUrls`, or run with empty search inputs to collect a diverse multi-category sample.
- ✅ **Rich listing extraction (fast mode)** — even with `scrapeDetails: false`, every record includes **`businessName`, `profileUrl`, `bbbId`, `bbbRating` (`A+`–`F`), `phone`, `categories`, `city`, `state`, and `zipCode`**.
- ✅ **Deep profile enrichment (`scrapeDetails: true`)** — visits each company's BBB profile to extract **`isAccredited`, `accreditationSince`, `ownerName`, `website`, `email`, `address`, `complaintsTotal`, `complaintsLast3Yrs`, `complaintsLast12Mo`, `reviewCount`, `averageReviewRating`, `yearsInBusiness`, `businessStartDate`, `businessType`, `numberOfEmployees`, `licenseNumbers`, `serviceAreas`, `socialMedia`, and `description`**.
- ✅ **Automatic pagination & 1,000+ scaling** — walks all available search result pages (`maxPages: 0` automatic mode) and, when `maxResults > 200`, automatically expands across major metropolitan areas so single-keyword runs can reach **1,000+ unique businesses**.
- ✅ **Sponsored ad & sub-page filtering** — drops paid advertisement links and normalizes `/details`, `/accreditation`, `/customer-reviews`, and `/complaints` links to a single canonical profile URL.
- ✅ **Verified business-only social links** — extracts the company's own Facebook, LinkedIn, Twitter/X, and Instagram profiles while filtering out BBB's site-wide social links.
- ✅ **United States & Canada coverage** — switch `country` between `USA` and `CAN` to search any US state/ZIP or Canadian province/postal code.

***

### 🎯 High-value use cases

#### 1. Outbound B2B sales to home-services & trade businesses

Agencies, SaaS platforms, fleet providers, insurance brokers, and material suppliers target local contractors (`roofing contractor`, `HVAC`, `plumber`, `electrician`, `landscaping`, `pest control`, `solar energy`). Sort by `Rating` or enable `accreditedOnly: true` to focus exclusively on established, creditworthy operators who invest in their business reputation.

#### 2. M\&A deal sourcing & founder outreach

Private equity roll-ups and search funds in home and commercial services use `scrapeDetails: true` to identify businesses with **10–30+ `yearsInBusiness`**, **`A+` BBB ratings**, **zero recent complaints (`complaintsLast12Mo: 0`)**, and the **owner/principal's full name (`ownerName`)** for direct off-market acquisition outreach.

#### 3. KYB, merchant risk & compliance screening

Fintechs, payment processors, and B2B lenders enrich merchant applications with BBB trust signals — automatically flagging applicants with `D` or `F` ratings or elevated `complaintsLast12Mo` counts before onboarding.

#### 4. Multi-location reputation & compliance monitoring

Franchise networks and multi-state operators schedule recurring runs with their brand keyword or `searchUrls` to monitor `bbbRating`, `complaintsLast12Mo`, and `averageReviewRating` across every branch location.

***

### 📥 Input configuration

All fields are optional. Running with no `keyword` and no `searchUrls` automatically collects a diverse sample across popular trade categories and major US metros.

| Parameter | Type | Default / Prefill | Description |
|---|---|---|---|
| `keyword` | `string` | Prefill: `"roofing contractor"` | Business category, trade, or company name (e.g. `"plumber"`, `"HVAC"`, `"auto repair"`, `"moving company"`). Leave empty for a multi-category sample. |
| `location` | `string` | Prefill: `"Dallas, TX"` | City + state/province, state alone, or ZIP/postal code (e.g. `"Houston, TX"`, `"Texas"`, `"75201"`, `"Toronto, ON"`). |
| `country` | `string` | `"USA"` | Target country: `"USA"` (United States) or `"CAN"` (Canada). |
| `sort` | `string` | `"Relevance"` | Result order: `"Relevance"`, `"Rating"` (highest BBB rating first), `"Distance"`, or `"Name"`. |
| `accreditedOnly` | `boolean` | `false` | When `true`, keeps only BBB-accredited businesses and skips non-accredited listings. |
| `scrapeDetails` | `boolean` | `false` | When `true`, visits each business profile page to extract owner name, complaints, reviews, website, years in business, entity type, licenses, and social media. |
| `maxResults` | `integer` | Default `0` (Prefill `45`) | Maximum businesses to collect (`0` = unlimited). Supports **1,000+ businesses** per run. |
| `maxPages` | `integer` | `0` (auto) | Max search pages per query (`0` = automatic, paginates until `maxResults` is reached). |
| `searchUrls` | `array<string>` | `[]` | Advanced: paste one or more ready-made BBB search URLs to scrape directly. |
| `proxyConfiguration` | `object` | `{ "useApifyProxy": false }` | Optional proxy settings. Works out of the box without proxy; enable Apify Proxy if running very large jobs. |
| `requestDelay` | `integer` | `500` (`0`–`15000` ms) | Pause between page requests in milliseconds. |
| `maxConcurrency` | `integer` | `2` (`1`–`2`) | Parallel detail-profile workers when `scrapeDetails: true`. |

#### Input example 1 — Fast listing discovery (1,000+ businesses)

```json
{
  "keyword": "roofing contractor",
  "location": "Dallas, TX",
  "country": "USA",
  "sort": "Rating",
  "accreditedOnly": false,
  "scrapeDetails": false,
  "maxResults": 1000,
  "maxPages": 0
}
```

#### Input example 2 — Full profile enrichment (owner, complaints, reviews & website)

```json
{
  "keyword": "HVAC",
  "location": "Chicago, IL",
  "country": "USA",
  "sort": "Rating",
  "accreditedOnly": true,
  "scrapeDetails": true,
  "maxResults": 100,
  "maxPages": 0
}
```

#### Input example 3 — Custom multi-city search URLs

```json
{
  "searchUrls": [
    "https://www.bbb.org/search?find_country=USA&find_loc=Houston%2C%20TX&find_text=plumber",
    "https://www.bbb.org/search?find_country=USA&find_loc=Austin%2C%20TX&find_text=plumber",
    "https://www.bbb.org/search?find_country=USA&find_loc=San%20Antonio%2C%20TX&find_text=plumber"
  ],
  "scrapeDetails": false,
  "maxResults": 500
}
```

***

### 📤 Output dataset & examples

Every dataset item uses a **consistent, flat JSON schema** so listing-only runs (`scrapeDetails: false`) and deep-profile runs (`scrapeDetails: true`) share the exact same columns for seamless CSV/Excel export and database ingestion.

#### Sample record — Fast listing mode (`scrapeDetails: false`)

```json
{
  "businessName": "Home Integrity Solutions LLC",
  "profileUrl": "https://www.bbb.org/us/tx/dallas/profile/roofing-contractors/home-integrity-solutions-llc-0875-91349575",
  "bbbId": "91349575",
  "bbbRating": "A",
  "isAccredited": null,
  "accreditationSince": null,
  "address": "4516 Lovers Ln",
  "city": "Dallas",
  "state": "TX",
  "zipCode": "75225",
  "phone": "(214) 498-6458",
  "email": null,
  "website": null,
  "categories": ["Roofing Contractors", "Home Renovation", "Roof Inspection", "Roof Replacement"],
  "serviceAreas": null,
  "yearsInBusiness": null,
  "businessStartDate": null,
  "businessType": null,
  "numberOfEmployees": null,
  "ownerName": null,
  "licenseNumbers": null,
  "complaintsTotal": null,
  "complaintsLast3Yrs": null,
  "complaintsLast12Mo": null,
  "complaintsResolved": null,
  "reviewCount": null,
  "averageReviewRating": null,
  "socialMedia": null,
  "governmentActions": null,
  "description": null,
  "searchKeyword": "roofing contractor",
  "searchLocation": "Dallas, TX",
  "scrapedAt": "2026-11-10T02:00:00.000Z"
}
```

#### Sample record — Deep profile mode (`scrapeDetails: true`)

```json
{
  "businessName": "Ecotech Roofing and Construction",
  "profileUrl": "https://www.bbb.org/us/tx/dallas/profile/roofing-contractors/ecotech-roofing-and-construction-0875-90228991",
  "bbbId": "90228991",
  "bbbRating": "A+",
  "isAccredited": true,
  "accreditationSince": "8/10/2009",
  "address": "3130 Harvard Ave Ste B",
  "city": "Dallas",
  "state": "TX",
  "zipCode": "75219-5305",
  "phone": "(972) 922-3606",
  "email": null,
  "website": "https://ecotechroofing.example",
  "categories": ["Roofing Contractors", "Gutters", "Commercial Roofing", "Replacement Windows", "Storm Damage Repair", "Residential Roofing"],
  "serviceAreas": null,
  "yearsInBusiness": 17,
  "businessStartDate": "2/23/2009",
  "businessType": "Limited Liability Company (LLC)",
  "numberOfEmployees": "25",
  "ownerName": "Mr. Robert Burnley",
  "licenseNumbers": null,
  "complaintsTotal": 0,
  "complaintsLast3Yrs": 0,
  "complaintsLast12Mo": 0,
  "complaintsResolved": null,
  "reviewCount": 19,
  "averageReviewRating": 4.95,
  "socialMedia": {
    "facebook": "https://www.facebook.com/ecotechroofing",
    "instagram": "https://www.instagram.com/ecotechroofing/"
  },
  "governmentActions": null,
  "description": "Full-service residential and commercial roofing contractor serving the Dallas–Fort Worth metroplex.",
  "searchKeyword": "roofing contractor",
  "searchLocation": "Dallas, TX",
  "scrapedAt": "2026-11-10T02:00:05.000Z"
}
```

***

### 📊 Field reference & coverage

#### 🏢 Core Identity, Location & Contact

| Field | Type | Listing Mode | Detail Mode (`scrapeDetails`) | Description |
|---|---|---|---|---|
| `businessName` | `string` | 🟢 High (100%) | 🟢 High (100%) | Official business or DBA name on BBB. |
| `profileUrl` | `string` | 🟢 High (100%) | 🟢 High (100%) | Canonical BBB profile URL (unique primary key). |
| `bbbId` | `string` | 🟢 High (100%) | 🟢 High (100%) | Stable numeric BBB business ID. |
| `phone` | `string \| null` | 🟢 High (~98%) | 🟢 High (~99%) | Primary business telephone number. |
| `address` | `string \| null` | 🟢 High (~85%) | 🟢 High (~98%) | Street address when published by the business. |
| `city` | `string` | 🟢 High (100%) | 🟢 High (100%) | City name. |
| `state` | `string` | 🟢 High (100%) | 🟢 High (100%) | Two-letter US state or Canadian province code. |
| `zipCode` | `string \| null` | 🟢 High (~99%) | 🟢 High (100%) | US ZIP code or Canadian postal code. |
| `categories` | `array<string>` | 🟢 High (100%) | 🟢 High (100%) | Business categories assigned by BBB. |
| `website` | `string \| null` | ⚪ Detail only | 🟢 High (~75%) | Direct company website URL (present when listed). |
| `email` | `string \| null` | ⚪ Detail only | 🟡 Conditional | Contact email address when publicly exposed on the profile. |
| `socialMedia` | `object \| null` | ⚪ Detail only | 🟡 Conditional | `{ facebook, linkedin, twitter, instagram }` links for the business. |

#### ⭐ Trust, Ratings, Complaints & Reviews

| Field | Type | Listing Mode | Detail Mode (`scrapeDetails`) | Description |
|---|---|---|---|---|
| `bbbRating` | `string \| null` | 🟢 High (~99%) | 🟢 High (100%) | Letter grade (`A+`, `A`, `A-`, `B+`, `B`, `B-`, `C+`, `C`, `C-`, `D+`, `D`, `D-`, `F`, or `NR`). |
| `isAccredited` | `boolean \| null` | 🟡 Partial | 🟢 High (100%) | Whether the company is an official BBB Accredited Business. |
| `accreditationSince` | `string \| null` | ⚪ Detail only | 🟢 High (Accredited) | Accreditation start date (`M/D/YYYY`). |
| `complaintsTotal` | `integer \| null` | ⚪ Detail only | 🟢 High (100%) | Total closed complaints on file. |
| `complaintsLast3Yrs` | `integer \| null` | ⚪ Detail only | 🟢 High (100%) | Closed complaints in the past 3 years. |
| `complaintsLast12Mo` | `integer \| null` | ⚪ Detail only | 🟢 High (100%) | Closed complaints in the past 12 months. |
| `reviewCount` | `integer \| null` | ⚪ Detail only | 🟢 High (100%) | Total customer reviews published on the profile. |
| `averageReviewRating` | `number \| null` | ⚪ Detail only | 🟡 Conditional | Average customer star rating (`1.0`–`5.0`, when reviews exist). |

#### 📋 Firmographics, Ownership & Metadata

| Field | Type | Listing Mode | Detail Mode (`scrapeDetails`) | Description |
|---|---|---|---|---|
| `ownerName` | `string \| null` | ⚪ Detail only | 🟢 High (~92%) | Principal, owner, or primary management contact name. |
| `yearsInBusiness` | `integer \| null` | ⚪ Detail only | 🟢 High (~95%) | Number of years operating. |
| `businessStartDate` | `string \| null` | ⚪ Detail only | 🟢 High (~95%) | Business start date (`M/D/YYYY`). |
| `businessType` | `string \| null` | ⚪ Detail only | 🟢 High (~90%) | Entity structure (e.g. `Limited Liability Company (LLC)`, `Corporation`). |
| `numberOfEmployees` | `string \| null` | ⚪ Detail only | 🟡 Conditional | Reported employee count when disclosed. |
| `licenseNumbers` | `array<string> \| null` | ⚪ Detail only | 🟡 Conditional | State/trade license numbers when listed on the BBB profile. |
| `serviceAreas` | `array<string> \| null` | ⚪ Detail only | 🟡 Conditional | Cities or counties served when listed. |
| `description` | `string \| null` | ⚪ Detail only | 🟡 Conditional | Business overview / about text. |
| `searchKeyword` / `searchLocation` | `string` | 🟢 High (100%) | 🟢 High (100%) | Search query and location that returned the record. |
| `scrapedAt` | `string` | 🟢 High (100%) | 🟢 High (100%) | ISO-8601 extraction timestamp. |

***

### 🔁 Pagination & 1,000+ business scaling

BBB search pages display roughly **15 organic businesses per page**, and BBB's search engine caps any single `(keyword, location)` query at **15 pages (~225 businesses)**. This Actor overcomes that ceiling automatically:

1. **Unbounded automatic page walking (`maxPages: 0`):** By default, `maxPages` is set to `0` (automatic), so the scraper walks every available page for each search until `maxResults` is reached or no further pages exist.
2. **Automatic multi-metro expansion for 1,000+ runs:** When you search by `keyword` and set `maxResults > 200` (e.g. `maxResults: 1000`) with `maxPages: 0`, once your primary location's 15 pages are collected, the scraper automatically expands your `keyword` across major US or Canadian metropolitan areas to deliver **1,000+ unique businesses** in a single run.
3. **Custom multi-URL batching (`searchUrls`):** Want exact control over which cities or states are combined? Pass an array of BBB search URLs in `searchUrls` and set `maxResults: 0` — the scraper walks every page of every URL and merges them.
4. **Global canonical URL deduplication:** Every business is deduplicated by its normalized `profileUrl` across all pages and all searches (`0%` duplicate rate).

***

### ⚙️ How to use step by step

1. Open **[BBB Scraper](https://apify.com/haketa/bbb-scraper)** in the Apify Console and click **Try for free**.
2. Enter a **What to search for** (`keyword`, e.g. `"roofing contractor"`) and **Where to search** (`location`, e.g. `"Dallas, TX"`), or leave both empty for a diverse sample.
3. Choose **Country** (`USA` or `CAN`), **Sort results by**, and whether to keep **BBB-accredited businesses only**.
4. Leave **Get full profile details** (`scrapeDetails`) off for fast listing extraction, or turn it on to collect owner names, websites, complaint counts, and firmographics.
5. Set **Maximum businesses** (`maxResults`) — e.g. `45` for a quick test, `500` or `1000` for a large lead list, or `0` for no limit.
6. Click **Start**, then export your dataset as **JSON, CSV, Excel, XML, or HTML** from the **Dataset** tab.

***

### 🔌 API & automation integration

#### Python example

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run = client.actor("haketa/bbb-scraper").call(run_input={
    "keyword": "roofing contractor",
    "location": "Dallas, TX",
    "country": "USA",
    "sort": "Rating",
    "scrapeDetails": True,
    "maxResults": 200,
    "maxPages": 0,
})

for biz in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(biz["bbbRating"], biz["businessName"], biz["phone"], biz["ownerName"], biz["website"])
```

#### Node.js example

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const run = await client.actor('haketa/bbb-scraper').call({
    keyword: 'plumber',
    location: 'Los Angeles, CA',
    country: 'USA',
    scrapeDetails: false,
    maxResults: 500,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Collected ${items.length} BBB business profiles.`);
```

***

### 💡 Pro tips for best results

- ⚡ **Use two-stage workflows for large TAMs:** Run with `scrapeDetails: false` first to rapidly collect 1,000+ businesses with `businessName`, `bbbRating`, `phone`, `categories`, and `city/state/zipCode`. Then enrich your top-tier subset with `scrapeDetails: true`.
- 🏆 **Combine `sort: "Rating"` + `accreditedOnly: true`** when building high-conversion B2B sales lists — accredited `A+` businesses answer phones and invest in vendor partnerships.
- 🔑 **Upsert on `bbbId` or `profileUrl`** when syncing to Postgres, Snowflake, BigQuery, HubSpot, or Clay so weekly scheduled runs cleanly track rating or complaint changes.
- 🇨🇦 **Targeting Canada:** Set `country: "CAN"` and pass a Canadian city/province or postal code (e.g. `"Toronto, ON"`, `"Vancouver, BC"`, `"Calgary, AB"`).

***

### ❓ Frequently asked questions

**Do I need a BBB account or API key?**
No. This Actor extracts public business directory data directly with no login, no cookies, and no API key.

**How many businesses can I extract in one run?**
You can extract anywhere from a quick 45-item sample to **1,000+ unique businesses** in a single run. With `maxPages: 0` (the default), the scraper automatically walks all pages and expands across metros when `maxResults > 200`.

**What is the difference between listing mode (`scrapeDetails: false`) and detail mode (`scrapeDetails: true`)?**
Listing mode extracts each search result card (`businessName`, `profileUrl`, `bbbId`, `bbbRating`, `phone`, `categories`, `address`, `city`, `state`, `zipCode`) at ~15 businesses per page load. Detail mode additionally opens each company's profile page to capture `isAccredited`, `accreditationSince`, `ownerName`, `website`, `complaintsTotal/3Yrs/12Mo`, `reviewCount`, `averageReviewRating`, `yearsInBusiness`, `businessStartDate`, `businessType`, `licenseNumbers`, and `socialMedia`.

**Does it work for both US and Canadian businesses?**
Yes — select `"USA"` or `"CAN"` in the `country` dropdown.

**Why are `website`, `email`, or `licenseNumbers` null on some detail records?**
Not every business discloses a website, public email, or state license number to the BBB. Fields that are not displayed on a company's BBB profile are returned as `null` so the dataset schema stays uniform.

***

### ⚠️ Limitations

- BBB caps any single `(keyword, location)` search query at ~15 pages (~225 businesses); to reach 1,000+ businesses, keep `maxPages: 0` (which automatically expands across metros) or supply multiple `searchUrls`.
- Detail mode (`scrapeDetails: true`) opens an individual page per business and is naturally slower than listing-only mode.
- Full narrative text of individual customer reviews and complaint threads lives on separate sub-pages; this Actor extracts the summary complaint and review counts and average star score.

***

### 🔗 Related scrapers

Combine BBB reputation data with these complementary B2B and licensing scrapers:

- [Dun & Bradstreet Scraper — Companies, DUNS & Revenue](https://apify.com/haketa/dnb-scraper) — enrich businesses with DUNS numbers, revenue, and key principals.
- [SBA Small Business Search Scraper](https://apify.com/haketa/sba-small-business-scraper) — US small businesses and federal contractors with NAICS codes and contacts.
- [Arizona ROC Contractor License Scraper](https://apify.com/haketa/az-roc-contractor-license-scraper) — official Arizona Registrar of Contractors license verification.
- [Washington L\&I Contractor License Scraper](https://apify.com/haketa/washington-li-contractor-license-scraper) — Washington state contractor registry data.
- [YCombinator Companies Scraper](https://apify.com/haketa/ycombinator-companies-scraper) — complete Y Combinator startup directory.

***

### 📋 Changelog

#### v1.2 (2026-11)

- **Unlocked 1,000+ deep pagination & multi-metro scaling:** Changed `maxPages` default to `0` (auto/unlimited governed by `maxResults`), removed the `maxPages` empty-run bottleneck when `maxResults > 100`, and added automatic US/Canada metro expansion when `maxResults > 200` so single-keyword runs can collect 1,000+ unique businesses.
- **Fast prefill configuration:** Set `maxResults` prefill to `45` (3 pages) for rapid `< 60s` test runs out of the box.
- **Memory ceiling & status handling:** Updated `maxMemoryMbytes` to `4096` for smooth browser execution and guaranteed final status message persistence before exit.

#### v1.1 (2026-11)

- Upgraded structured state extraction on search and profile pages, restoring ~100% `bbbRating` coverage on search cards and full firmographic/complaint enrichment on detail pages.

#### v1.0 (2026-07)

- Initial release with US & Canada search, pagination, ad filtering, and optional full profile enrichment.

# Changelog

This Actor's version history is a separate document: https://apify.com/haketa/bbb-scraper/changelog.md

# Actor input Schema

## `keyword` (type: `string`):

Type a business type or company name — for example 'roofing contractor', 'HVAC', 'plumber', 'auto repair' or a specific business name. Leave empty to get a diverse sample of popular businesses.

## `location` (type: `string`):

Narrow results to a place: a city and state, a state, or a ZIP code — for example 'Dallas, TX', 'Texas', '75201' or 'Los Angeles, CA'. Leave empty to search everywhere.

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

Choose the country to search in.

## `sort` (type: `string`):

Choose the order of the search results.

## `accreditedOnly` (type: `boolean`):

Turn on to keep only businesses that are BBB-accredited and skip everyone else.

## `scrapeDetails` (type: `boolean`):

Turn on to also open each business profile and collect complaint counts, customer review scores, owner info, social media and full contact details. This makes runs richer but slower.

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

The most businesses to collect in one run. Set 0 for no limit.

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

How many result pages to walk through for each search (0 = automatic, paginates until Maximum businesses is reached). Each page holds about 15 businesses.

## `searchUrls` (type: `array`):

Advanced: paste ready-made BBB search page links here to run them exactly as-is. When provided, the search box and location above are ignored. Most users can leave this empty.

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

Optional proxy settings. Start without a proxy; enable one only if BBB blocks your run. The Actor automatically blocks heavy image, media and font traffic.

## `requestDelay` (type: `integer`):

Pause between requests, in milliseconds. A higher delay is gentler and more reliable.

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

How many detail profiles to process in parallel. Two is the fastest safe setting for the default 1 GB memory.

## Actor input object example

```json
{
  "keyword": "roofing contractor",
  "location": "Dallas, TX",
  "country": "USA",
  "sort": "Relevance",
  "accreditedOnly": false,
  "scrapeDetails": false,
  "maxResults": 45,
  "maxPages": 0,
  "searchUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "requestDelay": 500,
  "maxConcurrency": 2
}
```

# Actor output Schema

## `businessName` (type: `string`):

Company name

## `profileUrl` (type: `string`):

BBB profile page URL

## `bbbId` (type: `string`):

BBB business identifier

## `bbbRating` (type: `string`):

A+ through F rating

## `isAccredited` (type: `string`):

BBB accreditation status

## `accreditationSince` (type: `string`):

Accreditation start date

## `address` (type: `string`):

Street address

## `city` (type: `string`):

City

## `state` (type: `string`):

State/province

## `zipCode` (type: `string`):

ZIP/postal code

## `phone` (type: `string`):

Business phone number

## `email` (type: `string`):

Contact email

## `website` (type: `string`):

Business website URL

## `categories` (type: `string`):

Business categories

## `yearsInBusiness` (type: `string`):

Years operating

## `businessType` (type: `string`):

LLC, Corporation, etc.

## `ownerName` (type: `string`):

Owner/principal name

## `complaintsTotal` (type: `string`):

All-time complaint count

## `complaintsLast3Yrs` (type: `string`):

Complaints in last 3 years

## `reviewCount` (type: `string`):

Customer review count

## `averageReviewRating` (type: `string`):

Average customer review (1-5)

## `scrapedAt` (type: `string`):

ISO timestamp

# 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 = {
    "keyword": "roofing contractor",
    "location": "Dallas, TX",
    "scrapeDetails": false,
    "maxResults": 45,
    "searchUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": false
    },
    "requestDelay": 500,
    "maxConcurrency": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("haketa/bbb-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 = {
    "keyword": "roofing contractor",
    "location": "Dallas, TX",
    "scrapeDetails": False,
    "maxResults": 45,
    "searchUrls": [],
    "proxyConfiguration": { "useApifyProxy": False },
    "requestDelay": 500,
    "maxConcurrency": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("haketa/bbb-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 '{
  "keyword": "roofing contractor",
  "location": "Dallas, TX",
  "scrapeDetails": false,
  "maxResults": 45,
  "searchUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "requestDelay": 500,
  "maxConcurrency": 2
}' |
apify call haketa/bbb-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,haketa/bbb-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/L8QQos9l8YOEsZUhS/builds/XqoTjjdEA8LNiUyLE/openapi.json
