# Agency Prospect Finder (`apium/agency-prospect-finder`) Actor

Finds local businesses that look like they run ads but are bleeding money on a broken, slow, or missing website, have weak reviews, and no online booking. Ranks every business into a scored 'needs an agency' list so agencies and freelancers can prioritize outreach.

- **URL**: https://apify.com/apium/agency-prospect-finder.md
- **Developed by:** [Tommi Sullivan](https://apify.com/apium) (community)
- **Categories:** Lead generation, Marketing
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 result items

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## Agency Prospect Finder — Local Businesses That Need an Agency (Pay Per Result)

**Find the local businesses that are already spending on visibility but leaking it through a broken funnel.** Give it a location and a vertical (e.g. "dentist" in "Austin, TX") and it returns a ranked list of businesses that look like they run ads but have a slow/broken/missing website, weak reviews, or no online booking — the exact profile of a business that needs an agency and can be shown the problem in one screenshot.

> Keywords: agency lead generation, local business leads, website audit scraper, google maps lead finder, cold outreach leads for agencies.

---

### Why this actor

Most "Google Maps scraper" actors dump raw place data and leave the qualifying work to you. This one does the qualifying work: it fetches each business's own website, times it, checks its HTTP status, and scans for booking-tool markers — then combines that with review and category signals into a single 0–100 **opportunity score**, sorted highest-first. You open the dataset and the top rows are your best outreach targets.

- **Composite scoring, not just raw data.** Website health (40 pts), reviews (30 pts), booking gap (15 pts), ads-likelihood heuristic (15 pts) — see [PRICING.md](PRICING.md) for cost math and README below for the exact rubric.
- **Direct JSON APIs, no browser.** Google Places API (New) for business data, a plain HTTP fetch for website health. No headless Chrome, so compute cost stays low.
- **Honest heuristics, clearly labeled.** "Likely runs ads" is a proxy signal (operational + review_count≥25) — there is no public Ads API this actor calls. It is never presented as verified ad spend.
- **Pay per result.** No subscription — you pay for scored businesses returned. See [PRICING.md](PRICING.md).

---

### What it does

1. Runs a Google Places Text Search for `"{vertical} in {location}"`.
2. Fetches Place Details (rating, review count, up to ~5 reviews, website, phone) for each result.
3. Fetches each business's website once: HTTP status, load time, HTTPS, mobile-viewport tag, and a scan for booking-tool links (Calendly, Vagaro, Square, Booksy, etc.).
4. Scores every business 0–100 on how much it looks like it needs an agency, tags a tier (`hot` / `warm` / `cool` / `healthy`), and lists the specific signals that drove the score.
5. Sorts by score descending, filters by your minimum score, and pushes.

---

### Input

| Field | Type | Description |
|---|---|---|
| `location` | string | Where to search, e.g. `Austin, TX`. |
| `vertical` | string | Business type, e.g. `dentist`, `roofer`, `med spa`. |
| `maxResults` | integer | Spend cap on scored records pushed. Default `60`. |
| `minOpportunityScore` | integer | Only push businesses at/above this score (0–100). Default `0`. |
| `siteTimeoutSeconds` | integer | Per-website fetch timeout. Default `10`. |
| `googlePlacesApiKey` | string (secret) | Your Google Cloud Places API key (Places API (New) enabled, billing on). |
| `proxyConfiguration` | object | Proxy for website health checks only (Places API calls go direct). Datacenter is the default and is normally sufficient. |

#### Input example

```json
{
  "location": "Austin, TX",
  "vertical": "dentist",
  "maxResults": 60,
  "minOpportunityScore": 40,
  "googlePlacesApiKey": "YOUR_KEY",
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["DATACENTER"] }
}
````

***

### Output

| Field | Description |
|---|---|
| `name`, `category`, `address`, `phone`, `website`, `maps_url` | Core Places data. |
| `opportunity_score` | 0–100 composite "needs an agency" score. |
| `opportunity_tier` | `hot` (≥70) / `warm` (≥45) / `cool` (≥20) / `healthy`. |
| `signals` | List of the specific scoring reasons, e.g. `["website:slow(+22)", "no_booking_link(+15)"]`. |
| `site_status` | `ok` / `slow` / `broken` / `missing` / `parked` / `timeout`. |
| `site_load_time_ms`, `site_http_status`, `site_is_https`, `site_has_mobile_viewport` | Website health detail. |
| `rating`, `review_count`, `review_response_rate` | Review signals (`review_response_rate` is `null` if Google's API doesn't expose owner replies — see FAQ). |
| `has_booking_link`, `booking_link_url` | Booking-tool detection. |
| `likely_runs_ads`, `likely_runs_ads_basis` | Heuristic flag + a plain-English note on what it is (and isn't) based on. |
| `scraped_at` | ISO-8601 UTC timestamp. |

#### Scoring rubric

- **Website health** (max 40): `missing`=40, `broken`/`parked`=35, `timeout`=25, `slow`=22, `ok`=0.
- **Reviews** (max 30): rating<3.5 (+16) or no rating (+6); <4.2 (+8); review\_count<5 (+10) or <20 (+5); low owner-response rate (+4).
- **No booking link**: +15.
- **Likely runs ads** (heuristic): +15.

***

### Use cases

- **Agency/freelancer cold outreach** — build a "these 20 businesses are losing customers to their own website" prospect list per city/niche.
- **Franchise/rollup audits** — score every location of a franchise or chain for underperforming digital presence.
- **Sales enablement** — hand reps a pre-scored, pre-qualified list instead of a raw Maps export.

***

### FAQ

**Do I need my own Google API key?** Yes. Get one at [console.cloud.google.com/apis/credentials](https://console.cloud.google.com/apis/credentials), enable **Places API (New)**, and attach billing. Google's own usage fees apply on top of this Actor's price — see PRICING.md.

**Is "likely runs ads" verified ad spend?** No — it's a conservative heuristic (operational + 25+ reviews) used as a proxy for "actively marketed business." There is no public Google/Meta Ads API called. Flagged in every output row via `likely_runs_ads_basis`.

**Is the website check a real Lighthouse audit?** No. It's a direct HTTP fetch measuring status code, load time, HTTPS, and a couple of HTML smell tests — described as "basic Lighthouse-style signals," not a real Lighthouse score. Sites behind bot-protection interstitials (e.g. Cloudflare challenge pages) may show a false "slow" or "broken" read since no browser/JS execution is used.

**Why is `review_response_rate` sometimes null?** Google's Places API (New) does not publicly document an owner-reply field on review objects as of this build. If Google exposes one, this field populates; otherwise it degrades to `null` rather than guessing. Marked `TODO-VERIFY` in `src/scoring.py`.

***

### Legality

This actor collects only **publicly available** business data via Google's official Places API (with your own billed key) and public website responses. It does not scrape Google Maps HTML, bypass authentication, or access private data. You are responsible for using the output in line with Google's Places API terms and applicable law. Not affiliated with or endorsed by Google.

# Actor input Schema

## `location` (type: `string`):

Where to search, e.g. 'Austin, TX' or 'Manchester, UK' or a full address/postcode. Passed to Google's Places Text Search as part of the query.

## `vertical` (type: `string`):

The kind of business to search for, e.g. 'dentist', 'roofer', 'med spa', 'plumber', 'hvac contractor'. Combined with location into a Places Text Search query.

## `maxResults` (type: `integer`):

Hard cap on the number of scored business records pushed. The Actor stops cleanly once reached.

## `minOpportunityScore` (type: `integer`):

Only push businesses scoring at or above this 0-100 'needs an agency' score. Set to 0 to get every business found (including healthy ones, useful for benchmarking).

## `siteTimeoutSeconds` (type: `integer`):

Max time to wait for each business website to respond before marking it slow/unreachable.

## `googlePlacesApiKey` (type: `string`):

Your Google Cloud Places API key (Places API (New) must be enabled, billing required). TODO-VERIFY: exact enabled-API name/billing tier — confirm in Google Cloud Console. Get one at https://console.cloud.google.com/apis/credentials.

## `proxyConfiguration` (type: `object`):

Proxy used only for fetching candidate business websites (health checks). Google Places API calls go direct (no proxy needed/allowed for the JSON API). Datacenter proxies are usually fine here since most small-business sites have no bot protection.

## Actor input object example

```json
{
  "location": "Austin, TX",
  "vertical": "dentist",
  "maxResults": 60,
  "minOpportunityScore": 0,
  "siteTimeoutSeconds": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "DATACENTER"
    ]
  }
}
```

# 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 = {
    "location": "Austin, TX",
    "vertical": "dentist",
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "DATACENTER"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("apium/agency-prospect-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 = {
    "location": "Austin, TX",
    "vertical": "dentist",
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["DATACENTER"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("apium/agency-prospect-finder").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "location": "Austin, TX",
  "vertical": "dentist",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "DATACENTER"
    ]
  }
}' |
apify call apium/agency-prospect-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=apium/agency-prospect-finder",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Agency Prospect Finder",
        "description": "Finds local businesses that look like they run ads but are bleeding money on a broken, slow, or missing website, have weak reviews, and no online booking. Ranks every business into a scored 'needs an agency' list so agencies and freelancers can prioritize outreach.",
        "version": "0.1",
        "x-build-id": "2U4HCWFhKR1U1elug"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/apium~agency-prospect-finder/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-apium-agency-prospect-finder",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/apium~agency-prospect-finder/runs": {
            "post": {
                "operationId": "runs-sync-apium-agency-prospect-finder",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/apium~agency-prospect-finder/run-sync": {
            "post": {
                "operationId": "run-sync-apium-agency-prospect-finder",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "location",
                    "vertical",
                    "googlePlacesApiKey"
                ],
                "properties": {
                    "location": {
                        "title": "Location",
                        "type": "string",
                        "description": "Where to search, e.g. 'Austin, TX' or 'Manchester, UK' or a full address/postcode. Passed to Google's Places Text Search as part of the query."
                    },
                    "vertical": {
                        "title": "Vertical / business type",
                        "type": "string",
                        "description": "The kind of business to search for, e.g. 'dentist', 'roofer', 'med spa', 'plumber', 'hvac contractor'. Combined with location into a Places Text Search query."
                    },
                    "maxResults": {
                        "title": "Max results (spend cap)",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Hard cap on the number of scored business records pushed. The Actor stops cleanly once reached.",
                        "default": 60
                    },
                    "minOpportunityScore": {
                        "title": "Minimum opportunity score to include",
                        "minimum": 0,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Only push businesses scoring at or above this 0-100 'needs an agency' score. Set to 0 to get every business found (including healthy ones, useful for benchmarking).",
                        "default": 0
                    },
                    "siteTimeoutSeconds": {
                        "title": "Website check timeout (seconds)",
                        "minimum": 3,
                        "maximum": 30,
                        "type": "integer",
                        "description": "Max time to wait for each business website to respond before marking it slow/unreachable.",
                        "default": 10
                    },
                    "googlePlacesApiKey": {
                        "title": "Google Places API key",
                        "type": "string",
                        "description": "Your Google Cloud Places API key (Places API (New) must be enabled, billing required). TODO-VERIFY: exact enabled-API name/billing tier — confirm in Google Cloud Console. Get one at https://console.cloud.google.com/apis/credentials."
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Proxy used only for fetching candidate business websites (health checks). Google Places API calls go direct (no proxy needed/allowed for the JSON API). Datacenter proxies are usually fine here since most small-business sites have no bot protection.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "DATACENTER"
                            ]
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
