locaihost data

Data recipe

20 Chicago movers on BBB in 3 minutes for 4 cents: every one is A+, so here is what actually separates them

We pulled the first 20 movers BBB shows for Chicago, with their grades, review stars, complaint counts and the latest complaints. All 20 are accredited and A+. The useful columns are the ones under the grade: complaint volume, review depth and whether complaints end up resolved.

Search BBB for movers in any big city and you get a page of A+ badges. That's a problem if you're trying to compare them, because a grade that everyone has can't tell you who to pick.

So we pulled the data under the badge. One run of our BBB Reviews Scraper on Apify, searching "movers" near Chicago, IL, opening each business and reading its five newest complaints:

  • Time: 194 seconds.
  • Cost: $0.037 of compute on our side. A user pays $0.50 per 1,000 rows on the Starter tier, and this run returned 77 rows, so it's about 4 cents for anyone else.
  • Coverage: 20 businesses (one row each), 20 summary rows and 37 complaints filed between November 2023 and October 2026.

Every number below comes from that one run. Complaints are written by members of the public, so this post shows counts only: no names and no quotes.

The input

JSON
{
  "searchQueries": ["movers"],
  "searchLocation": "Chicago, IL",
  "maxBusinessesPerSearch": 20,
  "detailsForFoundBusinesses": true,
  "maxReviewsPerBusiness": 0,
  "maxComplaintsPerBusiness": 5,
  "includeSummary": true
}

From Python:

python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("locaihost/bbb-reviews").call(run_input={
    "searchQueries": ["movers"],
    "searchLocation": "Chicago, IL",
    "maxBusinessesPerSearch": 20,
    "detailsForFoundBusinesses": True,
    "maxReviewsPerBusiness": 0,
    "maxComplaintsPerBusiness": 5,
    "includeSummary": True,
})
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
businesses = [r for r in rows if r["type"] == "business"]
complaints = [r for r in rows if r["type"] == "complaint"]

A business row has the BBB grade, accreditation and the date it started, years in business, review stars and count, complaint counts for the last 3 years and the last 12 months, category, licences and alerts. A summary row is worked out from what the run read: complaints by month, resolved and answered shares, and the median days a business takes to respond. You can also pass business profile links directly instead of searching, or add maxReviewsPerBusiness to pull the reviews themselves.

Finding 1: the grade doesn't separate anyone

All 20 businesses BBB returned for this search are accredited and graded A+. We didn't filter for that (the input has accreditedOnly and minGrade and both were left off), so this is simply what the first page of a Chicago search looks like.

The A+ covers very different businesses: years in business range from 4 to 146 (median 29), and the 20 include long-distance van lines, local crews, office movers, a storage company and a document shredding firm that BBB files under moving and storage.

Finding 2: the review stars underneath are thin or harsh

Review count on BBBBusinesses
None5
1 or 26
3 to 126
41 to 822
2,8241

11 of the 20 have two reviews or fewer, so their star rating is close to meaningless. Where there is depth, it doesn't always flatter: one national van line has 1.17 stars from 41 reviews and another national brand has 3.67 stars from 2,824 reviews, both under an A+ grade. The best-supported strong score is a local mover with 4.8 stars from 82 reviews.

BBB grades are built mostly from how a business handles complaints, its time in business and its licensing, not from review stars. That's why the two numbers can sit so far apart.

Finding 3: complaint volume is very uneven

The 20 businesses have 1,663 complaints between them over the last 3 years. One national brand's profile holds 1,563 of them (94%). Eight businesses have none at all.

That needs care before you compare. The two biggest complaint counts belong to national companies whose BBB profile is their headquarters (one in Texas, one in Indiana), so the count covers every city they work in, not just Chicago. A local mover with 11 complaints in 3 years and a national chain with 1,563 aren't on the same scale. Divide by reviews or by size, or compare locals with locals.

Finding 4: everyone replies, few complaints end resolved

We read the five newest complaints for every business that had any: 37 complaints across 12 businesses.

Complaint typeCount
Service or repair issues15
Order issues9
Delivery issues5
Billing issues3
Product issues3
Sales and advertising issues2

Every one of the 37 has a reply from the business, and the median reply came 3 days after the complaint was filed (24 of the 37 within a week, the slowest after 35 days). But only 7 of the 37 are marked Resolved. The other 30 are Answered, which on BBB means the business replied and the customer didn't confirm the problem was fixed.

So the reply rate is 100% and tells you nothing, while the resolved share (19% here, from 0% to 100% per business) is where businesses differ. That column, plus complaints in the last 12 months, is what we'd sort by.

What it doesn't do

  • It reads what a logged-out visitor sees on BBB. A search shows at most 225 businesses; for more, the Actor splits the search by ZIP code or nearby city (maxSplitSearches).
  • It doesn't add people's names. Complaint rows carry the type, status, dates, text and the business's reply.
  • Five complaints per business is a small sample. For a real benchmark, raise maxComplaintsPerBusiness or turn on benchmarkCompetitors, which ranks each business against up to 25 local rivals in the same category.

Try it

The Actor is locaihost/bbb-reviews on the Apify Store: $0.50 per 1,000 rows (reviews, complaints and businesses) on the Starter tier, cheaper on the higher tiers. It covers the US and Canada, and works from AI agents through Apify's MCP server, so "find roofers in Dallas with an A grade and fewer than 3 complaints this year" is one tool call away.

If you run it and something looks wrong, open an issue on the Actor page and we'll fix it the same day.