# Local Business Revenue Leak Finder (`herazur/local-business-revenue-leak-finder`) Actor

Find high-demand local businesses with website, booking, lead capture, and local SEO gaps. Scores Google Maps prospects using real market evidence and website analysis, then ranks the best agency outreach opportunities.

- **URL**: https://apify.com/herazur/local-business-revenue-leak-finder.md
- **Developed by:** [Furkan Toluç](https://apify.com/herazur) (community)
- **Categories:** Lead generation, SEO tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $40.00 / 1,000 business analyzeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Google Maps Agency Lead Scorer — Website & Booking Gaps

Find commercially established local businesses with visible website, booking, conversion, and local SEO opportunities.

This Apify Actor combines Google Maps demand signals, homepage-level website evidence, business-model-aware conversion checks, contactability, and deterministic scoring. It is an agency lead finder—not a generic Maps scraper, full website audit, or AI email generator.

### 1. What the Actor does

For each business query and location, the Actor:

1. Calls the existing `compass/crawler-google-places` Actor with a controlled place and spend limit.
2. Normalizes and deduplicates the returned Google Maps businesses.
3. Filters explicitly closed businesses and businesses below the minimum *known* review count.
4. Infers whether the business primarily needs appointments, quotes, reservations, phone calls, or a general conversion flow.
5. Safely fetches only the listed homepage, with SSRF checks, manual redirect validation, a timeout, and a response byte limit.
6. Detects deterministic CTA, contact, booking, mobile viewport, HTTPS, page identity, noindex, and structured-data evidence.
7. Produces separate opportunity and confidence scores, a service recommendation, and CONTACT / WATCH / SKIP decisions.
8. Saves ranked Dataset rows plus `OUTPUT` JSON and `REPORT.md` Key-value store records.

The result answers: **Which commercially established local businesses have the clearest, evidence-backed digital gap that an agency can realistically pitch?**

### 2. Who it is for

- Web design and conversion optimization agencies
- Local SEO agencies
- Appointment-booking and AI receptionist consultants
- Automation freelancers and independent web developers
- Teams doing Google Maps lead generation and local business prospecting

Typical use cases include web design leads, website audit leads, booking automation leads, local SEO leads, appointment booking opportunities, and conversion audit research.

### 3. How it works

```text
Input
  → Google Maps child Actor (one controlled run per query)
  → strict Maps adapter
  → evidence-aware filtering and deduplication
  → service-model inference
  → safe homepage fetch and deterministic HTML analysis
  → transparent scoring and decision engine
  → global ranking
  → Dataset + OUTPUT + REPORT.md
```

Raw upstream records never enter business or scoring logic directly. Only the adapter understands upstream field aliases. A missing source field remains unknown; it is never silently converted to `false` or `0`.

Website access errors, blocks, unsafe URLs, non-HTML responses, and unknown website fields do **not** become website deficiencies.

### 4. Input

```json
{
  "searchQueries": ["dentists"],
  "locationQuery": "Austin, Texas, USA",
  "maxBusinessesPerSearch": 25,
  "minimumReviews": 5,
  "includeBusinessesWithoutWebsite": true,
  "debug": false
}
```

| Field | Required | Default | Rules |
|---|---:|---:|---|
| `searchQueries` | Yes | — | 1–5 unique strings, 2–80 characters each |
| `locationQuery` | Yes | — | 2–120 characters |
| `maxBusinessesPerSearch` | No | `25` | 5–50 per query |
| `minimumReviews` | No | `5` | 0–10,000; only known counts are filtered |
| `includeBusinessesWithoutWebsite` | No | `true` | Keep explicit no-website prospects |
| `debug` | No | `false` | Adds safe adapter and scoring evidence; never secrets or raw HTML |

Homepage keyword, CTA, contact, and booking detection is English-first in this MVP.

### 5. Output

The default Dataset contains one globally ranked row per deduplicated business. Useful overview columns appear first: business, decision, opportunity, confidence, reviews, demand, digital gap, main gap, recommended service, website status, phone, website, and outreach angle.

Each record includes:

- Normalized Google Maps business evidence
- Matched source queries
- Inferred service model and inference evidence
- Homepage analysis status and observed signals
- Four component scores
- Opportunity and confidence scores
- CONTACT / WATCH / SKIP / INSUFFICIENT\_EVIDENCE decision
- Evidence-backed reasons, risks, primary gap, and service recommendation
- A concise outreach angle—not a generated cold email

`OUTPUT` contains a structured summary, safe run economics, query warnings, and top prospects. `REPORT.md` contains a human-readable summary and the top ten usable prospects.

### 6. Commercial Demand Score

This 0–100 score is a relative public Maps demand signal—not estimated revenue.

- Review strength: 65%
- Search rank: 20%
- Rating quality: 15%

Review strength combines 60% peer percentile within matched query results and 40% absolute log-normalized review count:

```text
absolute = clamp(log1p(reviews) / log1p(1000) × 100)
review strength = 60% peer percentile + 40% absolute
```

Rating maps approximately from 3.0 → 0 to 5.0 → 100. Rank starts at 100 for position 1 and declines progressively. Missing components are excluded and the remaining weights are re-normalized.

### 7. Digital Conversion Gap

Higher means more homepage-level conversion evidence is missing. An explicitly empty Maps website field scores 100. A successfully fetched homepage is evaluated for:

- Strong primary CTA: 20
- Contact action: 20
- Service-model-specific conversion action: 25
- Mobile viewport: 10
- HTTPS: 5
- LocalBusiness structured data: 10
- Page identity: 5
- Noindex: 5

Appointment businesses are checked for booking, quote businesses for a quote CTA or lead form, reservation businesses for reservation actions, and phone-first businesses for click-to-call. The model-specific component is excluded for a general business model.

Failed, blocked, unsafe, too-large, non-HTML, or unknown homepage evidence returns a `null` Digital Conversion Gap.

### 8. Confidence Score

Confidence is separate from opportunity:

- Google Maps source completeness: 45%
- Website evidence quality: 35%
- Service-model inference confidence: 20%

A complete Maps record with an explicitly empty website field can have high confidence. A failed homepage request sharply reduces confidence and never creates a fake gap.

### 9. CONTACT / WATCH / SKIP

- **CONTACT**: opportunity ≥ 75, confidence ≥ 65, demand ≥ 50, contactability ≥ 35, and usable core evidence.
- **WATCH**: opportunity ≥ 60, confidence ≥ 45, meaningful service fit, and usable evidence.
- **SKIP**: weak opportunity, weak demand, or no meaningful current service gap.
- **INSUFFICIENT\_EVIDENCE**: required source evidence is missing or homepage analysis failed while the conclusion depends on it.

All thresholds and weights are centralized and deterministic.

### 10. Example

```json
{
  "rank": 1,
  "decision": "CONTACT",
  "business": {
    "name": "Example Dental",
    "rating": 4.8,
    "reviewCount": 436,
    "phone": "+1...",
    "website": "https://example.com"
  },
  "website": {
    "status": "SUCCESS",
    "hasBookingAction": false
  },
  "opportunityScore": 80,
  "confidenceScore": 88,
  "mainGap": "No online booking action detected on the homepage",
  "recommendedService": "BOOKING_AUTOMATION",
  "outreachAngle": "Google Maps shows 436 reviews for this business, but no online booking action was detected on the homepage. A booking-flow audit may be relevant."
}
```

The values are illustrative. Production values are calculated only from observed evidence.

### 11. API and automation usage

JavaScript with the Apify API client:

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('YOUR_USERNAME/google-maps-agency-lead-scorer').call({
    searchQueries: ['dentists'],
    locationQuery: 'Austin, Texas, USA',
    maxBusinessesPerSearch: 25,
    minimumReviews: 5,
    includeBusinessesWithoutWebsite: true,
    debug: false,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

The Actor can also be called from the Apify CLI, schedules, webhooks, and standard Apify integrations. This MVP does not include direct CRM or automation-platform integrations.

### 12. Pricing behavior

The Actor calls a separately priced Google Maps Actor. Each child run uses a controlled result limit, timeout, and `maxTotalChargeUsd` (default `$0.50` per query). Check current upstream pricing before production use.

Future pay-per-event scaffolding uses the event name `business_analyzed`. Charging is disabled by default with `ENABLE_BUSINESS_CHARGING=false`. When deliberately enabled and supported by the Actor pricing model, a result is chargeable exactly once only when:

- The normalized business is valid and deduplicated.
- Website status is `SUCCESS` or `EXPLICIT_NO_WEBSITE`.
- A visible Dataset record is atomically pushed.

Malformed, filtered, duplicate, fetch-error, blocked, unsafe, non-HTML, too-large, and website-unknown records are not charged. No event price is configured in source code.

### 13. Data sources

- Google Maps business records through the existing [`compass/crawler-google-places`](https://apify.com/compass/crawler-google-places) Actor
- Public business homepage HTML fetched directly by this Actor

Optional Maps reviews, images, contact enrichment, social enrichment, lead enrichment, and competitor analysis are disabled. No LLM, browser automation, PageSpeed, verified-email, review sentiment, or custom Google Maps crawler is used.

Runtime configuration:

| Environment variable | Default |
|---|---:|
| `GOOGLE_MAPS_ACTOR_ID` | `compass/crawler-google-places` |
| `GOOGLE_MAPS_MAX_CHARGE_PER_QUERY_USD` | `0.50` |
| `GOOGLE_MAPS_CHILD_TIMEOUT_SECS` | `180` |
| `ENABLE_BUSINESS_CHARGING` | `false` |
| `WEBSITE_FETCH_CONCURRENCY` | `5` (hard-capped at 10) |
| `WEBSITE_FETCH_TIMEOUT_MS` | `10000` |
| `MAX_HTML_BYTES` | `2000000` |

### 14. Limitations

- Results are prospecting signals, not guaranteed clients.
- Commercial Demand Score is based on public Maps signals, not business revenue.
- Website analysis is homepage-level only.
- No detected booking link does not prove that no booking option exists elsewhere.
- Response time is diagnostic request evidence, not a PageSpeed or Core Web Vitals score.
- Public emails are not verified.
- Website access failures are not treated as website deficiencies.
- Google Maps and business websites change over time.
- English-language CTA and booking detection is the MVP focus.
- Deterministic booking detection can produce false positives or miss custom widgets.
- The upstream Actor schema and pricing can change; revalidate its connector fixture before deployment changes.
- Maps website-field coverage varies. An absent field is `WEBSITE_UNKNOWN`; only an observed empty field is `EXPLICIT_NO_WEBSITE`.
- Some websites block non-browser requests even when they work normally for visitors.
- Unit economics depend on upstream cost, website success rate, result yield, and the future Store event price.
- Users should manually review high-priority prospects before outreach.

### Local development

```bash
npm install
npm run typecheck
npm test
npm run build
npm run check
```

Tests use offline Maps and homepage fixtures. They do not call paid Actors or real websites.

### Private deployment

1. Install and authenticate the current Apify CLI:

   ```powershell
   npm install -g apify-cli
   apify login
   ```

2. From this project directory, verify and upload the Actor:

   ```powershell
   npm run check
   apify push
   ```

3. In Apify Console, open the new `google-maps-agency-lead-scorer` Actor, confirm it remains private, and do not submit it to the Store.

4. In Actor settings, keep `ENABLE_BUSINESS_CHARGING=false`. Optionally set the other environment variables listed above.

5. Build with the `latest` tag and confirm the image starts with 256–1024 MB memory and no browser.

6. Run the three private validation inputs below separately. Review the Dataset, `OUTPUT`, `REPORT.md`, child-run costs, field coverage, and unsupported-claim safeguards.

#### First private validation inputs

Dentists in Austin:

```json
{"searchQueries":["dentists"],"locationQuery":"Austin, Texas, USA","maxBusinessesPerSearch":25,"minimumReviews":5,"includeBusinessesWithoutWebsite":true,"debug":true}
```

Med spas in Miami:

```json
{"searchQueries":["med spas"],"locationQuery":"Miami, Florida, USA","maxBusinessesPerSearch":25,"minimumReviews":5,"includeBusinessesWithoutWebsite":true,"debug":true}
```

HVAC contractors in Dallas:

```json
{"searchQueries":["HVAC contractors"],"locationQuery":"Dallas, Texas, USA","maxBusinessesPerSearch":25,"minimumReviews":5,"includeBusinessesWithoutWebsite":true,"debug":true}
```

For CLI testing, save one JSON object as `INPUT.json`, then run:

```powershell
Get-Content .\INPUT.json -Raw | apify call YOUR_USERNAME/google-maps-agency-lead-scorer --silent
```

Do not enable charging until private runs have established upstream cost, homepage success rate, chargeable-result yield, and sustainable unit economics.

# Actor input Schema

## `searchQueries` (type: `array`):

Enter 1–5 local-business categories. Homepage detection is English-first.

## `locationQuery` (type: `string`):

City, region, and country used for Google Maps discovery.

## `maxBusinessesPerSearch` (type: `integer`):

Controlled upstream result limit for each query.

## `minimumReviews` (type: `integer`):

Businesses with a known lower review count are filtered. Unknown counts remain with lower confidence.

## `includeBusinessesWithoutWebsite` (type: `boolean`):

Explicit no-website evidence can identify website-build prospects.

## `debug` (type: `boolean`):

Include safe adapter, website, and scoring diagnostics. Secrets and raw HTML are never included.

## Actor input object example

```json
{
  "searchQueries": [
    "dentists"
  ],
  "locationQuery": "Austin, Texas, USA",
  "maxBusinessesPerSearch": 25,
  "minimumReviews": 5,
  "includeBusinessesWithoutWebsite": true,
  "debug": false
}
```

# Actor output Schema

## `leads` (type: `string`):

One result per deduplicated business.

## `jsonReport` (type: `string`):

Structured summary, run economics, warnings, and top prospects.

## `markdownReport` (type: `string`):

Human-readable run summary and top prospects.

# 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 = {
    "searchQueries": [
        "dentists"
    ],
    "locationQuery": "Austin, Texas, USA"
};

// Run the Actor and wait for it to finish
const run = await client.actor("herazur/local-business-revenue-leak-finder").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 = {
    "searchQueries": ["dentists"],
    "locationQuery": "Austin, Texas, USA",
}

# Run the Actor and wait for it to finish
run = client.actor("herazur/local-business-revenue-leak-finder").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "dentists"
  ],
  "locationQuery": "Austin, Texas, USA"
}' |
apify call herazur/local-business-revenue-leak-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,herazur/local-business-revenue-leak-finder"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

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