BBB Scraper avatar

BBB Scraper

Pricing

from $4.00 / 1,000 results

Go to Apify Store
BBB Scraper

BBB Scraper

Scrape business profiles from Better Business Bureau (BBB.org). Extract BBB ratings, accreditation status, complaints, reviews, owner info, license numbers and contact details. Search by keyword, location, category and country (USA/Canada).

Pricing

from $4.00 / 1,000 results

Rating

0.0

(0)

Developer

Haketa

Haketa

Maintained by Community

Actor stats

0

Bookmarked

11

Total users

6

Monthly active users

3 days ago

Last modified

Share

BBB Scraper — Better Business Bureau Business Profiles, Ratings, Complaints & Accreditation Data Extractor (US + Canada)

The most complete Better Business Bureau (BBB.org) data extraction tool on Apify. Pull full business profiles from BBB — letter grade ratings, accreditation status, complaint counts, customer review scores, owner details, license numbers and contact info — across the entire United States and Canada. Search by keyword, city, state, ZIP, or pre-built BBB search URL, and ship structured JSON ready for B2B lead generation, business-credit risk analysis, reputation monitoring, M&A due diligence, contractor vetting, and journalism workflows.

Apify Actor


What This Actor Does

The BBB Scraper is a production-grade Apify Actor that extracts complete business profiles from the Better Business Bureau (BBB.org) — the largest non-profit business directory in North America, covering more than 5 million companies across the United States and Canada. BBB profiles are widely treated as a de-facto trust signal for local services: roofing contractors, plumbers, HVAC companies, home builders, auto dealers, movers, financial advisors, debt collectors, e-commerce brands, and thousands of other categories all maintain public BBB pages.

This actor opens a real Chromium browser via Playwright (in headed mode under Apify's virtual display), navigates BBB search results and business profile pages, transparently solves Cloudflare's JavaScript challenge, and parses each profile into a normalized JSON record. You drive it with a keyword + location (e.g. "roofing contractor" in "Dallas, TX") or by pasting direct BBB search URLs, and you get back a structured dataset of every business that BBB shows for that query.

Each record can include:

  • Identity — business name, BBB business ID, full BBB profile URL
  • Trust signals — BBB letter-grade rating (A+ through F), accreditation status, accreditation start date
  • Contact — street address, city, state/province, ZIP/postal code, phone, email, website
  • Categorization — business categories, service areas, line of business
  • Firmographics — years in business, business start date, business type (LLC / Corporation / Sole Proprietorship), employee count band, owner / principal name
  • Compliance — license numbers reported to BBB, government action narratives
  • Reputation — total complaints closed, complaints in the last 3 years, complaints in the last 12 months, complaints resolved, customer review count, average customer review rating
  • Channels — social media URLs (Facebook, LinkedIn, X/Twitter, Instagram) belonging to the business itself, not BBB's own accounts
  • Provenance — source search keyword, source search location, ISO-8601 scrapedAt timestamp

The result is the fastest way to populate or refresh a BBB-anchored business dataset for B2B lead generation, reputation monitoring, vendor onboarding, contractor vetting, and investigative reporting.

Why scrape BBB yourself when this exists?

BBB looks like a simple directory until you try to scrape it at scale. Almost every team that tries to roll their own pipeline hits the same wall:

  • BBB.org sits behind Cloudflare's JS challenge — naive HTTP clients (requests, axios, got, even got-scraping) get a 403 and an HTML "Just a moment…" page instead of data
  • Cloudflare also fingerprints headless Chromium — running Playwright in plain headless: true mode is detected within seconds and challenged on every request
  • The search page is React-rendered, so the business cards do not exist in the initial HTML and require a real DOM to materialize
  • Pagination is URL-driven (?page=2, ?page=3…) but BBB silently caps deep pagination and serves partial pages near the end of a result set
  • Result cards mix organic businesses with paid ads that link out through DoubleClick / Google Ads — those entries have to be filtered out or they pollute your dataset
  • Profile URLs include duplicate sub-pages (/details, /accreditation, /customer-reviews, /complaints, /addressId) that all need to be deduplicated to one canonical profile per business
  • Profile pages mix JSON-LD structured data, free-text "About this business" prose, and CSS-class-driven panels — extracting accreditation, complaints, owner, and business start date reliably requires four different parsing strategies
  • Email addresses on profiles are protected by Cloudflare's email obfuscation (data-cfemail="...") — they have to be decoded with the XOR-key trick before they are readable
  • BBB rate-limits aggressively; running anything beyond single-digit concurrency triggers temporary IP blocks
  • Categories, service areas, and license numbers live in CSS class names that drift every few months — the parser needs fuzzy class matching that survives BBB's redesigns

This actor solves every one of those problems out of the box. You provide a keyword and location; it returns clean, deduplicated, normalized JSON with all of the BBB trust signals you actually need.


Quick Start

One-Click Run

  1. Open the actor on the Apify Store: apify.com/haketa/bbb-scraper
  2. Click "Try for free" and accept the defaults (roofing contractor in Dallas, TX, 5 results, no detail pages)
  3. Hit Start — within a minute or two you will have your first dataset of business cards
  4. Toggle Scrape Detail Pages to true and bump Max Results to 100 for a full enrichment run

API Run (Python)

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("haketa/bbb-scraper").call(run_input={
"keyword": "roofing contractor",
"location": "Dallas, TX",
"country": "USA",
"accreditedOnly": True,
"sort": "Rating",
"scrapeDetails": True,
"maxResults": 200,
"maxPages": 10,
"requestDelay": 2500,
"proxyConfiguration": {
"useApifyProxy": True,
"apifyProxyGroups": ["RESIDENTIAL"]
}
})
for record in client.dataset(run["defaultDatasetId"]).iterate_items():
print(
record["bbbRating"],
record["businessName"],
record["city"],
record["complaintsLast3Yrs"],
record["profileUrl"],
)

API Run (Node.js / TypeScript)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('haketa/bbb-scraper').call({
keyword: 'HVAC',
location: 'Phoenix, AZ',
country: 'USA',
accreditedOnly: false,
sort: 'Relevance',
scrapeDetails: true,
maxResults: 100,
maxPages: 5,
proxyConfiguration: {
useApifyProxy: true,
apifyProxyGroups: ['RESIDENTIAL'],
},
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`Pulled ${items.length} Phoenix HVAC companies from BBB`);
const aPlusAccredited = items.filter(
(b) => b.bbbRating === 'A+' && b.isAccredited === true,
);
console.log(`${aPlusAccredited.length} are A+ rated AND BBB Accredited`);

API Run (cURL)

curl -X POST "https://api.apify.com/v2/acts/haketa~bbb-scraper/runs?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"keyword": "plumber",
"location": "Toronto, ON",
"country": "CAN",
"scrapeDetails": false,
"maxResults": 50
}'

Direct-URL mode (skip keyword/location, use BBB URLs you already have)

run = client.actor("haketa/bbb-scraper").call(run_input={
"searchUrls": [
"https://www.bbb.org/search?find_text=electrician&find_loc=Brooklyn%2C+NY&find_country=USA",
"https://www.bbb.org/search?find_text=auto+repair&find_loc=Los+Angeles%2C+CA&find_country=USA"
],
"scrapeDetails": True,
"maxResults": 0, # unlimited
"maxPages": 15
})

How It Works

The actor talks to a single host — www.bbb.org — and walks two layers of pages:

  1. Search results pages at https://www.bbb.org/search?find_text={keyword}&find_loc={location}&find_country={USA|CAN}&page={N}&sort={Relevance|Rating|Distance|Name}
  2. Business profile pages at https://www.bbb.org/{us|ca}/{state}/{city}/profile/{category-slug}/{business-slug}-{bbbId}

Source endpoints

LayerURL patternPurposeEngine
Searchbbb.org/search?find_text=...&find_loc=...&find_country=...&page=NList business cards 20 per pagePlaywright + Cheerio
Profilebbb.org/{country}/{state}/{city}/profile/{category}/{slug}-{bbbId}Full firmographics, complaints, reviewsPlaywright + Cheerio
JSON-LDEmbedded <script type="application/ld+json"> on profile pagesStructured business name, address, phone, ratingsCheerio JSON parse

Engineering details

  • Headed Playwright Chromium — runs with headless: false under Apify's xvfb virtual display. Headless Chromium is detected and challenged by Cloudflare almost immediately; headed mode under xvfb passes the same fingerprint checks a real browser passes.
  • Stealth init scriptnavigator.webdriver is set to undefined and window.chrome.runtime is stubbed before any page navigates, killing the two most common bot-detection flags.
  • Cloudflare challenge loop — every navigation enters a 15-step wait loop that watches document.title and the first 200 chars of body.innerText for the strings Just a moment, Checking your browser, and Verify you are human. The loop exits as soon as real <a href*="/profile/"> links appear or the body length crosses 500 characters.
  • Custom UA + viewport — Chrome 124 on Windows 10 at 1920x1080, en-US locale, JavaScript enabled.
  • Cheerio parsing — once the HTML is in hand, parsing is done with Cheerio in-process (zero browser overhead per field extraction).
  • Ad filtering — search-card links that go through doubleclick.net, adclick, or googleads are dropped before they reach the dataset.
  • Sub-page deduplication — links ending in /details, /accreditation, /customer-reviews, /complaints, or /addressId are stripped down to the canonical profile URL and deduplicated via a Set.
  • BBB ID extraction — the trailing -XXXXXXXX numeric segment of the profile slug becomes the stable bbbId.
  • Multi-strategy field extraction — accreditation, complaints, owner name, business type, and employee count are extracted from (a) JSON-LD Organization / LocalBusiness blocks, (b) CSS-class-keyed panels, and (c) free-text regex over the full page body. First non-null wins.
  • Cloudflare email decoderdata-cfemail attributes are decoded with the XOR-key trick (first byte = key, remaining bytes XORed) so obfuscated emails become readable.
  • Social media hygiene — Facebook / LinkedIn / X / Instagram URLs are filtered against a blocklist of BBB's own accounts (betterbusinessbureau, bbb_us, share-intent URLs) so you only get the business's socials.
  • Random-jitter delay — each subsequent request waits requestDelay + random(0–1000ms) to avoid forming a detectable cadence.
  • Single-concurrency defaultmaxConcurrency = 1 and capped at 3. BBB rate-limits aggressively; speed comes from requestDelay tuning, not parallelism.
  • Graceful partial output — fatal errors flush whatever was already collected and call Actor.exit with a non-zero exit code so the run is visibly failed without losing progress.

Input Parameters

{
"searchUrls": [],
"keyword": "roofing contractor",
"location": "Dallas, TX",
"country": "USA",
"accreditedOnly": false,
"sort": "Relevance",
"scrapeDetails": false,
"maxResults": 100,
"maxPages": 10,
"requestDelay": 1500,
"maxConcurrency": 1,
"proxyConfiguration": { "useApifyProxy": false }
}

Parameter reference

ParameterTypeDefaultDescription
searchUrlsarray<string>[]Pre-built BBB search URLs. When provided, keyword / location / country / sort are ignored and the actor walks each URL through maxPages. Use this when you already have a curated BBB URL list.
keywordstringroofing contractorBusiness type, profession, or company-name query. Examples: plumber, HVAC, home builder, electrician, moving company, auto repair, dentist, mortgage broker, tree service.
locationstringDallas, TXCity + state, state only, or ZIP / postal code. Examples: Houston, TX, California, 90210, Toronto, ON, Vancouver, BC.
countrystring enumUSAUSA for the United States, CAN for Canada. Drives the find_country query param.
accreditedOnlybooleanfalseWhen true, filters out any listing that is not BBB Accredited.
sortstring enumRelevanceSort order for search results: Relevance, Rating, Distance, or Name.
scrapeDetailsbooleanfalseWhen true, the actor opens every business profile page and fills complaints, reviews, owner, license numbers, social media, business start date, employee count, and full address. Adds ~3–6 seconds per business.
maxResultsinteger100Hard cap on total businesses saved. 0 means unlimited.
maxPagesinteger10Maximum search pages walked per task. Each page = ~20 results.
requestDelayinteger (ms)1500Base delay between requests. Random jitter of 0–1000 ms is added on top. Keep ≥ 1000 ms to avoid blocks.
maxConcurrencyinteger1Parallel browser pages. Max 3. BBB rate-limits aggressively — leave at 1 unless you have residential proxies and are willing to monitor for blocks.
proxyConfigurationobject{ useApifyProxy: false }Standard Apify proxy block. Residential proxies strongly recommended for runs above ~50 businesses or whenever you see Cloudflare challenge loops.

Output Schema

Every record is a flat JSON object so it can be loaded directly into a CRM, warehouse, spreadsheet, or BI tool without per-field branching. Fields that were not present on a given profile come back as null (so the schema is stable across listing-only and detail-enriched runs).

Identity fields

FieldTypeDescription
businessNamestringCompany / DBA name as displayed by BBB
profileUrlstringCanonical BBB profile URL (sub-pages stripped)
bbbIdstringBBB's stable business identifier (trailing digits in the profile slug)

Trust signals

FieldTypeDescription
bbbRatingstringLetter grade — one of A+, A, A-, B+, B, B-, C+, C, C-, D+, D, D-, F, or NR (no rating)
isAccreditedbooleantrue if the page shows "BBB Accredited Business since…", false if explicitly "Not BBB Accredited", null if undetermined
accreditationSincestringAccreditation start date as printed on the profile (e.g. 5/12/2017, March 2009, 2003)

Contact fields

FieldTypeDescription
addressstringStreet address as reported to BBB
citystringCity
statestringTwo-letter US state or Canadian province abbreviation
zipCodestringZIP code (5 or 9 digits, US) or postal code (Canada)
phonestringBusiness phone number — pulled from tel: link, JSON-LD, or visible text
emailstringBusiness contact email — Cloudflare-obfuscated emails are decoded
websitestringBusiness website URL (BBB redirect URLs and share links filtered out)

Categorization

FieldTypeDescription
categoriesarray<string>BBB business categories (e.g. ["Roofing Contractors", "Construction"])
serviceAreasarray<string>Cities / regions the business reports serving

Firmographics

FieldTypeDescription
yearsInBusinessintegerComputed from businessStartDate
businessStartDatestringDate the business reports having started (e.g. 1/1/2008)
businessTypestringLegal structure — LLC, Corporation, Sole Proprietorship, Partnership, Inc, LP, LLP
numberOfEmployeesstringEmployee count band as printed on BBB (e.g. 25 to 50, 5)
ownerNamestringOwner / principal / management contact name
licenseNumbersarray<string>License numbers the business has registered with BBB

Reputation

FieldTypeDescription
complaintsTotalintegerAll-time BBB complaints closed for the business
complaintsLast3YrsintegerBBB complaints closed in the last 3 years
complaintsLast12MointegerBBB complaints closed in the last 12 months
complaintsResolvedintegerBBB complaints resolved to the customer's satisfaction
reviewCountintegerNumber of customer reviews submitted on BBB
averageReviewRatingnumberAverage customer review score (1.0 – 5.0)

Channels & narratives

FieldTypeDescription
socialMediaobject{ facebook, linkedin, twitter, instagram } — only the business's own accounts
governmentActionsstringFree-text summary of government / regulatory actions noted on the profile
descriptionstring"About this business" narrative

Provenance

FieldTypeDescription
searchKeywordstringThe keyword used to find this business
searchLocationstringThe location used to find this business
scrapedAtstringISO-8601 timestamp of extraction

Example: search-only record (scrapeDetails: false)

{
"businessName": "Skyline Roofing & Solar",
"profileUrl": "https://www.bbb.org/us/tx/dallas/profile/roofing-contractors/skyline-roofing-solar-0875-90719612",
"bbbId": "90719612",
"bbbRating": "A+",
"isAccredited": true,
"accreditationSince": null,
"address": "5050 Quorum Dr Ste 700",
"city": "Dallas",
"state": "TX",
"zipCode": "75254",
"phone": "+1 214 555 0142",
"email": null,
"website": null,
"categories": ["Roofing Contractors", "Solar Energy Contractors"],
"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-05-16T14:22:11.401Z"
}

Example: fully enriched record (scrapeDetails: true)

{
"businessName": "Northstar HVAC Services LLC",
"profileUrl": "https://www.bbb.org/us/az/phoenix/profile/heating-and-air-conditioning/northstar-hvac-services-1126-99999001",
"bbbId": "99999001",
"bbbRating": "A",
"isAccredited": true,
"accreditationSince": "3/14/2014",
"address": "2400 W Camelback Rd Ste 210",
"city": "Phoenix",
"state": "AZ",
"zipCode": "85015",
"phone": "+1 602 555 0188",
"email": "service@northstar-hvac.example",
"website": "https://northstar-hvac.example",
"categories": ["Heating and Air Conditioning", "Air Duct Cleaning", "Furnace Repair"],
"serviceAreas": ["Phoenix", "Scottsdale", "Tempe", "Mesa", "Glendale", "Chandler"],
"yearsInBusiness": 17,
"businessStartDate": "1/1/2008",
"businessType": "LLC",
"numberOfEmployees": "25 to 50",
"ownerName": "Maria S. Alvarez",
"licenseNumbers": ["ROC 99999", "ROC 99998"],
"complaintsTotal": 12,
"complaintsLast3Yrs": 7,
"complaintsLast12Mo": 2,
"complaintsResolved": 6,
"reviewCount": 184,
"averageReviewRating": 4.6,
"socialMedia": {
"facebook": "https://www.facebook.com/northstarhvacaz",
"linkedin": "https://www.linkedin.com/company/northstar-hvac",
"instagram": "https://www.instagram.com/northstar.hvac/"
},
"governmentActions": null,
"description": "Full-service residential and commercial HVAC contractor serving the Phoenix metro since 2008. NATE-certified technicians, 24/7 emergency service.",
"searchKeyword": "HVAC",
"searchLocation": "Phoenix, AZ",
"scrapedAt": "2026-05-16T14:25:48.117Z"
}

BBB Rating Reference

BBB issues a single letter-grade rating per business on a 13-point scale plus a "not rated" bucket. The rating is computed from complaint history, transparency of the business, time in operation, government action, advertising practices, and licensing.

Investment-grade ratings (low risk, default vendor whitelist)

RatingMeaning
A+Top score — clean complaint history + transparent + tenured
AExcellent — minor blemishes but resolved
A-Very good — small number of unresolved items

Sub-investment ratings (still operating, vet manually)

RatingMeaning
B+ / B / B-Above average — review complaint themes before engagement
C+ / C / C-Average — pattern of complaints or limited transparency
D+ / D / D-Poor — recurring unresolved complaints, government action, or short history

Distressed (high risk, recommend exclude)

RatingMeaning
FWorst rating — pattern of unresolved complaints, fraud allegations, or refusal to engage with BBB
NRNot Rated — insufficient information or business too new

Accreditation vs. Rating

The two are independent: a business can be A+ and not accredited (didn't apply / didn't pay) or B- and accredited (passed standards review even with mixed complaint history). Use both bbbRating and isAccredited to score risk.


Use Cases

B2B Lead Generation (Local Services)

Companies selling into the trades — software vendors, payment processors, lead-gen networks, equipment suppliers, insurance brokers — use BBB as a curated source of vetted local-service businesses:

  • Pull every roofing contractor in Dallas-Fort Worth with rating ≥ A- for a SaaS roofing CRM sales push
  • Build a HVAC TAM list for every metro you target by running 20+ keyword × city pairs in one schedule
  • Enrich CRM accounts (Salesforce, HubSpot, Pipedrive, Close) with BBB rating, accreditation, complaint counts, and owner name
  • Filter outbound to accredited businesses only by setting accreditedOnly: true — instantly higher reply rates because the prospects have already paid to be vetted
  • Score lead quality in your scoring model using complaintsLast3Yrs / yearsInBusiness as a normalized friction signal
  • Route territory by ZIP using the zipCode and city fields exactly as they appear on BBB
  • Tier accountsA+ accredited & 10+ years in business → enterprise team; B rated & <3 years → SMB self-serve

Business Credit & Risk Analysis

Trade-credit insurers, factoring companies, BNPL providers, alt-data scoring shops, and KYB platforms use BBB data as a soft-but-pervasive trust signal:

  • Build a daily watchlist of every counterparty in your portfolio and re-pull BBB to detect rating downgrades
  • Flag spikes in complaintsLast12Mo as an early-warning signal of operational distress
  • Combine with SAM.gov, TTB and state licensing data to build a multi-source trust score
  • Validate ownership during onboarding by cross-referencing ownerName against operating-agreement filings
  • Detect newly accredited businesses in your target ICP for credit upsells
  • Quantify reputation tail risk by joining bbbRating × complaintsTotal × governmentActions into a single score
  • Provide adverse-media surrogate for borrowers without traditional bureau coverage

Reputation Monitoring & Brand Protection

Brands, franchise HQs, and managed-service providers use this actor to watch their own and competitor reputation:

  • Monitor every franchise location of a multi-location brand for rating drops, new complaints, or accreditation lapses
  • Diff weekly snapshots to catch new complaints within 7 days of filing
  • Benchmark against competitors in the same metro and category
  • Trigger PR / customer-care workflows when complaintsLast12Mo crosses a threshold
  • Audit franchisee compliance with brand standards by tracking license numbers and governmentActions
  • Feed Power BI dashboards that show rating drift per location per month

M&A Due Diligence (Lower-Middle-Market Services Roll-Ups)

PE firms and search funds rolling up local services (HVAC, plumbing, roofing, pest control, auto repair, vet clinics, home health) lean on BBB as a free, pre-acquisition diligence layer:

  • Screen targets in a metro by pulling every A and A+ rated business in the trade
  • Reject targets with F ratings or governmentActions content before spending hours on a CIM
  • Quantify complaint exposure for any LOI candidate before committing capital
  • Verify years in business against seller-provided figures
  • Identify the owner / principal for direct cold outreach (LP-funded search funds rely on this heavily)
  • Build sector heatmaps showing density and quality of providers per ZIP for thesis building

Journalism, Watchdog & Complaint Investigations

Investigative reporters, consumer-protection columnists, and state attorney-general offices use BBB to surface patterns of consumer harm:

  • Identify clusters of high-complaint businesses in a single category and metro (e.g. moving scams, debt-relief mills, solar door-knockers, timeshare exit firms)
  • Track government-action narratives across hundreds of businesses to spot serial offenders rebranded under new entities
  • Quantify "F"-rated business density by neighborhood for accountability journalism
  • Combine with TTB alcohol permittees, SAM.gov entities, and state licensing scrapers to build full corporate-shell maps
  • Build a complaint-spike alert that fires when any local business breaches a threshold

Contractor & Vendor Vetting

Property managers, REITs, facility managers, insurance adjusters, and corporate procurement teams use BBB during contractor selection:

  • Pre-approve vendors by requiring rating ≥ B+ and isAccredited === true
  • Automate panel refresh with a scheduled run every 30 days that re-validates every contractor
  • Cross-reference license numbers between BBB and state licensing scrapers (Arizona ROC, NC GC Board, Washington L&I, California DCA) for credentials sanity-check
  • Push results to a Make.com / Zapier flow that issues / revokes vendor portal access automatically
  • Maintain a per-property "approved trades" list with daily-fresh ratings

Compliance & Anti-Fraud Operations

Marketplaces, payment platforms, and KYB-driven onboarding teams use BBB data as one signal among several:

  • Block onboarding for merchants with F ratings or active governmentActions
  • Manual review queue triggered by complaintsLast12Mo > N
  • Risk segmentation for chargeback monitoring — high-rating accredited merchants get faster settlement
  • Build merchant-risk profiles that combine BBB with SAM.gov debarment, OFAC, and state licensing scrapes
  • Post-incident retro — diff the BBB snapshot from before vs. after a chargeback storm

Market Research & Competitive Intelligence

Strategy consultants, market-research firms, and corporate strategy teams use the dataset to size local-service markets:

  • Count active accredited businesses per category per metro to size TAM
  • Track competitor counts over time (run the same query monthly, diff the dataset)
  • Map rating distribution — what percentage of plumbers in Atlanta are A-rated vs. B vs. unaccredited?
  • Quantify market consolidation by tracking owner-name uniqueness over many businesses
  • Geographic expansion modeling — pull 50 metros in one schedule, normalize, plot rating × density

Insurance Underwriting (Small Commercial)

Carriers underwriting GL, BOP, E&O, or workers-comp for small contractors use BBB as a free underwriting overlay:

  • Auto-decline quotes for F-rated applicants
  • Surcharge quotes where complaintsLast3Yrs > 5
  • Validate years in business during quote bind
  • Re-check at renewal — schedule a monthly refresh against your in-force book

Academic & Public-Policy Research

Researchers studying small-business dynamics, consumer protection, and local labor markets use BBB as a free, structured panel:

  • Study churn by snapshotting the dataset quarterly and comparing
  • Analyze complaint patterns across demographics and ZIP codes
  • Quantify accreditation impact on consumer-review volume
  • Compare US vs. Canadian business norms by running both country: "USA" and country: "CAN"

Sample Queries & Recipes

Recipe 1 — Top-rated roofing contractors in Texas metros (lead-gen TAM)

{
"searchUrls": [
"https://www.bbb.org/search?find_text=roofing+contractor&find_loc=Houston%2C+TX&find_country=USA",
"https://www.bbb.org/search?find_text=roofing+contractor&find_loc=Dallas%2C+TX&find_country=USA",
"https://www.bbb.org/search?find_text=roofing+contractor&find_loc=Austin%2C+TX&find_country=USA",
"https://www.bbb.org/search?find_text=roofing+contractor&find_loc=San+Antonio%2C+TX&find_country=USA"
],
"accreditedOnly": true,
"sort": "Rating",
"scrapeDetails": true,
"maxResults": 0,
"maxPages": 10,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

Recipe 2 — HVAC TAM across the southwest US (no detail enrichment for speed)

{
"keyword": "HVAC",
"location": "Arizona",
"country": "USA",
"scrapeDetails": false,
"maxResults": 500,
"maxPages": 25
}

Recipe 3 — Canadian general contractors in Greater Toronto

{
"keyword": "general contractor",
"location": "Toronto, ON",
"country": "CAN",
"accreditedOnly": false,
"scrapeDetails": true,
"maxResults": 200
}

Recipe 4 — High-risk movers nationwide (journalism / consumer protection)

{
"keyword": "moving company",
"location": "United States",
"country": "USA",
"sort": "Rating",
"scrapeDetails": true,
"maxResults": 1000,
"maxPages": 50
}

Then post-filter in your stack:

high_risk = [
r for r in records
if r["bbbRating"] in ("F", "D-", "D", "D+")
or (r.get("complaintsLast12Mo") or 0) > 5
]

Recipe 5 — Reputation watch for a specific brand's franchise network

{
"keyword": "ABC Plumbing",
"location": "United States",
"country": "USA",
"scrapeDetails": true,
"maxResults": 0,
"maxPages": 20
}

Schedule this nightly; diff bbbRating and complaintsLast12Mo against yesterday's run.

Recipe 6 — Test sample (10 records to validate filters before a big run)

{
"keyword": "electrician",
"location": "90210",
"country": "USA",
"scrapeDetails": true,
"maxResults": 10,
"maxPages": 1
}

Recipe 7 — Auto-dealer vetting with full enrichment in Chicago

{
"keyword": "used car dealer",
"location": "Chicago, IL",
"country": "USA",
"accreditedOnly": true,
"sort": "Rating",
"scrapeDetails": true,
"maxResults": 300,
"maxPages": 15,
"requestDelay": 3000,
"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}

Integration Examples

Google Sheets

  1. Create an Apify schedule that runs this actor once a week with your TAM keywords
  2. Add the "Save to Google Sheets" Apify integration to the schedule
  3. Every Monday morning, a fresh sheet of BBB-vetted leads appears in your Drive — append-mode keeps history

Make.com / Zapier / n8n

The Apify connector exists on every major automation platform. Common BBB triggers:

  • New A+ accredited business in $METRO → push to Slack #sales channel
  • Rating downgrade for any account in CRM → create a HubSpot Task for the account owner
  • complaintsLast12Mo spike → email the customer-success team
  • New governmentActions text → page the compliance officer

Power BI / Tableau / Looker

Pull the Apify dataset via the REST API as a custom data source. Refresh on the actor's schedule. Dashboards we have seen built on this data:

  • Rating distribution heatmap per metro per category
  • Complaint velocity (complaintsLast12Mo / yearsInBusiness) per ZIP
  • Accredited vs. non-accredited share over time
  • Top 20 worst-rated businesses per state, refreshed weekly

Postgres / Snowflake / BigQuery

Use Apify's webhook integration to POST the dataset URL to your warehouse ingestion endpoint after every run. The flat JSON schema maps cleanly to a single bbb_businesses table; treat bbbId as a natural key for upserts.

CREATE TABLE bbb_businesses (
bbb_id TEXT PRIMARY KEY,
business_name TEXT,
bbb_rating TEXT,
is_accredited BOOLEAN,
accreditation_since TEXT,
city TEXT,
state TEXT,
zip_code TEXT,
phone TEXT,
website TEXT,
categories TEXT[],
years_in_business INTEGER,
owner_name TEXT,
complaints_total INTEGER,
complaints_3yrs INTEGER,
complaints_12mo INTEGER,
review_count INTEGER,
avg_review_rating NUMERIC(2,1),
scraped_at TIMESTAMPTZ
);

Salesforce / HubSpot / Pipedrive CRM Enrichment

Trigger a scheduled run nightly, then upsert against Account records keyed on bbbId (preferred) or website (fallback). Rating-change events can create Tasks, fire Workflows, or update Lead Scores automatically.

Webhook fan-out

Apify can POST the run's dataset directly to any HTTPS endpoint. Use this to push fresh BBB data into your own backend, a Lambda, a Cloud Function, or a worker queue without polling.


Major US & Canadian Markets Covered

BBB lists businesses in every metro across the United States and Canada. The table below highlights the markets most commonly queried by users of this actor — but the actor works for any city or postal code BBB indexes.

MarketCountryWhy this metro shows up so often
New York, NYUSALargest small-business pool in the US; high inbound from B2B SaaS teams
Los Angeles, CAUSAMassive home-services TAM; contractor due diligence
Chicago, ILUSAStrong financial services + trades coverage
Houston, TXUSAEnergy services, HVAC, roofing — high storm-claim volume
Dallas–Fort Worth, TXUSADefault keyword + location for trades lead-gen
Phoenix, AZUSAHVAC capital of the US; pairs cleanly with the Arizona ROC scraper
Atlanta, GAUSALogistics, moving, home services — high complaint-investigation use
Miami, FLUSAReal estate services, hurricane-zone contractors
Seattle, WAUSAPairs with the Washington L&I contractor scraper
Denver, COUSAPairs with the Colorado professional license scraper
Boston, MAUSAProfessional services, education-adjacent
Washington, DCUSAGovernment-services adjacent companies
Toronto, ONCANLargest Canadian metro; default country: "CAN" test
Vancouver, BCCANWest-coast trades + property management
Montréal, QCCANFrench-language listings still parse cleanly
Calgary, ABCANEnergy services + home builders
Ottawa, ONCANFederal-services adjacency
Edmonton, ABCANTrades, contractors

The country input toggles between USA and CAN; the location input accepts city + state/province, state/province alone, or ZIP / postal code.


Cost & Performance

MetricValue
EnginePlaywright Chromium (headed mode under xvfb) + Cheerio
Auth requiredNone (no BBB account, no API key)
Proxy requiredRecommended for production runs (RESIDENTIAL group)
ConcurrencyDefault 1; max 3 — BBB rate-limits aggressively
Memory footprint1024 MB minimum, 4096 MB cap (browser overhead)
Search-only runtime~5–10 seconds per 20-result page
Detail-enriched runtime~5–10 seconds per business profile (add requestDelay)
Data freshnessLive at run time — exactly what BBB serves the moment you scrape
Pricing modelPay-per-event (transparent per-record pricing)
Cost per 100 search-only recordstypically pennies
Cost per 100 fully enriched recordsvaries with requestDelay and proxy use
Output formatsJSON, CSV, Excel, HTML, XML, RSS, JSON Lines

Tuning tip: if you only need name + rating + accreditation + city for lead scoring, leave scrapeDetails: false. You will get 20× the throughput. Flip to true only for the high-value records you actually need to enrich.


  • Public data only — every field this actor returns is published on www.bbb.org and visible to any visitor without login
  • No PII beyond business listingsownerName is the public principal contact the business itself filed with BBB
  • No PHI — BBB is a business directory, not a healthcare system; no patient data is in scope
  • No SSNs, DOBs, or financial credentials are extracted or available
  • Email addresses are pulled from publicly displayed mailto: links and Cloudflare-obfuscated data-cfemail attributes that BBB has chosen to display; share-link mailto:?body= URLs are explicitly filtered out
  • Robots & ToS — review BBB's Terms of Use before commercial redistribution of the data; the actor is provided as a self-service tool for the operator to use within those terms
  • Rate limits — the actor's default requestDelay and maxConcurrency are intentionally conservative to minimize load on BBB's infrastructure
  • GDPR / CCPA / CASL — compliance with downstream marketing, telemarketing, and email regulations (CAN-SPAM, TCPA, CASL, GDPR) is the responsibility of the data consumer; BBB profile contact info is not consent to be marketed to
  • No bulk redistribution of BBB's proprietary rating methodology is intended; the actor surfaces the rating value, not BBB's underlying algorithm
  • Compliance use cases are explicitly supported — vendor onboarding, KYB, and risk monitoring are well within reasonable commercial use of public directory data

Important: BBB data may not be used for unlawful purposes including identity fraud, stalking, harassment, or coordinated review manipulation. Use the data as a trust signal, not as a substitute for direct due diligence.


Frequently Asked Questions

How fresh is the data?

Live at run time. Every record reflects exactly what BBB.org was serving at the moment the actor scraped it. There is no cache layer between you and BBB — if a rating changed an hour ago, the next run reflects it.

Does the actor handle BBB's Cloudflare protection?

Yes. That is the single biggest technical lift this actor solves. It launches a real Chromium browser in headed mode under Apify's xvfb display, applies stealth init scripts (navigator.webdriver = undefined, window.chrome.runtime stub), and waits up to 30 seconds per page for the Cloudflare challenge to clear before extracting HTML.

Do I need a BBB account or API key?

No. BBB does not publish a public API. This actor scrapes the public website that any visitor can browse, without login.

Do I need proxies?

For small runs (under ~30 businesses) you can run without proxies and usually succeed. For anything larger, or for production reliability, residential proxies are strongly recommended. Pass proxyConfiguration: { useApifyProxy: true, apifyProxyGroups: ["RESIDENTIAL"] } in your input.

How many records will I get per run?

You control it with maxResults (default 100, set 0 for unlimited) and maxPages (default 10, each page = ~20 results). BBB's own pagination caps deep results in any single query; if you need very large datasets, split the query across multiple searchUrls (different keyword × location pairs).

Does this work for Canada?

Yes. Set country: "CAN" and pass a Canadian location (e.g. "Toronto, ON", "Vancouver, BC", "Montréal, QC"). The actor follows BBB's find_country=CAN URL pattern automatically.

Does it scrape BBB complaints in full text?

It extracts complaint counts — total, last-3-years, last-12-months, resolved — directly from the profile page. Full complaint narratives are not included by default; BBB shows them on separate paginated sub-pages and they fall outside the schema.

Does it include customer reviews?

Review count and average rating are included. Individual review text is not in the dataset schema.

Can I filter to BBB Accredited businesses only?

Yes — set accreditedOnly: true and the actor drops any listing that explicitly marks "Not BBB Accredited".

How do I sort by rating?

Set sort: "Rating". Other valid values are Relevance (default), Distance, and Name.

Can I run multiple keyword × location queries in one run?

Yes — provide an array in searchUrls. Each URL is walked independently up to maxPages and the results are merged into a single dataset.

Can I use this on the Apify Free Plan?

Yes — every feature works on the free tier. Test with maxResults: 5 to validate your filters before committing to a larger run.

Can I schedule it?

Yes. Apify's built-in Scheduler supports any cron expression. Common schedules:

  • Daily watchlist refresh for your CRM accounts
  • Weekly TAM rebuild for your territory teams
  • Monthly competitor delta diff

Does the actor deduplicate across pages?

Yes. The actor maintains an internal Set keyed on the canonical profile URL and drops duplicates as they appear. Sub-pages (/details, /customer-reviews, etc.) are stripped down to the canonical profile before deduping.

Will it pick up paid ad listings?

No. Search-card links that route through doubleclick.net, adclick, or googleads are filtered out before reaching the dataset.

What if a profile is missing some fields?

The schema is stable — fields that aren't present on a given profile come back as null. This makes downstream ingestion (warehouse, CRM, BI) trivial because the column set never changes between runs.

Why is maxConcurrency capped at 3?

BBB rate-limits aggressively. Running more than 1–3 concurrent browser pages from the same IP almost always triggers temporary blocks. The actor's design favors single-thread + jittered delay + residential proxies over raw parallelism.

Are NAICS codes included?

Not directly — BBB exposes business categories as free text, not NAICS. The categories field is an array of those category strings, which you can map to NAICS in your downstream pipeline.

Can I export to CSV?

Yes — JSON, CSV, Excel, HTML, XML, RSS, and JSON Lines are all available from the Apify dataset view or the dataset items endpoint.

How do I report a bug or request a feature?

Open an issue on the Apify Store actor page or contact the developer directly through the Apify Console. PRs welcome via the Apify version sync.


BBB data is most powerful when joined to other public-business datasets. These sibling actors are commonly used alongside this one for B2B lead generation, KYB, contractor vetting, compliance monitoring, and journalism workflows:

Pattern: pull a BBB dataset for a category + metro, then enrich with the matching state-licensing actor on licenseNumbers or ownerName, then enrich with SAM.gov on entity name. You get a three-source view of every business in your TAM — public reputation (BBB) + regulatory licensure (state board) + federal contracting (SAM.gov) — in three actor runs.


Comparison vs. Alternatives

ApproachSetup timeHandles CloudflareSchema normalizationCost per 1K recordsCompliance log
This actor< 1 minute✅ Built-in headed Playwright + stealth + CF wait loop✅ Flat JSON, stable columnsPennies on pay-per-event✅ Automatic
Manual BBB browsingHours per session✅ Human user❌ Copy/paste hellFree + your hourly rate❌ None
requests / axios script1 hour to fail❌ 403 from CloudflareDIYFree + your time❌ None
Headless Puppeteer / Playwright DIY2–3 days to MVP, ongoing⚠️ Partial — easily detected without xvfb tricksDIYInfra + dev time❌ None
Paid "BBB data" resellerDays of contracting$500–2,000+/mo + per-recordVaries
BBB partner APISales cycleEnterprise pricing only

Why Pay-Per-Event Pricing?

Most scraping tools charge a flat monthly subscription (you pay even if you don't use it) or per-Compute-Unit (unpredictable). This actor uses pay-per-event, which means:

  • ✅ You only pay when the actor runs and produces records
  • ✅ Charges scale with how much BBB data you actually consume
  • ✅ Transparent, line-item billing inside Apify
  • ✅ No monthly minimums and no seat licenses
  • ✅ Free to evaluate — sample with maxResults: 5 for pennies
  • ✅ Predictable unit economics that map directly to your lead cost or risk-monitoring budget

Changelog

VersionDateNotes
1.02026-05Initial public release — headed Playwright + Cloudflare bypass, USA + Canada coverage, search-card and full-detail extraction, BBB rating + accreditation + complaints + reviews + owner + license numbers + social media, pay-per-event pricing

Keywords

BBB scraper · Better Business Bureau data · Better Business Bureau scraper · BBB.org scraper · BBB business profile API · BBB API alternative · BBB data extraction · BBB rating extractor · BBB accreditation scraper · BBB accredited business data · BBB complaints data · BBB complaint counts scraper · BBB reviews scraper · BBB owner lookup · BBB license number scraper · BBB lead generation · B2B business directory scraper · contractor reputation lookup · contractor vetting API · roofing contractor leads BBB · HVAC leads BBB · plumber leads BBB · electrician leads BBB · auto dealer reputation lookup · moving company complaints scraper · BBB letter grade scraper · A+ accredited business scraper · BBB rating downgrade alert · KYB enrichment BBB · vendor onboarding BBB · BBB Canada scraper · BBB USA scraper · BBB Toronto scraper · BBB Dallas scraper · BBB Houston scraper · BBB Phoenix scraper · BBB Los Angeles scraper · BBB New York scraper · BBB Chicago scraper · BBB Atlanta scraper · BBB Miami scraper · small business credit signal · business reputation monitoring API · reputation monitoring scraper · M&A due diligence small business · investigative journalism BBB data · consumer protection data · franchise reputation monitoring · multi-location brand monitoring BBB · Apify BBB actor · Playwright Cloudflare bypass scraper · headed Chromium BBB scraper · BBB scheduled scraper


Support

  • 🐛 Bug reports: Use the Issues tab on the Apify Store actor page
  • 💡 Feature requests: Same place — please describe your use case so we can prioritize
  • 📧 Direct contact: Through the Apify developer profile

If this actor saves you time, a 5-star rating on the Apify Store helps other B2B, compliance, journalism, and reputation-monitoring teams discover it. Thank you!