# Local Business Finder and Fit Scorer (`physealabs/lead-finder-qualifier`) Actor

Find local businesses in OpenStreetMap and score each one against your ideal customer description.

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

## Pricing

$5.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/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

## Local Business Finder and Fit Scorer

Find local businesses in OpenStreetMap and score each one against your ideal customer description.

### What can Local Business Finder and Fit Scorer do?

Describe the businesses you want, then name business types and a place. The Actor finds OpenStreetMap records, reads available company websites, and returns contact details, fit scores, reasons, and an outreach angle.

| What you get | Features |
|--|--|
| 📍 Business and contact facts from OpenStreetMap and company sites | 🗺️ Business search by type and place |
| 🎯 A fit score, confidence, reasons, and outreach angle | 🌐 Optional website reading for more evidence |

### Who this is for

- Build a local prospect list
- Filter businesses against an ideal customer profile
- Draft a research backed outreach angle

### What you get back

| Field | Type | What you get | Example |
|--|--|--|--|
| `lead_id` | `string` | Stable OpenStreetMap identifier for the business. | `osm:node/2533220906` |
| `name` | `string` | Business name from the source record. | `KC Dental` |
| `category` | `string` | Primary business category. | `dentist` |
| `categories` | `array` | Knowledge categories assigned to the result. | `["cosmetic dentists"]` |
| `description` | `null` | Business description when the source provides one. | `null` |
| `address` | `string` | Street address reported for the business. | `6301 West Parmer Lane, 606, Austin, TX, 78729` |
| `city` | `string` | City reported for the business. | `Austin` |
| `state` | `string` | State or region reported for the business. | `TX` |
| `country` | `null` | Country reported for the business. | `null` |
| `website` | `string` | Business website address when listed. | `https://www.kcdentalaustin.com/` |
| `phone` | `string` | Phone number reported by the source. | `+1-512-918-0888` |
| `email` | `string` | Public business email when listed. | `info@kcdentalaustin.com` |
| `rating` | `null` | Rating when the source provides one. | `null` |
| `reviews_count` | `null` | Review count when the source provides one. | `null` |
| `opening_hours` | `string` | Business hours reported by the source. | `Mo-Th 08:00-17:00; Fr 08:00-16:00` |
| `brand` | `null` | Brand name when the source provides one. | `null` |
| `lat` | `number` | Latitude of the business location. | `30.4443219` |
| `lon` | `number` | Longitude of the business location. | `-97.7440456` |
| `website_status` | `string` | Result of fetching the business website. | `ok` |
| `website_title` | `string` | Page title found on the business website. | `Best Dentist in Austin \| KC Dental` |
| `website_text` | `string` | Text extracted from the business website. | `Family and Cosmetic DentistryServing Northwest Austin , Best Dentist in Austin \| KC Dental Skip to main content Skip to primary sidebar Skip to footer Welco...` |
| `source_url` | `string` | Public source page for this record. | `https://www.openstreetmap.org/node/2533220906` |
| `source` | `string` | Directory or source system used for the record. | `openstreetmap` |
| `status` | `string` | Whether this item completed its requested analysis. | `qualified` |
| `qualified` | `boolean` | Whether the business met the supplied ideal customer criteria. | `true` |
| `qualification_score` | `integer` | Fit score assigned to the lead. | `85` |
| `confidence` | `string` | Confidence level for the qualification. | `high` |
| `qualification_reasons` | `array` | Evidence that supported the qualification result. | `["Cosmetic dentistry services explicitly listed on website","Independent practice (founder Dr. Kyleen Chen, not a chain)","Active website with service descri...` |
| `disqualifiers` | `array` | Reasons the lead did not fit, if any. | `[]` |
| `qualification_summary` | `string` | Plain summary of the lead fit. | `KC Dental is an independent Austin cosmetic dentistry practice with active website services matching ideal customer profile.` |
| `outreach_angle` | `string` | Suggested outreach angle when the lead qualifies. | `Offer digital impression technology integration to enhance their cosmetic dentistry workflow` |
| `ideal_customer` | `string` | Ideal customer description used to score the lead. | `Independent dental clinics offering cosmetic dentistry with an active website. Exclude large chains.` |
| `model` | `string` | Model used for the analysis. | `nvidia.nemotron-nano-3-30b` |
| `qualified_at` | `string` | Time the lead was qualified. | `2026-09-11T17:12:31.106675+00:00` |
| `error` | `null` | Problem details when this item does not complete. | `null` |
| `error_stage` | `null` | Processing step that failed, if any. | `null` |

The run also links to its dataset and any files named in the Actor output.

### What you need to provide

| Field | Type | Required | What it does | Example |
|--|--|--:|--|--|
| `idealCustomer` | `string` | Yes | Describe the businesses you want in free text: industry, size, ownership, services, location, signals, and exclusions. | `Independent dental clinics offering cosmetic dentistry, with an active website and stro...` |
| `searchSpec` | `object` | Yes | queries: business types (e.g. 'dentists', 'coffee shops', 'law firms'); location: city, neighbourhood, region or address (geocoded with OpenStreetMap); maxResults per query (1-500); fetchWebsites (default true) fetches each business's own website for qualification evidence. Legacy Google-Maps keys (language, includeWebResults, skipClosedPlaces) are accepted and ignored. | `{"queries":["dentists","cosmetic dentists"],"location":"Austin, TX","maxResults":15,"fe...` |
| `llm` | `object` | No | Leave blank for the included model (nvidia.nemotron-nano-3-30b via the Actor's Bedrock endpoint, no key needed), or provide an OpenAI-compatible baseUrl, model, and apiKey. Without an apiKey, baseUrl/model are ignored. | \`\` |

#### Quick start

1. Open the Actor in Apify Console.
2. Click **Try for free** or **Create a task**.
3. Replace the sample values with your own input.
4. Click **Start**.
5. Open the dataset and the named output files when the run ends.

### Pricing

- `lead-qualified`: $0.005 per lead qualified.
- Failed or skipped work is not charged unless an event is listed in the run charges.
- Normal Apify compute and proxy costs may also apply.

### Limits and honest notes

- OpenStreetMap coverage varies by area and business type.
- Ratings and review counts are often absent because OpenStreetMap is not a review service.
- A fit score is model analysis of the available record and website text. Review it before outreach.

### Code and API

The examples below use the same values as the Apify Console sample.

#### Input JSON

```json
{
  "idealCustomer": "Independent dental clinics offering cosmetic dentistry, with an active website and strong local reviews. Exclude large chains.",
  "searchSpec": {
    "queries": [
      "dentists",
      "cosmetic dentists"
    ],
    "location": "Austin, TX",
    "maxResults": 15,
    "fetchWebsites": true
  }
}
```

#### Real output sample

This excerpt comes from the real run named in the current marketplace release report.

```json
{
  "lead_id": "osm:node/2533220906",
  "name": "KC Dental",
  "category": "dentist",
  "categories": [
    "dentists"
  ],
  "description": null,
  "address": "6301 West Parmer Lane, 606, Austin, TX, 78729",
  "city": "Austin",
  "state": "TX",
  "country": null,
  "website": "https://www.kcdentalaustin.com/",
  "phone": "+1-512-918-0888",
  "email": "info@kcdentalaustin.com",
  "rating": null,
  "reviews_count": null,
  "opening_hours": "Mo-Th 08:00-17:00; Fr 08:00-16:00",
  "brand": null,
  "lat": 30.4443219,
  "lon": -97.7440456,
  "website_status": "ok",
  "website_title": "Best Dentist in Austin | KC Dental",
  "website_text": "Family and Cosmetic DentistryServing Northwest Austin , Best Dentist in Austin | KC Dental Skip to main content Skip ...",
  "source_url": "https://www.openstreetmap.org/node/2533220906",
  "source": "openstreetmap",
  "status": "qualified",
  "qualified": true,
  "qualification_score": 85,
  "confidence": "high",
  "qualification_reasons": [
    "Business name includes 'Cosmetic Dentistry'",
    "Website explicitly offers 'Family and Cosmetic Dentistry' services",
    "Location in 'Northwest Austin' matches target area",
    "Founder's background includes cosmetic dentistry affiliations",
    "Services listed include 'cosmetic' and 'advanced' dentistry"
  ],
  "disqualifiers": [],
  "qualification_summary": "KC Dental is a single-location Austin dental practice offering cosmetic dentistry services with a dedicated website and founder credentials aligned with cosmetic focus.",
  "outreach_angle": "Offer advanced digital impression solutions to enhance their cosmetic dentistry workflow",
  "model": "nvidia.nemotron-nano-3-30b",
  "qualified_at": "2026-09-11T04:22:22.759391+00:00"
}
```

#### curl

```sh
curl -X POST "https://api.apify.com/v2/acts/physealabs~lead-finder-qualifier/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d @input.json
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("physealabs/lead-finder-qualifier").call(run_input={'idealCustomer': 'Independent dental clinics offering cosmetic dentistry, with an active website and strong local reviews. Exclude large chains.', 'searchSpec': {'queries': ['dentists', 'cosmetic dentists'], 'location': 'Austin, TX', 'maxResults': 15, 'fetchWebsites': True}})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

#### Node.js

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('physealabs/lead-finder-qualifier').call({"idealCustomer": "Independent dental clinics offering cosmetic dentistry, with an active website and strong local reviews. Exclude large chains.", "searchSpec": {"queries": ["dentists", "cosmetic dentists"], "location": "Austin, TX", "maxResults": 15, "fetchWebsites": true}});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

You can call this Actor from an agent or LLM tool that can send HTTP requests to the Apify API. Keep the Apify token in a secret store.

### FAQ

#### Does it scrape Google Maps?

No. It uses OpenStreetMap and each business website when available.

#### Does it always find an email address?

No. Contact fields are returned only when the public sources provide them.

#### Can I skip website fetches?

Yes. Set `fetchWebsites` to `false` inside `searchSpec`.

# Actor input Schema

## `idealCustomer` (type: `string`):

Describe the businesses you want in free text: industry, size, ownership, services, location, signals, and exclusions.

## `searchSpec` (type: `object`):

queries: business types (e.g. 'dentists', 'coffee shops', 'law firms'); location: city, neighbourhood, region or address (geocoded with OpenStreetMap); maxResults per query (1-500); fetchWebsites (default true) fetches each business's own website for qualification evidence. Legacy Google-Maps keys (language, includeWebResults, skipClosedPlaces) are accepted and ignored.

## `llm` (type: `object`):

Leave blank for the included model (nvidia.nemotron-nano-3-30b via the Actor's Bedrock endpoint, no key needed), or provide an OpenAI-compatible baseUrl, model, and apiKey. Without an apiKey, baseUrl/model are ignored.

## Actor input object example

```json
{
  "idealCustomer": "Independent dental clinics offering cosmetic dentistry, with an active website and strong local reviews. Exclude large chains.",
  "searchSpec": {
    "queries": [
      "dentists",
      "cosmetic dentists"
    ],
    "location": "Austin, TX",
    "maxResults": 15,
    "fetchWebsites": true
  }
}
```

# Actor output Schema

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

OpenStreetMap business facts, website evidence, fit score, evidence, confidence, and outreach angle.

## `summary` (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 = {
    "idealCustomer": "Independent dental clinics offering cosmetic dentistry, with an active website and strong local reviews. Exclude large chains.",
    "searchSpec": {
        "queries": [
            "dentists",
            "cosmetic dentists"
        ],
        "location": "Austin, TX",
        "maxResults": 15,
        "fetchWebsites": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("physealabs/lead-finder-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 = {
    "idealCustomer": "Independent dental clinics offering cosmetic dentistry, with an active website and strong local reviews. Exclude large chains.",
    "searchSpec": {
        "queries": [
            "dentists",
            "cosmetic dentists",
        ],
        "location": "Austin, TX",
        "maxResults": 15,
        "fetchWebsites": True,
    },
}

# Run the Actor and wait for it to finish
run = client.actor("physealabs/lead-finder-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 '{
  "idealCustomer": "Independent dental clinics offering cosmetic dentistry, with an active website and strong local reviews. Exclude large chains.",
  "searchSpec": {
    "queries": [
      "dentists",
      "cosmetic dentists"
    ],
    "location": "Austin, TX",
    "maxResults": 15,
    "fetchWebsites": true
  }
}' |
apify call physealabs/lead-finder-qualifier --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,physealabs/lead-finder-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/Y2ASBoNee8Dmnf2Xg/builds/HeGvr1AnOQo9NuUIr/openapi.json
