# BBB Business Search Scraper (`automation-lab/bbb-business-search-scraper`) Actor

Search public BBB business listings by keyword, US location, radius, or direct search URL. Export ratings, accreditation, phones, categories, addresses, coordinates, and profile links.

- **URL**: https://apify.com/automation-lab/bbb-business-search-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## BBB Business Search Scraper

Search public Better Business Bureau business listings by keyword and US location, then export normalized lead, rating, accreditation, contact, category, and location data.

Use **BBB Business Search Scraper** when you need repeatable BBB directory results rather than individual review text or complaint histories. One run can process a normal keyword/location search, one or more existing BBB search URLs, or both.

### What does BBB Business Search Scraper do?

The Actor requests BBB search-result pages through stable US residential sessions and reads the server-rendered business data already present in those pages.

It can:

- search by business keyword or category;
- target a city/state, ZIP code, or other US location accepted by BBB;
- apply an optional radius from 1 to 250 miles;
- paginate through search results;
- accept direct `bbb.org/search` URLs;
- combine several searches into one dataset;
- deduplicate businesses by canonical BBB profile URL;
- stop at a user-defined global result limit;
- export normalized JSON, CSV, Excel, XML, or RSS through Apify datasets.

The Actor does **not** open business profiles in v1. It does not extract individual reviews, complaint narratives, or fields that are not present in public search results.

### Who is it for?

#### Lead-generation agencies

Build prospect lists for local trades and services. Use categories, phone numbers, ratings, and accreditation flags for prioritization before enrichment or outreach.

#### Local-market researchers

Compare the businesses BBB returns for a category across cities, ZIP codes, or radii. Schedule the same inputs to refresh market snapshots.

#### Vendor-risk and compliance teams

Collect public BBB rating and accreditation signals alongside profile URLs for later review. Treat these as source signals, not as a complete risk decision.

#### Reputation and directory platforms

Refresh normalized BBB search records for matching, monitoring, or source-linking workflows without manually copying listings.

### Why use this Actor?

- **Search-focused:** the output is one clean row per business, not a mixture of businesses, reviews, and complaints.
- **Useful source context:** every row includes the exact search, location, radius, page, and URL that produced it.
- **Anti-blocking controls:** sticky residential sessions, explicit Cloudflare challenge detection, bounded retries, and session rotation are built in.
- **Fail-closed behavior:** a challenge page is never reported as a valid empty search.
- **Cost control:** `maxResults` and `maxPages` prevent an unexpectedly broad crawl.
- **Integration-ready:** the default dataset works directly with the Apify API, webhooks, Make, Zapier, Google Sheets, and MCP clients.

### What BBB business data can I extract?

| Field | Meaning |
| --- | --- |
| `businessName` | Business name shown in BBB search |
| `address`, `city`, `state`, `postalCode` | Public address components when present |
| `categories`, `primaryCategory` | BBB category labels |
| `bbbRating`, `ratingScore` | BBB letter rating and exposed numeric score |
| `isBbbAccredited`, `isBbbMember` | Accreditation/member flags exposed by search |
| `phones` | Public phone numbers shown in the result |
| `profileUrl` | Canonical absolute BBB profile URL |
| `bbbOffice` | BBB office associated with the listing |
| `latitude`, `longitude` | Coordinates supplied in the search response |
| `requestAQuoteUrl` | BBB quote-request URL when available |
| `leaveReviewUrl` | BBB leave-a-review URL when available |
| `outOfBusinessStatus` | Out-of-business status when BBB supplies one |
| `sourceQuery` | Search text, location, radius, page, and source URL |
| `scrapedAt` | ISO 8601 collection timestamp |

Fields can be `null` when BBB does not publish them for a particular result. Arrays can be empty.

### How to scrape BBB business search results

1. Open the Actor in Apify Console.
2. Enter both **Business keyword or category** and **Location**.
3. Optionally set a radius in miles.
4. Keep `maxResults` small for your first run.
5. Click **Start**.
6. Open the **Dataset** tab to inspect results.
7. Export the dataset or connect it to your workflow.

A tested starter input is:

```json
{
  "search": "Home Improvement",
  "location": "Los Angeles, CA",
  "distance": 25,
  "maxResults": 25,
  "maxPages": 5
}
```

### Input parameters

| Input | Type | Default | Description |
| --- | --- | --- | --- |
| `search` | string | prefilled | Business keyword or category. Requires `location`. |
| `location` | string | prefilled | US city/state, ZIP code, or BBB-supported location. Requires `search`. |
| `distance` | integer | optional | Radius from 1 to 250 miles. |
| `startUrls` | array | `[]` | Public `bbb.org/search` URLs whose filters should be preserved. |
| `maxResults` | integer | `100` | Maximum unique business rows across the run. |
| `maxPages` | integer | `20` | Maximum result pages processed per search. |
| `maxRequestRetries` | integer | `3` | Retries for blocked or transiently failed pages. |
| `proxyConfiguration` | object | US residential | Advanced proxy override. |

Provide either a keyword/location pair or at least one direct search URL. If you provide both, all searches contribute to one deduplicated dataset.

Only BBB search URLs are accepted in `startUrls`; profile and review URLs are rejected because they are outside this Actor's contract.

### Output example

A current Los Angeles search produced a record with this shape:

```json
{
  "businessName": "Buildda, Inc.",
  "address": null,
  "city": "Culver City",
  "state": "CA",
  "postalCode": "90230-4933",
  "categories": ["Home Improvement"],
  "primaryCategory": "Home Improvement",
  "bbbRating": "A-",
  "ratingScore": 93.17,
  "isBbbAccredited": true,
  "isBbbMember": true,
  "phones": ["(310) 266-5744"],
  "profileUrl": "https://www.bbb.org/us/ca/culver-city/profile/home-improvement/buildda-1216-1000038952",
  "bbbOffice": "BBB of Los Angeles & Silicon Valley",
  "latitude": 34.04,
  "longitude": -118.3,
  "requestAQuoteUrl": "https://www.bbb.org/losangelessiliconvalley/quote/request-buildda-1000038952",
  "leaveReviewUrl": "https://www.bbb.org/us/ca/culver-city/profile/home-improvement/buildda-1216-1000038952/leave-a-review",
  "outOfBusinessStatus": null,
  "sourceQuery": {
    "search": "Home Improvement",
    "location": "Los Angeles, CA",
    "distance": 1,
    "page": 1,
    "url": "https://www.bbb.org/search?find_country=USA&find_text=Home+Improvement&find_loc=Los+Angeles%2C+CA&find_radius=1&page=1"
  },
  "scrapedAt": "2026-01-15T12:00:00.000Z"
}
```

Public source values can change between runs as BBB updates its directory.

### How much does it cost to scrape BBB business results?

The Actor uses pay-per-event pricing:

- **$0.005 per run start**;
- **$0.000041071 per saved business on the FREE tier**;
- volume discounts reduce the per-business price through BRONZE, SILVER, GOLD, PLATINUM, and DIAMOND tiers.

At FREE-tier pricing, approximate Actor charges are:

| Saved businesses | Approximate charge |
| ---: | ---: |
| 25 | about 0.006 USD |
| 100 | about 0.009 USD |
| 1,000 | about 0.046 USD |

These examples include the run-start event and round to three decimals. Your active tier can be cheaper. A duplicate, rejected record, failed request, or empty result is not charged as a business result. Apify displays the exact charge in each run.

### Search and pagination tips

- Begin with 25–100 results to validate category and location quality.
- Prefer a specific trade such as `Roofing Contractors` over a broad word such as `Services`.
- Use direct BBB search URLs when you need to reproduce filters selected in the BBB interface.
- Use several `startUrls` to build multi-market exports in one run.
- Keep `maxPages` bounded; BBB can rank or repeat businesses across neighboring areas.
- Deduplication uses the canonical BBB profile URL across every search in the run.
- `maxResults` is global, so earlier searches can consume the limit before later searches run.

### Anti-bot behavior and retries

BBB currently challenges direct data-center HTTP traffic. The default configuration therefore uses a US residential proxy and keeps one proxy session while paginating.

On a verified challenge or transient response, the Actor rotates to a fresh session and retries with exponential backoff. After `maxRequestRetries` is exhausted, the run fails with a clear error instead of returning a misleading empty dataset.

Disabling the proxy is an advanced choice and can cause HTTP 403 responses. There is no hidden automatic browser fallback, which keeps runtime and pricing predictable.

### Workflow and integration ideas

#### Scheduled local-lead refresh

Run weekly with the same category and city. Deliver the dataset to Google Sheets or a CRM, then match by `profileUrl` to detect new or changed businesses.

#### Accreditation-aware prospect scoring

Combine `bbbRating`, `isBbbAccredited`, categories, and location with your own firmographic enrichment. Do not treat accreditation alone as proof of suitability.

#### Multi-city market comparison

Pass multiple search URLs for the same category, group rows by `sourceQuery.location`, and compare result counts, rating distribution, and category mix.

#### Human vendor review queue

Send records with a low or missing rating to an internal review workflow and retain `profileUrl` so an analyst can inspect the public source.

### Use the Apify API

Replace `APIFY_TOKEN` with your token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~bbb-business-search-scraper/runs?token=APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"search":"Plumber","location":"Dallas, TX","distance":25,"maxResults":100}'
```

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/bbb-business-search-scraper').call({
  search: 'Plumber',
  location: 'Dallas, TX',
  distance: 25,
  maxResults: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("automation-lab/bbb-business-search-scraper").call(run_input={
    "search": "Plumber",
    "location": "Dallas, TX",
    "distance": 25,
    "maxResults": 100,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)
```

For synchronous API calls, use `run-sync-get-dataset-items` when the expected run fits the endpoint timeout.

### Use BBB search with MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/bbb-business-search-scraper"
```

#### Claude Desktop, Cursor, and VS Code setup

Desktop and editor clients can use this HTTP MCP configuration in Claude Desktop, Cursor, or VS Code:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/bbb-business-search-scraper"
    }
  }
}
```

Example prompts:

- “Find up to 100 BBB-listed roofing contractors around Phoenix and return phone, rating, accreditation, and profile URL.”
- “Collect plumbers from my three BBB search URLs and group them by source location.”
- “Run this BBB search weekly and highlight new profile URLs.”

### Responsible use and legality

This Actor collects public business-search data without a BBB login. You are responsible for your use of the output.

- Review BBB's terms and applicable laws for your use case.
- Respect privacy, marketing, telemarketing, and anti-spam rules before outreach.
- Do not use BBB ratings as the sole basis for consequential decisions.
- Avoid excessive collection and retain only data needed for a legitimate purpose.
- Do not attempt to use the Actor for authenticated, private, or restricted content.

The Actor is not affiliated with or endorsed by the Better Business Bureau.

### Limitations

- V1 exports search-result fields only; it does not scrape profile details, complaints, or individual reviews.
- Search ranking, result availability, fields, and category labels are controlled by BBB and can change.
- Some addresses, phones, coordinates, ratings, and action URLs are absent and return `null` or an empty array.
- BBB anti-bot controls can change. Exhausted challenge retries fail the run.
- Search results may include businesses near, rather than strictly inside, the text location according to BBB's matching logic.
- The radius applies only when BBB honors the `find_radius` filter.
- A successful no-result search produces an empty dataset; a challenge does not.

### Troubleshooting

#### Why did my run return no businesses?

Open the source URL recorded in the logs and confirm BBB itself returns results for that keyword/location combination. Try a broader category, larger radius, or a direct search URL from BBB.

#### Why did my run fail with a challenge error?

Keep the default US residential proxy enabled and leave retries at 3 or 4. If BBB is experiencing a temporary protection spike, retry later rather than raising concurrency.

#### Why was my direct URL rejected?

`startUrls` accepts only public BBB `/search` URLs. Profile, complaint, and review URLs belong to different workflows.

#### Why are some fields null?

BBB does not expose every field for every listing. Nulls represent missing source data, not parser placeholders.

### Related Automation Lab actors

- [Google Maps Lead Finder](https://apify.com/automation-lab/google-maps-lead-finder) — discover broader local-business leads and place data.
- [Bing Maps Places Scraper](https://apify.com/automation-lab/bing-maps-places-scraper) — compare directory coverage from another maps source.
- [Multi-Source Lead Enrichment](https://apify.com/automation-lab/multi-source-lead-enrichment) — enrich and score business records after collection.

Use BBB Business Search Scraper when BBB rating, accreditation, and source profile links are central to the workflow. Use the related actors when broader discovery or enrichment is the main job.

### FAQ

#### Does the Actor require a BBB account?

No. It accesses public BBB search pages anonymously.

#### Can it extract BBB reviews or complaints?

No. Individual reviews and complaints are intentionally outside v1 scope.

#### Can I search several cities in one run?

Yes. Add direct BBB search URLs for each city. You can also combine one keyword/location pair with those URLs.

#### Will the Actor save duplicate businesses?

No. Results with the same canonical BBB profile URL are saved once per run.

#### Can I export CSV or Excel?

Yes. Use the dataset export controls in Apify Console or the dataset API.

#### Can I schedule recurring runs?

Yes. Use Apify Schedules and optionally connect a webhook or integration to process the refreshed dataset.

#### Is a BBB rating a recommendation?

No. It is a source-provided signal. Validate businesses using criteria appropriate to your workflow.

# Actor input Schema

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

What to search for, such as Home Improvement, Plumber, or Roofing Contractors.

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

US city and state, ZIP code, or other location understood by BBB search.

## `distance` (type: `integer`):

Optional maximum radius around the location, from 1 to 250 miles.

## `startUrls` (type: `array`):

Optional public bbb.org/search URLs. Their keyword, location, and radius filters are preserved.

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

Maximum number of unique business records to save across all searches.

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

Safety limit for BBB search-result pages processed for each search.

## `maxRequestRetries` (type: `integer`):

Retries a blocked or transiently failed page with a fresh proxy session.

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

Residential US proxy is used by default because BBB blocks direct data-center requests.

## Actor input object example

```json
{
  "search": "Home Improvement",
  "location": "Los Angeles, CA",
  "distance": 20,
  "startUrls": [],
  "maxResults": 20,
  "maxPages": 5,
  "maxRequestRetries": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

Dataset view containing BBB business ratings, accreditation, contacts, categories, locations, profile links, and source-query context.

# 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 = {
    "search": "Home Improvement",
    "location": "Los Angeles, CA",
    "distance": 20,
    "startUrls": [],
    "maxResults": 20,
    "maxPages": 5,
    "maxRequestRetries": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/bbb-business-search-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 = {
    "search": "Home Improvement",
    "location": "Los Angeles, CA",
    "distance": 20,
    "startUrls": [],
    "maxResults": 20,
    "maxPages": 5,
    "maxRequestRetries": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/bbb-business-search-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "search": "Home Improvement",
  "location": "Los Angeles, CA",
  "distance": 20,
  "startUrls": [],
  "maxResults": 20,
  "maxPages": 5,
  "maxRequestRetries": 3
}' |
apify call automation-lab/bbb-business-search-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/bbb-business-search-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rm9p27Lm0omfN09Qt/builds/MmBR5UDCR8MfKelP1/openapi.json
