BBB Scraper icon

BBB Scraper

Scrape bbb.org (Better Business Bureau, USA & Canada) business profiles: BBB rating, accreditation, contact and lead-gen data (decoded email, phone,…

Start using this actor on Apify ↗Need a custom scraper?Contact us ↗

BBB Scraper at a glance

BBB Scraper is a ready-to-run Apify actor from abotapi for collecting lead generation data. Its documented output includes business name, change type (incremental mode), bbb rating, bbb score (0-100) and accredited, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $2.00 per 1,000 results on the Apify Free plan and from $1.20 on paid plans, with smaller per-run or optional feature charges listed on Apify.

Runs on
Apify cloud: console, API, schedules and integrations
Data type
Lead Generation, Developer Tools, Automation
Pricing
$2.00 per 1,000 results (Free plan), from $1.20 on paid plans
Output
Documented below · JSON, CSV, Excel
Inputs
35 options

Scrape bbb.org (Better Business Bureau, USA & Canada) business profiles: BBB rating, accreditation, contact and lead-gen data (decoded email, phone, website, socials, owner), address + coordinates, business type, years in business, licenses, hours, plus opt-in customer reviews and complaints..

What BBB Scraper can do

  • Two ways to find businesses. Search by business term plus location, or paste BBB search-result, category and business-profile links, mixed in one run.
  • Past BBB's 225-result view. BBB shows at most 15 pages per search however many businesses match; Maximize coverage walks the same search in BBB's other sort orders to reach the businesses the first order never shows, each still returned and billed once.
  • Decoded contact details. BBB scrambles published email addresses against harvesters; this actor returns the plain address, and leaves it empty when the business truly has not published one.
  • Full profile depth. Rating, accreditation, owner, address with coordinates, business type, years in business, licenses, operating hours, service areas and the full category tree.
  • Optional reviews and complaints. Turn on a per-business add-on to also pull customer reviews and complaints, each paginated up to a per-business page cap you set (0 walks every page).
  • Resume or monitor on a schedule. Continue one interrupted crawl by run id, or turn on Incremental mode so recurring runs return only new and changed businesses.

Choose what to collect

These inputs let you configure BBB Scraper - Business Ratings, Reviews, Complaints & B2B Leads. Open the actor on Apify to enter your values and review the current options.

Supported input fields
InputWhat it controls
modestring · requiredChoose 'search' to run business-term + location searches with filters, or 'url' to scrape pasted BBB search-result pages and business-profile URLs (both are auto-detected and can be mixed).

Choices: search, url

searchTermsarrayOnly used when mode = search, ignored in url mode. Business category or keyword terms to search on BBB, e.g. "plumber", "roofing", "hvac". Each term is combined with the location below and searched separately.
searchstringAPI alias merged into Business terms.
searchesarrayAPI alias merged into Business terms.
locationstringCity + state (US) or city + province (Canada) to search within, e.g. "Los Angeles, CA" or "Toronto, ON". A ZIP / postal code also works. Leave empty for a nationwide search of the selected country. To search several places in one run, add them under "More locations" below.
locationsarrayOptional. Extra cities, states/provinces or ZIP/postal codes to search in the same run, e.g. "San Diego, CA", "90210". Every business term is searched in the Location above AND in each of these; a business found by more than one search is returned (and billed) once. Search mode only.
countrystringCountry to search within. Covers the USA and Canada.

Choices: USA, CAN

Show 28 more inputs
More input fields
InputWhat it controls
sortstringOrder of search results, applied by BBB itself.

Choices: Relevance, Rating, Distance, AToZ, ZToA

distanceintegerLimit results to businesses within this many miles of the location (BBB's own distance filter; needs a Location). Leave empty for BBB's default radius.
accreditedOnlybooleanOnly return BBB-accredited businesses; non-accredited results are skipped and not billed. Applies to keyword searches (BBB filters those itself) and pasted search-result URLs; a directly pasted profile URL is always returned.
minRatingstringOnly return businesses rated at least this BBB letter grade (e.g. "B" keeps A+ through B, and drops B- and below). Businesses BBB has not rated (NR) are skipped. Leave empty for every rating. Applies to keyword searches and pasted search-result URLs; skipped businesses are not billed.

Choices: A+, A, A-, B+, B, B-, C+, C, C-, D+, D, D-, F

categorystringOptional. Narrow each search to one BBB business category, by name (e.g. "Commercial Plumber", "Drain Cleaning") or BBB category code (e.g. "10113-100"). A name is matched to BBB's own category filter for that search; if BBB doesn't offer it there, each business's own categories are matched instead. Search mode only.
stateFilterstringOptional 2-letter state or province code (e.g. "TX", "ON") applied by BBB itself. Most useful with an empty Location (a nationwide search). Search mode only.
requestQuoteOnlybooleanOnly return businesses that accept "Get a Quote" requests through BBB (BBB's own filter). Search mode only.
servesMyAreaOnlybooleanOnly return businesses BBB lists as serving the searched location, including ones based elsewhere (BBB's "Serving my Area" filter). Needs a Location. Search mode only.
onlyWithComplaintsbooleanOnly return businesses that have at least one complaint on file with BBB (useful for reputation research). BBB's search does not offer this filter, so each business's profile is opened to read its complaint count; businesses without complaints are skipped and not billed, so a run may return fewer than Max businesses. Works in Search and URL mode.
startUrlsarrayOnly used when mode = url, ignored in search mode. Paste BBB search-result pages (https://www.bbb.org/search?... , filters and page= all work) or direct business-profile URLs, USA (https://www.bbb.org/us/ca/los-angeles/profile/plumber/fords-plumbing-1216-100081178 ) or Canada (https://www.bbb.org/ca/on/toronto/profile/house-cleaning/custom-maids-incorporated-0107-1151951 ), with or without a trailing slash, a /customer-reviews or /complaints suffix, or tracking params. BBB category pages (https://www.bbb.org/us/ca/los-angeles/category/plumber , also state-, country- and Canada-level) work like a search. Search, category and profile URLs are auto-detected and can be mixed in one run.
maxItemsintegerHard cap on the number of business profiles returned across the whole run. This is the run's cap. Maximum 100,000; 0 = up to the maximum of 100,000.
maxPagesPerQueryintegerMaximum result pages walked per search term / pasted search or category URL (15 businesses per page). Leave empty or use 0 for up to 100 pages: the run then stops at Max businesses, at BBB's own last page (BBB shows at most 15 pages per sort order; see Maximize coverage) or at 100 pages, whichever comes first. Values above 100 are treated as 100.
maximizeCoveragebooleanBBB shows at most 15 pages (225 businesses) per search, whatever the total it reports (e.g. 7,000+ plumbers in Los Angeles). When a search or pasted search/category URL is cut off this way, also walk it in BBB's other sort orders (A-Z, Z-A, Rating, Distance) to reach businesses the first order never shows. Each business is still returned and billed once. Off by default.
scrapeReviewsbooleanAlso collect each business's customer reviews (rating, author, text, date, business response), paginated up to Max review pages. Adds the reviews & complaints surcharge per business. 💲 Turning this on charges the detail-enrichment event (billed as "Reviews & complaints") once per business returned, including businesses that turn out to have none, PLUS one more detail-enrichment event per started block of 10 reviews delivered on that business (1–10 reviews = 1, 11–20 = 2, 50 = 5). Limit it with Max reviews per business.
scrapeComplaintsbooleanAlso collect each business's complaints (type, status, date, text, response count), paginated up to Max complaint pages. Adds the reviews & complaints surcharge per business. 💲 Turning this on charges the detail-enrichment event (billed as "Reviews & complaints") once per business returned, including businesses that turn out to have none.
maxReviewPagesintegerCap on review pages pulled per business (~10 reviews per page). Only used when "Scrape customer reviews" is on. 0 = up to 100 pages; values above 100 are treated as 100. The walk still stops earlier at the last review page BBB reports.
maxComplaintPagesintegerCap on complaint pages pulled per business (~10 complaints per page). Only used when "Scrape complaints" is on. 0 = up to 100 pages; values above 100 are treated as 100. The walk still stops earlier once every complaint BBB counts for the business has been collected.
maxReviewsPerBusinessintegerHard cap on reviews collected per business, on top of "Max review pages per business", whichever limit is hit first stops the walk. Only used when "Scrape customer reviews" is on. Default 20 (raise it for more reviews per business). Maximum 1,000; 0 = up to the maximum of 1,000 (page cap still applies). 💲 Reviews are billed in blocks of 10 delivered reviews: each started block of 10 charges one extra detail-enrichment event on top of the per-business charge (e.g. 50 reviews = 5 extra events), so this cap also caps the review charge.
maxComplaintsPerBusinessintegerHard cap on complaints collected per business, on top of "Max complaint pages per business", whichever limit is hit first stops the walk. Only used when "Scrape complaints" is on. Default 20 (raise it for more complaints per business). Maximum 1,000; 0 = up to the maximum of 1,000 (page cap still applies). Complaints are not billed per complaint.
resumeFromRunIdstringPaste a previous run ID or dataset ID to continue a large crawl of businesses without returning or charging for businesses already collected there. Use this after an interrupted run, or when continuing a business list pull in another run. For recurring daily monitoring of the same search, use Incremental mode below instead.
incrementalModebooleanTurn this on for daily or recurring monitoring. The first run returns all matching businesses as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED businesses. Turn on "Emit unchanged" or "Emit expired" only when you also want those businesses returned (and billed). State is kept separately for each search/URL and reviews/complaints setup; use State key when you want to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.
stateKeystringOptional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the search/URL and detail settings, different searches then never mix state with each other.
emitUnchangedbooleanOff by default. Turn on to also return businesses that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want the full snapshot every run.
emitExpiredbooleanOff by default. Turn on to also return businesses that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search, not when Max businesses capped it, not when Max result pages capped it, and not when Resume was used. Leave BOTH "Max businesses" and "Max result pages" empty for the run that should detect expiries. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.
ignoreFieldsForChangesarrayOutput field names that should NOT make a business count as UPDATED (incremental mode only). Use a plain field name (e.g. "logoUrl") to ignore a whole top-level field, or a dotted path (e.g. "complaints.respondedAt") to ignore just that nested field inside every item of a list like reviews/complaints/categoryTree. Ignored fields are still returned in the output and never removed from it, this only controls what counts as a change. searchKeyword, searchLocation and localProfileUrl (which of your searches, and which local branch listing, found the business) never count as a change, so a business reached by a different term, location or branch is not reported as UPDATED.
mcpConnectorsarrayOptionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write/digest. Leave empty to skip; never changes the dataset output.
notionParentPageUrlstringURL or id of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.
maxNotifyListingsintegerCap on items written to each connector per run. Does not affect the dataset.

Fields in the output

The documented dataset includes the fields below. Availability can depend on the source page and selected mode.

nameBusiness name
changeTypeChange type (incremental mode) (text)
bbbRatingBBB rating
ratingScoreBBB score (0-100) (number)
isAccreditedAccredited (boolean)
primaryCategoryCategory
categoriesAll categories (array)
phonePhone
emailEmail (decoded)
websiteWebsite (link)
ownerNameOwner / principal
cityCity
Show 67 more fields
stateCodeState
zipCodeZIP
yearsInBusinessYears in business
reviewsTotalReviews
complaintsTotalComplaints
complaintResolutionRateComplaint resolution rate (percentage)
searchKeywordSearch term
searchLocationSearch location
bbbIdBBB ID
businessIdBusiness ID
profileUrlProfile URL (link)
scrapedAtScraped at (date)
changedFieldsChanged fields (incremental mode) (array)
firstSeenAtFirst seen (incremental mode) (date)
lastSeenAtLast seen (incremental mode) (date)
additionalPhonesAdditional phones (array)
additionalEmailsAdditional emails (array)
faxNumbersFax numbers (array)
socialProfilesSocial profiles (array)
ownerTitleOwner title
streetAddressStreet address
addressLine2Address line 2
countryCodeCountry
formattedAddressFormatted address
latitudeLatitude (number)
longitudeLongitude (number)
serviceAreasService areas (array)
serviceAreaDescriptionService area (business statement)
hasServiceAreaHas a service area (boolean)
businessTypeBusiness type
entityTypeEntity type
businessStartDateBusiness start date (date)
incorporatedDateIncorporated date (date)
numberOfEmployeesNumber of employees (number)
isOutOfBusinessOut of business (boolean)
categoryTreeCategory tree (array)
hoursHours (array)
licensesLicenses (array)
logoUrlLogo URL (link)
contactsContacts (array)
additionalWebsitesAdditional websites (array)
requestQuoteUrlGet a Quote form (link)
isHeadquartersHead office (boolean)
accreditationRevokedDateAccreditation revoked (date)
primaryCategoryIdPrimary category code
categoryIdsCategory codes (array)
averageReviewRatingAverage review rating (number)
reviewsUrlReviews URL (link)
reviewsCollectedReviews collected (number)
reviewsreviews
idReview/complaint ID
authorReviewer
ratingRating (number)
dateDate (date)
textText
businessResponseBusiness response
businessResponseDateBusiness response date (date)
businessRebuttalBusiness rebuttal
customerResponseCustomer response
complaintsClosedLast3YearsComplaints closed (3 yrs) (number)
complaintsClosedLast12MonthsComplaints closed (12 mo) (number)
complaintsUrlComplaints URL (link)
complaintscomplaints
typeType
statusStatus
responsesResponses (array)
responseCountResponse count (number)

Example output

An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.

{
  "name": "Example Plumbing Co.",
  "alternateNames": [
    "Example Plumbing Co., LLC"
  ],
  "businessId": "0825-1000000000",
  "bbbId": "0825",
  "bbbOfficeName": "BBB Heart of Texas",
  "profileUrl": "https://www.bbb.org/us/tx/austin/profile/plumber/example-plumbing-co-0825-1000000000",
  "bbbRating": "A+",
  "isAccredited": true,
  "accreditedDate": "2024-01-16",
  "phone": "(555) 010-0100",
  "email": "info@example.com",
  "website": "https://www.example.com/",
  "ownerName": "Jane Doe",
  "ownerTitle": "Owner/Manager",
  "contacts": [
    {
      "name": "Jane Doe",
      "title": "Owner/Manager",
      "isPrincipal": true,
      "isManagement": true
    }
  ],
  "requestQuoteUrl": "https://www.bbb.org/heartoftexas/quote/request-example-plumbing-co-1000000000",
  "isHeadquarters": false,
  "streetAddress": "100 Example St",
  "city": "Austin",
  "stateCode": "TX",
  "zipCode": "78701",
  "formattedAddress": "100 Example St, Austin, TX 78701",
  "countryCode": "US",
  "latitude": 30.27,
  "longitude": -97.74,
  "serviceAreas": [
    "Travis County, TX",
    "Williamson County, TX"
  ],
  "primaryCategory": "Plumber",
  "categories": [
    "Plumber",
    "Plumbing Renovation",
    "Commercial Plumber"
  ],
  "businessType": "Limited Liability Company (LLC)",
  "yearsInBusiness": 3,
  "licenses": [
    {
      "licenseNumber": "44648",
      "expirationDate": "2026-11-30",
      "agencyName": "Texas State Board of Plumbing Examiners",
      "agencyPhone": "800-8456584"
    }
  ],
  "hours": [
    {
      "day": "M",
      "hours": [
        {
          "opens": "07:00",
          "closes": "16:00"
        }
      ],
      "note": null
    }
  ],
  "reviewsTotal": 1,
  "averageReviewRating": 1,
  "complaintsTotal": 0,
  "complaintResolutionRate": null,
  "socialProfiles": null,
  "reviews": null,
  "reviewsCollected": null,
  "complaints": null,
  "logoUrl": "https://m.bbb.org/prod/ProfileImages/2024/1f7a8bd4-fdd2-45ca-8963-5c246e1d3b85.png",
  "scrapedAt": "2026-01-01T00:00:00Z",
  "changeType": "NEW",
  "changedFields": [],
  "firstSeenAt": "2026-01-01T00:00:00Z",
  "lastSeenAt": "2026-01-01T00:00:00Z"
}

Ways to use this data

  • Lead generation: pull business name, decoded email and phone, website, owner and address for every plumber, roofer or HVAC company in a city.
  • Reputation monitoring: track a business's BBB rating, accreditation, complaint volume and resolution rate over time.
  • Compliance and licensing checks: collect license numbers, issuing agency and expiration dates alongside years in business and entity type.
  • Customer feedback analysis: read customer reviews and complaints together with the business's own responses.
  • Recurring portfolio monitoring: schedule the same search or URL list and use Incremental mode to see only what changed since the last run.

Before you run

Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.

Questions about this actor

What data does BBB Scraper return?

The documented output for BBB Scraper includes business name, change type (incremental mode), bbb rating, bbb score (0-100), accredited, category, all categories and phone. Availability of each field depends on the source page and the selected mode.

How much does BBB Scraper cost?

It costs $2.00 per 1,000 results on the Apify Free plan and from $1.20 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.

Can I get only new or changed businesses on a schedule?

Yes. Schedule the actor and turn on Incremental changes for scheduled runs. The first run returns everything as NEW; later runs return only NEW and UPDATED businesses by default. Turn on Emit unchanged or Emit expired only if you also want unchanged or disappeared businesses returned (and billed). EXPIRED needs a complete, uncapped scan; REAPPEARED only shows up for a business an earlier complete run had already marked EXPIRED.

What is the difference between Resume and Incremental mode?

Resume (resumeFromRunId) continues one specific interrupted run so you do not pay twice for businesses it already collected. Incremental mode is for running the same search or URL list again and again on a schedule and getting only what changed. You can combine them, but only to bootstrap a brand-new monitoring campaign that has no saved state yet: the resumed businesses are seeded into the campaign's baseline as already present. Once a campaign has saved state, a run with Resume set fails with an error telling you to remove it or pick a different State key.

Why do I get at most 225 businesses for a big search?

BBB itself shows at most 15 pages of 15 businesses for any one search and sort order, even when it reports thousands of matches (7,000+ plumbers in Los Angeles). Turn on Maximize coverage to walk the search again in BBB's other sort orders, add more locations (nearby cities or ZIP codes), or narrow it with a Category filter. A search BBB cut off this way is never treated as a complete scan, so Incremental mode will not mark the businesses beyond the cut as EXPIRED.

Why did my run fail instead of returning an empty dataset?

If BBB did not return any readable page for the entire run, even after the actor automatically tried every available connection, it stops with a clear error rather than reporting "no businesses found", so a real block is never confused with a genuinely empty search. Try again in a few minutes. If only some pages could not be read, the run still returns what it found, with a warning that the results may be incomplete.

Ready to collect with BBB Scraper?

Run it on Apify with your own input and export the results as JSON, CSV or Excel.