Local Business Qualifier with Sources avatar

Local Business Qualifier with Sources

Pricing

Pay per usage

Go to Apify Store
Local Business Qualifier with Sources

Local Business Qualifier with Sources

Find Google Maps businesses, qualify ratings and review counts, check websites, and report evidence-backed ownership. Unverifiable Google post freshness stays unknown.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Korado Labs

Korado Labs

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Categories

Share

Evidence-first Google Maps discovery and qualification. Early release, version 0.3. Bounded discovery and evidence-backed qualification; missing evidence is never treated as a pass or fabricated as fact. Coverage varies by business, location and Google interface; this is not a guarantee of exhaustive or error-free results.

What it does

  • Searches Maps or accepts direct Google Maps place URLs; bounded discovery, scrolling and CID/place-ID deduplication, up to 100 businesses per run. Queries receive a fair first share; duplicate/unused shares are refilled.
  • Reads rating and exact review count from the place header, with a location-ID-checked public page-state fallback adapted from the MIT-licensed gosom parser. No rounded count is used to make a threshold decision.
  • Checks public business websites and a bounded number of same-site about/ownership/franchise pages, recursively prioritized from every fetched page. A 45-second per-site budget preserves partial evidence. Honors robots.txt before each redirect destination and stops at access challenges. A fresh isolated browser can retry HTTP 403/transport failures or render JS-only pages, with DNS-pinned public-network egress, byte/time limits, no login and no CAPTCHA bypass. A 429 rate limit is not retried.
  • Classifies this location as franchise/corporate/independent only when an explicit first-party statement is found. Franchising offered by the brand is a separate nullable field, not a claim about a location.
  • Reads actual Maps “From the owner” previews and expanded owner-post cards before falling back to Search. Expanded cards must match the exact 64-bit business CID and business author; customer updates are excluded. Search cards must match the location feature ID. A per-browser-session 15-minute circuit breaker stops repeated Search attempts after a challenge. Relative dates are intervals, not fabricated exact publication timestamps.
  • Returns qualified, rejected, or unknown, per-check decisions, quotes, URLs and observation timestamps. Unknown JSON values are null and CSV cells are blank. Does not invent a score or fill missing ownership from brand names.

Important limits

Google frequently changes its UI. Search is ranked and location-dependent, not an exhaustive census. Unexposed posts remain not_exposed, never "no posts." maxPostAgeDays passes only with a definitely recent observed profile post; old/missing/ambiguous posts produce unknown, never a false pass or definitive inactivity claim. latestObservedPostAt is populated only for exact timestamps. Post date bounds are in each posts[] item.

Ownership rules intentionally favor low recall over false positives. "Family owned," "independently operated," a franchise link, or many locations is not enough. Website reachability is not a design, accessibility or SEO assessment. A domain's marketing statements are evidence claims, not independent legal ownership records. Sitewide or multi-location statements may be insufficient for a specific branch; review sensitive decisions manually.

No CAPTCHA solver, login scraping or challenge bypass. The browser reports its real Chromium version and platform (only the "Headless" marker is removed, which otherwise makes Google omit review counts). An optional user-supplied proxy (proxyConfiguration) is supported. Native Maps owner cards are tried first; Google Search may still block requests, and a residential proxy is not a tested guarantee of complete post coverage. Blocked checks stay unknown. Use only where you have the right to collect the public data; review platform terms and applicable law before commercial operation.

Inputs

See examples/input.json and .actor/input_schema.json. Optional filters: minRating, maxRating, minReviews, maxReviews, maxPostAgeDays, requireWebsite, ownership. Unset means no filter. All active criteria must pass. An observed mismatch rejects; otherwise missing required evidence yields unknown. Each run is bounded by maxPlaces and maxRunSeconds.

Apify

The container's default command runs python -m local_qualifier with the official Apify SDK. Input comes from the default key-value store INPUT; results go to the default dataset and run diagnostics to SUMMARY. includeRejected=false pushes only qualified rows but keeps all counts in SUMMARY. No usable rows/all extraction failures/timeouts fail the Actor run with SUMMARY.

Apify Actor Y2c2vdTFSr02vGbJE uses version 0.3, tag latest. Update with apify login (your own token) and apify push in this folder.

Pay-per-event charging

The code charges these events only when they are priced in Apify Console:

EventWhen it is charged
qualified-leadA business passes every active filter and is saved
business-checkedOptional: every processed business, qualified or not

Rejected/unknown rows are free unless business-checked is priced. Do not price apify-default-dataset-item, or every rejected row is billed. Before charging anything, the Actor reserves the full price of the row; when a user's maximum charge cannot cover it, the run stops cleanly without billing a dropped lead. See docs/PRICING.md.

Self-hosted deployment

An optional Fly.io service is a separate deployment and is not updated when this Apify Actor is rebuilt. Its single-worker SQLite queue is not horizontally scalable. Self-hosted infrastructure incurs separate hosting costs.

Development and tests

python -m venv .venv
.venv/bin/pip install -r requirements-dev.txt -c constraints.txt
export PYTHONPATH=src:vendor
.venv/bin/pytest -q
# In your own development environment:
.venv/bin/playwright install chromium
.venv/bin/python -m local_qualifier examples/input.json output

For a managed browser/CDP test, set QUALIFIER_CDP_URL; the pipeline creates and closes only its own isolated context. Never include CDP credentials in artifacts.

The MIT-licensed Maps parser is pinned and attributed in THIRD_PARTY_NOTICES.md. Runtime package versions are pinned in requirements.txt; full environment locks and validation reports are included with the build.

See docs/HANDOFF.md for the actual cloud test results, access instructions and confirmed Google data-access limitations. A running service is not the same as production readiness: do not publish claims of reliable post/count coverage yet.