# Local Lead Qualifier — Google Maps + AI Scoring (`congism/local-lead-qualifier`) Actor

Search Google Maps for a niche and location, then use Claude to score each business as a sales lead based on their web presence and draft a ready-to-send outreach line for the hot ones.

- **URL**: https://apify.com/congism/local-lead-qualifier.md
- **Developed by:** [Cong](https://apify.com/congism) (community)
- **Categories:** Lead generation, AI, Automation
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $110.00 / 1,000 lead qualifieds

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

## Local Lead Qualifier — Google Maps + AI Scoring

**Stop paying for raw lead lists. Get pre-qualified leads with a reason and an opening line already written.**

Local Lead Qualifier searches Google Maps for a niche + location (e.g. "roofers in Denver, CO"), checks each business's actual web presence, and uses Claude to score every business as `hot` / `warm` / `cold` against the service you're selling — plus a ready-to-send outreach line. Built for agencies and freelancers selling to local businesses (web design, SEO, ads management, anything where "weak or missing website" is the buying signal).

***

### Why this instead of a generic Maps scraper

Raw Google Maps scrapers hand you a spreadsheet of names and phone numbers — you still have to manually check every website and decide who's worth calling. This Actor does that triage for you:

1. Scrapes the listing (name, category, rating, phone, website)
2. Fetches the business's actual homepage and checks it for weak signals (no site, no SSL, no mobile viewport, no analytics, stale copyright year)
3. Sends those signals + your service description to Claude, which returns a score, a one-sentence reason, and a non-generic outreach line
4. Skips businesses already flagged in a previous run, so repeat runs only surface new leads

***

### Quickstart

#### 1. Describe what you sell

In **What You Sell**, be specific — this is what the AI scores against:

> "We build fast, mobile-friendly websites for local service businesses, $1,500 flat fee."

#### 2. Add your Anthropic API key

Get one at [console.anthropic.com](https://console.anthropic.com) → API Keys → Create key. Stored as a secret.

#### 3. Configure searches

```json
[
  { "query": "roofing contractors in Denver, CO", "maxResults": 20 },
  { "query": "family dentists in Austin, TX", "maxResults": 20 }
]
```

#### 4. Turn on a Residential proxy

Google Maps applies bot detection to datacenter IPs — use **Apify Residential Proxies** in the Proxy Configuration field. Without one, runs will frequently get blocked or CAPTCHA'd.

#### 5. Connect Slack (optional)

Same as any Apify Incoming Webhook setup — paste the URL into **Slack Webhook URL** to get a digest of new hot leads per search.

***

### Output

One dataset record per qualified lead:

```json
{
  "searchQuery": "roofing contractors in Denver, CO",
  "scoredAt": "2026-07-31T14:00:00.000Z",
  "listing": {
    "name": "Peak Roofing Co",
    "category": "Roofing contractor",
    "address": "123 Main St, Denver, CO",
    "phone": "(303) 555-0100",
    "website": null,
    "rating": 4.6,
    "reviewCount": 82,
    "mapsUrl": "https://www.google.com/maps/place/..."
  },
  "websiteSignals": {
    "hasWebsite": false,
    "isReachable": false,
    "hasSsl": false,
    "hasMobileViewport": false,
    "hasAnalytics": false,
    "copyrightYear": null,
    "loadErrorMessage": null
  },
  "leadScore": {
    "score": "hot",
    "reason": "82 reviews at 4.6 stars but no website at all — strong local reputation with no digital front door.",
    "outreachLine": "Peak Roofing Co has 82 five-star-ish reviews on Google but no website — happy to show you what a $1,500 site could do for calls booked."
  },
  "isNewLead": true
}
```

***

### Pricing guidance

Billed per business scored (pay-per-result recommended — see Apify's pricing setup when publishing). Each result costs roughly one Claude Haiku call plus one lightweight HTTP fetch, so cost scales with `maxResults × number of searches`.

***

### Known limitations

- **Requires a residential proxy** for reliable results — Google Maps blocks datacenter IPs aggressively.
- **Website signal checks are HTTP-only**, not a full browser render — this is intentional (keeps cost and run time down across hundreds of businesses) but means JS-only sites may look weaker than they are.
- **Google's Maps DOM changes over time.** If listing scraping starts returning empty results, the CSS/attribute selectors in `src/mapsScraper.ts` need an update — same maintenance profile as any Maps scraper on the platform.
- **Dedup state is per-Actor, not per-run** — disable "Skip Leads Already Flagged" if you want a full re-score every time.

***

### Architecture

```
Playwright (headless Chrome, residential proxy) → Google Maps listings
  → HTTP fetch of business homepage → website quality signals
  → Claude Haiku (lead scoring + outreach line)
  → Apify KV Store (seen-lead dedup)
  → Slack Block Kit digest (hot leads only)
  → Apify Dataset (full run archive)
```

# Actor input Schema

## `searches` (type: `array`):

List of Google Maps searches. Each item must have a 'query' (e.g. 'roofers in Denver, CO') and optional 'maxResults' (default 20).

## `yourServiceDescription` (type: `string`):

1–2 sentences describing the service you're prospecting for. The more specific, the better the AI qualification and outreach lines. E.g. 'We build fast, mobile-friendly websites for local service businesses, $1,500 flat fee.'

## `anthropicApiKey` (type: `string`):

Your Anthropic API key for Claude-powered lead scoring. Get one at console.anthropic.com.

## `minScoreToKeep` (type: `string`):

Only include leads scored at or above this level in the dataset and Slack digest.

## `slackWebhookUrl` (type: `string`):

Slack Incoming Webhook URL for a digest of new hot leads. Leave empty to skip Slack notifications. Create one at api.slack.com/apps.

## `skipPreviouslySeenLeads` (type: `boolean`):

When enabled, businesses already scored in a prior run are skipped so you don't get re-notified about the same lead. Dedup state is scoped to this Actor's default key-value store.

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

Proxy settings. Apify Residential proxies are strongly recommended — Google Maps applies bot detection to datacenter IPs.

## Actor input object example

```json
{
  "searches": [
    {
      "query": "roofing contractors in Denver, CO",
      "maxResults": 20
    },
    {
      "query": "family dentists in Austin, TX",
      "maxResults": 20
    }
  ],
  "minScoreToKeep": "cold",
  "skipPreviouslySeenLeads": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "searches": [
        {
            "query": "roofing contractors in Denver, CO",
            "maxResults": 20
        },
        {
            "query": "family dentists in Austin, TX",
            "maxResults": 20
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("congism/local-lead-qualifier").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 = {
    "searches": [
        {
            "query": "roofing contractors in Denver, CO",
            "maxResults": 20,
        },
        {
            "query": "family dentists in Austin, TX",
            "maxResults": 20,
        },
    ],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("congism/local-lead-qualifier").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 '{
  "searches": [
    {
      "query": "roofing contractors in Denver, CO",
      "maxResults": 20
    },
    {
      "query": "family dentists in Austin, TX",
      "maxResults": 20
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call congism/local-lead-qualifier --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,congism/local-lead-qualifier"
        }
    }
}

```

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/vZ7yX301R8nC9QKVr/builds/zUFaccttBXP0l3Ger/openapi.json
