# AI Local Business Opportunity Finder (`kayhermes/ai-local-business-opportunity-finder`) Actor

Find local businesses, enrich contacts, audit websites, score sales opportunities, and create personalized outreach angles.

- **URL**: https://apify.com/kayhermes/ai-local-business-opportunity-finder.md
- **Developed by:** [Khoa Nguyen](https://apify.com/kayhermes) (community)
- **Categories:** Social media
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $12.00 / 1,000 qualified leads

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/actors/running/actors-in-store.md#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

## AI Local Business Opportunity Finder

Turn Google Maps searches or business websites into **qualified sales opportunities**, not another raw lead dump.

The Actor discovers local businesses, visits their websites, extracts public contact information, audits digital weaknesses, calculates a 0–100 opportunity score, and creates outreach grounded in the observed facts.

### What it returns

Each lead can include:

- Business name, category, address, phone, Google Maps URL, rating, and review count
- Website, public emails, website phones, and linked social profiles
- Website audit signals: HTTPS, mobile setup, meta description, H1, schema, lead form, CTA, chat, analytics, booking, ordering, ecommerce, and content depth
- A ranked list of specific sales opportunities
- Opportunity score and lead temperature (`hot`, `warm`, `possible`, or `low`)
- Recommended service to pitch
- Outreach subject, first line, and message
- Optional screenshot and webhook delivery

### Best use cases

- Web-design agencies finding businesses with missing or weak websites
- Local SEO agencies identifying technical and review-growth opportunities
- Appointment and ordering providers finding businesses without online conversion paths
- Reputation-management services targeting low-rating businesses
- Marketing agencies building scheduled fresh-lead pipelines
- CRM and AI-agent workflows that need structured, evidence-based leads

### Quick start

Use a query and location:

```json
{
  "searchQueries": ["dentists", "roofing contractors"],
  "locations": ["Detroit, Michigan"],
  "maxResultsPerSearch": 20,
  "auditWebsites": true,
  "minimumOpportunityScore": 40,
  "generateOutreach": true,
  "sellerBusinessName": "Your Agency",
  "sellerOffer": "fast websites and local SEO that turn Google traffic into calls"
}
```

You can also provide direct Google Maps place URLs or website URLs.

### Opportunity scoring

The Actor looks for evidence such as:

- No listed website or an inaccessible website
- No HTTPS or mobile viewport
- Missing meta description, H1, or structured data
- No contact form, visible email, strong CTA, chat, or analytics
- No online booking for appointment-driven categories
- No online ordering for food and beverage categories
- No ecommerce for retail categories
- Thin content or visibly stale copyright year
- Low review volume or a rating-improvement opportunity
- Strong Google reputation with a weak conversion path

Set `serviceFocus` to emphasize the problems that match your offer.

### Outreach modes

#### Built-in templates

The default mode creates truthful outreach without an external model. It only references facts found in the lead record.

#### OpenAI-compatible AI

Enable `useAiForOutreach`, then supply:

- `aiBaseUrl`
- `aiModel`
- Secret `aiApiKey`

The endpoint must be reachable from the Apify cloud. A local Hermes or llama.cpp endpoint behind a private LAN or Tailscale address will not be reachable unless you expose it securely through an authenticated public gateway.

### Fresh-lead schedules

Set:

```json
{
  "onlyNewLeads": true,
  "leadHistoryStoreName": "my-agency-lead-history"
}
```

Schedule the Actor daily or weekly. It remembers previously delivered businesses and outputs only new leads.

### Output

- **Dataset:** complete structured lead records
- **`OUTPUT`:** machine-readable run statistics
- **`REPORT.html`:** visual report sorted by highest opportunity score
- **Screenshots:** optional key-value-store records for higher-scoring websites

### Webhooks

Use `webhookUrl` to send the run summary and top leads to Make, Zapier, n8n, Slack workflows, a CRM, or your own endpoint. Add secret headers through `webhookHeadersJson`.

### Proxy guidance

Google Maps may limit or challenge repeated automated requests. Start with a small run. If discovery is blocked, enable Apify Proxy; residential proxy groups generally improve reliability but increase cost. Keep concurrency moderate.

### Responsible use

Collect and use only publicly available business information. Follow applicable privacy, anti-spam, marketing, and platform rules. Do not send deceptive, misleading, or mass unsolicited messages. Review each generated message before sending it.

### Monetization hooks

The source supports these pay-per-event names:

- `qualified-lead` — charged for each dataset lead delivered
- `ai-outreach` — charged when AI outreach is successfully generated

Pricing is configured in the Actor’s Apify Publication settings, not in source code. A practical launch test is `$0.025` per qualified lead and `$0.01` per AI-written outreach, then adjust after measuring browser/proxy costs and conversion.

### Local development

```bash
npm ci
npm test
npm run check
apify validate-schema
apify call
```

Node.js 22 or newer is required.

# Actor input Schema

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

Examples: dentists, roofing contractors, bubble tea shops, salons. Each query is combined with every location below.

## `locations` (type: `array`):

Cities, ZIP codes, counties, or regions. Leave empty when the location is already included in each query.

## `directGoogleMapsUrls` (type: `array`):

Optional specific Google Maps place pages to enrich and audit.

## `businessWebsiteUrls` (type: `array`):

Optional websites to audit without using Google Maps discovery.

## `maxResultsPerSearch` (type: `integer`):

Maximum Google Maps place pages collected for each query/location combination.

## `maxSearchScrolls` (type: `integer`):

Higher values may find more businesses but increase run time.

## `searchScrollWaitMs` (type: `integer`):

Delay that allows more Google Maps results to load.

## `languageCode` (type: `string`):

Two-letter language code used for Google Maps pages. English provides the most reliable field parsing.

## `includeClosedBusinesses` (type: `boolean`):

Include places detected as temporarily or permanently closed.

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

Businesses without a website are often strong web-design leads.

## `minRating` (type: `number`):

Businesses with no detected rating are not removed by this filter.

## `maxRating` (type: `number`):

Use a lower value to focus on reputation-management prospects.

## `minReviews` (type: `integer`):

Minimum review count

## `maxReviews` (type: `integer`):

Maximum review count

## `auditWebsites` (type: `boolean`):

Checks contacts, mobile setup, SEO, booking, ordering, lead forms, analytics, social profiles, and conversion signals.

## `maxSupplementalPages` (type: `integer`):

Visit a small number of contact, about, booking, or ordering pages to improve email and phone enrichment.

## `websiteWaitAfterLoadMs` (type: `integer`):

Extra website load wait

## `serviceFocus` (type: `string`):

Opportunity scoring gives more weight to issues that match what you sell.

## `minimumOpportunityScore` (type: `integer`):

Only output leads at or above this 0–100 score.

## `requireEmail` (type: `boolean`):

Remove leads when no email is found on the website or contact pages.

## `maxOutputLeads` (type: `integer`):

Highest-scoring leads are output first.

## `onlyNewLeads` (type: `boolean`):

Uses the persistent history store below, making scheduled runs useful for fresh lead delivery.

## `leadHistoryStoreName` (type: `string`):

Reuse the same named key-value store across scheduled runs.

## `generateOutreach` (type: `boolean`):

Creates a subject line, first line, and concise message for each qualified lead.

## `sellerBusinessName` (type: `string`):

Used in outreach messages.

## `sellerOffer` (type: `string`):

Example: websites, local SEO, appointment booking, or reputation management.

## `senderName` (type: `string`):

Sender name

## `outreachTone` (type: `string`):

Outreach tone

## `useAiForOutreach` (type: `boolean`):

When off, truthful template outreach is generated without external AI cost.

## `maxAiOutreachLeads` (type: `integer`):

Limits external model cost. Remaining leads use the built-in template.

## `aiBaseUrl` (type: `string`):

Usually https://api.openai.com/v1. A private model endpoint must be reachable from the Apify cloud.

## `aiModel` (type: `string`):

Required only when AI outreach is enabled.

## `aiApiKey` (type: `string`):

Encrypted secret input. Never place API keys in source code.

## `aiOrganization` (type: `string`):

Optional OpenAI organization value.

## `aiTimeoutSecs` (type: `integer`):

AI request timeout

## `saveWebsiteScreenshots` (type: `boolean`):

Stores full-page screenshots in the run key-value store.

## `screenshotMinimumScore` (type: `integer`):

Screenshot minimum score

## `webhookUrl` (type: `string`):

Optional Slack workflow, Make, Zapier, n8n, CRM, or custom webhook endpoint.

## `webhookHeadersJson` (type: `string`):

Optional secret headers, for example {"Authorization":"Bearer ..."}.

## `webhookLeadLimit` (type: `integer`):

Maximum leads included in webhook

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

Google Maps can block repeated traffic. Apify Proxy or a residential proxy improves reliability.

## `maxConcurrency` (type: `integer`):

Maximum browser concurrency

## `maxRequestRetries` (type: `integer`):

Request retries

## `navigationTimeoutSecs` (type: `integer`):

Navigation timeout

## `requestHandlerTimeoutSecs` (type: `integer`):

Request processing timeout

## `blockHeavyResources` (type: `boolean`):

Reduces browser cost while keeping scripts, styles, and page content available.

## Actor input object example

```json
{
  "searchQueries": [
    "dentists"
  ],
  "locations": [
    "Detroit, Michigan"
  ],
  "directGoogleMapsUrls": [],
  "businessWebsiteUrls": [],
  "maxResultsPerSearch": 25,
  "maxSearchScrolls": 30,
  "searchScrollWaitMs": 900,
  "languageCode": "en",
  "includeClosedBusinesses": false,
  "includeBusinessesWithoutWebsite": true,
  "minRating": 0,
  "maxRating": 5,
  "minReviews": 0,
  "maxReviews": 1000000,
  "auditWebsites": true,
  "maxSupplementalPages": 2,
  "websiteWaitAfterLoadMs": 500,
  "serviceFocus": "all",
  "minimumOpportunityScore": 30,
  "requireEmail": false,
  "maxOutputLeads": 500,
  "onlyNewLeads": false,
  "leadHistoryStoreName": "local-business-opportunity-history",
  "generateOutreach": true,
  "sellerBusinessName": "",
  "sellerOffer": "website, local SEO, and online booking improvements",
  "senderName": "",
  "outreachTone": "friendly",
  "useAiForOutreach": false,
  "maxAiOutreachLeads": 25,
  "aiBaseUrl": "https://api.openai.com/v1",
  "aiModel": "",
  "aiTimeoutSecs": 45,
  "saveWebsiteScreenshots": false,
  "screenshotMinimumScore": 60,
  "webhookLeadLimit": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "maxConcurrency": 5,
  "maxRequestRetries": 2,
  "navigationTimeoutSecs": 45,
  "requestHandlerTimeoutSecs": 120,
  "blockHeavyResources": true
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

## `report` (type: `string`):

No description

# 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"
    ],
    "locations": [
        "Detroit, Michigan"
    ],
    "directGoogleMapsUrls": [],
    "businessWebsiteUrls": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("kayhermes/ai-local-business-opportunity-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"],
    "locations": ["Detroit, Michigan"],
    "directGoogleMapsUrls": [],
    "businessWebsiteUrls": [],
}

# Run the Actor and wait for it to finish
run = client.actor("kayhermes/ai-local-business-opportunity-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"
  ],
  "locations": [
    "Detroit, Michigan"
  ],
  "directGoogleMapsUrls": [],
  "businessWebsiteUrls": []
}' |
apify call kayhermes/ai-local-business-opportunity-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kayhermes/ai-local-business-opportunity-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/jgVHaULdnwg9QVTos/builds/L5BQHjryvgoef4ptk/openapi.json
