# Local Business Leads Enricher: Emails, Phones & Tech Stack (`mortenm/local-business-prospect-qualifier`) Actor

Enrich local business leads: paste plumber, roofer, HVAC, electrician or contractor websites and get emails, phone numbers, contact forms, booking tools, services and tech stack (WordPress, Wix, GA4, Meta Pixel, Housecall Pro, ServiceTitan). Every result has a source. Pay only for useful results.

- **URL**: https://apify.com/mortenm/local-business-prospect-qualifier.md
- **Developed by:** [Lead Notebook](https://apify.com/mortenm) (community)
- **Categories:** Lead generation, Marketing
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 useful website assessments

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Local Business Leads Enricher: Emails, Phones & Tech Stack

**For marketing and web agencies that already have a list of local business leads.** Paste your list of websites in bulk (for example plumber, roofer, HVAC, electrician or other contractor leads from your CRM or a Google Maps export). For each website you get back public contact routes, evidence of which services the business advertises, and the web tools it uses. Every claim comes with the page it was found on and a short excerpt. You pay only for websites where something useful was found.

- 📞 **Contact routes:** emails, phone numbers, contact forms and booking tools, each marked with how reliable it looks. Contact details a site publishes in its own schema.org structured data are included too.
- 🏷️ **Business type:** the schema.org type a site declares for itself (e.g. `Plumber`, `RoofingContractor`), with its stated town and service area. This is the site's own description, not a verified fact.
- 🛠️ **Service evidence:** 24 home-service categories (plumbing, HVAC, roofing, electrical, landscaping…), plus *commercial*, *residential*, *24/7* and *free estimates*. Each match is graded **strong** (in a title or heading, or repeated in the main text) or **weak** (a passing mention, menu or customer review).
- 🧩 **Web tooling:** WordPress, Wix, Squarespace, Webflow, Duda, GoDaddy; Google Tag Manager, GA4, Google Ads, Meta Pixel, Clarity, CallRail; Gravity Forms, Contact Form 7, HubSpot, Jotform; Housecall Pro, ServiceTitan, Jobber, Calendly, GoHighLevel (LeadConnector), Roofle; chat and review widgets. 50 signatures in total.
- 🚩 **Dead and broken websites:** a listed business whose domain no longer resolves, or whose site has a certificate problem, is flagged. These rows are never charged.
- 🔗 **Your IDs stay attached:** your `clientRecordId`, business name, country and city come back on every row, so the results merge straight back into your spreadsheet or CRM.

### Enrich a Google Maps lead list

No list yet? Run [Google Maps Scraper](https://apify.com/compass/crawler-google-places) for a search such as "roofers in Dallas", then pass its rows here:

| Google Maps Scraper field | This Actor's input field |
|---|---|
| `website` | `website` |
| `placeId` | `clientRecordId` |
| `title` | `businessName` |
| `city` | `city` |
| `countryCode` | `country` |

Rows without a website can be left out; they have nothing to enrich.

### Why this instead of a generic contact scraper or tech-stack detector?

- **One row per input row, with your IDs kept.** Generic scrapers lose the link back to your CRM record. This Actor doesn't.
- **Proof, not guesses.** Every email, phone number, service and tool comes with the page it was found on and the exact text. Nothing is guessed or "enriched" from third-party databases.
- **Qualification, not just contacts.** You can see which businesses actually advertise the service you sell to (roofing, HVAC, plumbing…), and whether they run Google Ads tags, a Meta Pixel, call tracking or an online booking tool.
- **Dead websites are leads too.** Businesses still listed on Google Maps whose website no longer works are flagged, at no charge.
- **Fair billing.** Blocked, empty, dead and duplicate websites are free.

### Who it is for

- **Web design agencies** looking for local businesses with outdated, broken or DIY websites (Wix, GoDaddy, no booking tool, no tracking).
- **Marketing agencies** checking which prospects already run Google Ads tags, a Meta Pixel or call tracking.
- **Lead-generation teams** that need a verified contact route and proof that the business actually offers the service before outreach.

### Quick start

1. Click **Try for free**. The input is prefilled with fictional demo businesses, so you can see every kind of result without touching a real website.
2. Replace `businesses` with about **20 rows of your own**: `website` and `clientRecordId` are required; `businessName`, `country` (two-letter code such as `US`) and `city` are optional.
3. Optionally choose **Target service categories** (for example `roofing`) to get a direct yes/weak/no column.
4. Run, then open the **Overview** table or export to CSV/Excel/JSON.

```json
{
  "businesses": [
    { "website": "https://acme-roofing.com", "clientRecordId": "crm-001", "businessName": "Acme Roofing LLC", "country": "US", "city": "Austin" }
  ],
  "targetServiceCategories": ["roofing"],
  "defaultCountry": "US"
}
```

### What you get per row

| Field | Meaning |
|---|---|
| `status` | `ASSESSED`, `PARTIAL_ASSESSED`, `REACHABLE_NO_SUPPORTED_EVIDENCE`, `BLOCKED`, `FETCH_FAILED`, `INVALID_TARGET`, `PROHIBITED_TARGET`, `BODY_LIMIT`, `NOT_PROCESSED_BUDGET` or `NOT_PROCESSED_SPEND_LIMIT`, always with a plain-English `statusReason` |
| `siteIssue` | for failed sites: `domain_not_resolving`, `tls_certificate_problem`, `timeout`, `http_not_found`, … |
| `summary.emails` | the business's own domain first, then Gmail-style addresses, then other domains |
| `summary.phones` | normalised to E.164 (`+15125550142`) |
| `summary.hasContactForm`, `hasBookingRoute`, `hasOnlineBookingTool` | form found; a booking link or tool; an actual booking tool such as Housecall Pro or ServiceTitan |
| `summary.hasJobApplicationForm` | a job application form (résumé upload, "position applying for") was found; it is a hiring signal and is never counted as a contact form |
| `summary.leadGenSiteSuspected` | the site looks like a pay-per-call lead-generation page rather than the business's own site: only toll-free numbers, a toll-free number in the page title, no email on the site's domain and your business name missing from the page. This can mean the business no longer controls the domain. The reasons are listed in `warnings`; the row is still charged if it has supported evidence |
| `summary.serviceCategories` / `weakServiceMentions` | strong / weak service evidence |
| `summary.technologies` | observed tools |
| `summary.businessTypes` | schema.org types the site declares for itself in its structured data (e.g. `Plumber`); details such as stated town and service area are in `evidence.businessEntities` |
| `targetServiceMatch` | `observed`, `weak_mention_only` or `not_observed_in_fetched_pages` |
| `inputCityMention`, `businessNameMention` | whether your city or business name appears on the site |
| `evidence.*` | every claim with source URL, page context and excerpt; phones with `lineType` (e.g. `toll_free`); a flag when a link's real target differs from its visible text |
| `coverage.pages` | which pages were read and what happened (`usable`, `soft_404`, `duplicate_content`, `bot_challenge`, …) |
| `billing.status` | whether this row was charged and why |

The run's key-value store holds a `RUN_SUMMARY` with:

- status counts and charges;
- the IDs of rows that were not processed, ready to resubmit;
- phone numbers that appear on several different websites, which often points to a shared call centre or lead-generation network rather than the business's own line.

### Pricing

**$0.02 per useful assessment ($20 per 1,000)**, plus Apify's tiny per-run start fee ($0.00005). There is no extra platform-usage charge.

A *useful assessment* means the site was read and at least one supported contact route, strong service match or tool was found, with its source. **You are not charged for:**

- blocked, failed, dead, invalid or excluded websites;
- sites where nothing was found;
- weak-only service mentions;
- duplicate rows (each website is charged at most once per run).

| Example | What you pay |
|---|---|
| 100 websites, 78 useful | 78 × $0.02 = **$1.56** |
| 1,000 websites, 780 useful | **$15.60** |

Set **Maximum charge per run** in Apify to cap your spend. When the next website would not fit under that cap, the Actor stops starting new ones; the remaining rows come back marked for resubmission.

In our own test on 180 home-service businesses listed on Google Maps in three US metros, about 4 in 5 reachable websites produced a useful assessment. Your lists will differ. This is not an accuracy guarantee.

### What it does *not* do

- It does **not** verify that an email is deliverable, belongs to a decision-maker, or may legally be contacted. Outreach permission is your responsibility.
- It never claims a business does **not** offer a service or does **not** use a tool. Unmatched means *not observed on the pages read*.
- It does not check that a tracking tag fires or that a booking widget works.
- It does not assign a phone number to the branch in your `city` input.
- It does not estimate revenue, size, buying intent or a "lead score".
- It does not run a browser. Sites that load all their content with JavaScript give little evidence and are reported as such.
- Service terms are **English only**; it works best on US/UK/Canadian/Australian home-service sites.

### Limits and settings

- **Batch size:** default 100 websites per run, up to 1,000 rows. A run stops starting new websites after about 4.5 minutes by default (`runTimeBudgetSecs`); unprocessed rows are listed for resubmission.
- **Pages per site:** up to 3 by default, maximum 4: the homepage plus contact, services, booking, about or location pages.
- **Other caps:** per-site time, request timeout, page size and total download.
- **Re-runs:** some hosting firewalls block repeat visitors. Re-running the same list soon after can return more `BLOCKED` rows (never charged).

### Responsible use

- robots.txt is respected. Blocks, CAPTCHAs and bot challenges are reported, never evaded.
- No proxies, logins, cookies or form submissions are used.
- A permissive robots.txt or a URL you supply is not treated as permission to reuse a site's content. The output keeps short factual excerpts only.
- You can exclude domains with `excludedDomains`. A built-in list excludes sites whose terms are known to forbid automated access.
- The Actor refuses private-network and cloud-metadata addresses, including on redirects.

### Reliability

- **No double charges:** a website is charged at most once per run, even if Apify restarts or migrates the run.
- **Results are not lost:** a charged result is never lost. If saving results fails, the run keeps them and a resurrected run delivers them without a new charge.
- **Billing is visible:** every row's `billing.status` shows what happened. `RUN_SUMMARY` lists any charge with an unknown outcome.

### FAQ

**Can I run it from Make, n8n, Zapier or my own code?** Yes. Use Apify's API or integrations, pass the same JSON input and read the dataset.

**Why is a website `BLOCKED`?** The site or its host refused automated access (403, bot challenge or robots.txt). We do not try to get around that, and you are not charged.

**How do I find emails from a list of websites in bulk?** Paste up to 1,000 websites per run in `businesses`. Each website gets the emails, phone numbers and contact forms published on its homepage and a few contact, services, booking, about or location pages (3 pages per site by default, at most 4), with the page each one came from.

**Can I look up the tech stack of many websites at once?** Yes. Every row lists the site builder, analytics and ad tags, call tracking, form and booking tools that were observed, from the same run. Tools that were not observed are not claimed to be missing.

**Why only some emails?** Many local businesses publish only a phone number and a form. The Actor reports only what is on the pages it read, and never guesses addresses.

**Why is a .gov address on the site missing from the emails?** Licensed trades often have to show their regulator's contact details, for example the complaint notice Texas plumbers must display (`@tsbpe.texas.gov`, `@hpc.state.tx.us`). Such government addresses are kept as `evidence.governmentEmails` and named in `warnings`, never listed as the business's email, and never billed as a useful result on their own. The same goes for the regulator's phone number in that notice (for example the Texas plumbing board's (512) 936-5200 or TDLR's 1-800-803-9202): it is kept as `evidence.governmentPhones` with its source and excerpt, not as a phone of the business. A short verified list of regulator numbers is recognised anywhere, including `tel:` links; another number counts as the regulator's only when it is printed straight after the agency's name or Austin address in visible text, and never when the business also links it as its own.

**Is this in beta?** Yes. Version 0.1: feedback and edge cases are very welcome via the Issues tab.

### More tools from the same developer

- [Web Design Leads](https://apify.com/mortenm/web-design-leads): audit websites in bulk and find businesses with outdated, broken or non-mobile sites, with a lead score.
- [SEO Audit Leads](https://apify.com/mortenm/seo-audit-leads): bulk on-page, technical and local SEO audit of business websites with an SEO score, grade, lead level and the fixes to pitch.
- [Local Business Leads by City & Category](https://apify.com/mortenm/business-leads-overture): find businesses by type and city (a Google Maps alternative from open data), with phones, websites and emails.
- [Google Trends Trending Now + Bluesky, Wikipedia & Songs](https://apify.com/mortenm/social-trends-radar): what is trending right now across Google Trends, Bluesky, Mastodon, Wikipedia, Hacker News and Apple Music.

# Actor input Schema

## `businesses` (type: `array`):

Array of objects: {"website": "https://example-roofing.com", "clientRecordId": "crm-123", "businessName": "Example Roofing LLC", "country": "US", "city": "Austin"}. website and clientRecordId are required; businessName, country (ISO 3166-1 alpha-2) and city are optional context. Context is preserved and used only to normalise phone numbers and to report whether the name/city was mentioned; it is never treated as verified site geography. Up to 1,000 rows per run.

## `targetServiceCategories` (type: `array`):

Optional. Report whether terms for these home-service categories were observed (targetServiceMatch). All categories are still reported in summary.serviceCategories. Term occurrences are evidence of wording on the site, not proof of what the business currently sells; no match never proves absence.

## `customServiceTerms` (type: `array`):

Optional, up to 20 extra English terms (e.g. "commercial roofing", "tankless"). Matched case-insensitively as whole words; each match is reported with page context and an excerpt.

## `defaultCountry` (type: `string`):

Optional ISO 3166-1 alpha-2 code (e.g. US) used to normalise phone numbers for rows without a country. Numbers written with an explicit +country prefix always take precedence. The source of every normalisation is reported.

## `maxDomains` (type: `integer`):

Unique canonical websites processed in this run (duplicate rows of the same site count once). Rows beyond this are returned as NOT_PROCESSED_BUDGET for resubmission.

## `maxPagesPerDomain` (type: `integer`):

Homepage plus up to this many minus one same-site contact/services/booking/about/location pages. robots.txt requests are counted separately in the run summary.

## `runTimeBudgetSecs` (type: `integer`):

The run stops starting new work so it can finish within this time, and returns untouched rows as NOT_PROCESSED_BUDGET. This is a cost cap, not a promise that every row completes. Keep the run timeout above this value.

## `perDomainTimeBudgetSecs` (type: `integer`):

Total time one website may consume across all its requests, so a slow host cannot hold a worker.

## `requestTimeoutSecs` (type: `integer`):

Hard deadline for each HTTP request including redirects and body download. Transient network/5xx failures are retried once within budget; blocks are never retried.

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

Websites processed in parallel. Each website is fetched one request at a time.

## `maxPageSizeKiB` (type: `integer`):

Decompressed HTML bytes read per page; larger pages are truncated and analysed partially.

## `maxTotalDownloadMiB` (type: `integer`):

Response-body byte budget for the whole run, including robots.txt and retries. When it would be exceeded, no new requests start.

## `excludedDomains` (type: `array`):

Domains you do not want fetched (subdomains included). They are returned as PROHIBITED_TARGET and never charged. A built-in list also excludes sites known to restrict automated access.

## Actor input object example

```json
{
  "businesses": [
    {
      "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/summit-ridge-roofing/",
      "clientRecordId": "demo-001",
      "businessName": "Summit Ridge Roofing",
      "country": "US",
      "city": "Austin"
    },
    {
      "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing/",
      "clientRecordId": "demo-002",
      "businessName": "Clearwater Plumbing Co.",
      "country": "US",
      "city": "Denver"
    },
    {
      "website": "mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing",
      "clientRecordId": "demo-003",
      "businessName": "Clearwater Plumbing Co. (duplicate CRM row)",
      "country": "US",
      "city": "Aurora"
    },
    {
      "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/brightside-hvac/",
      "clientRecordId": "demo-004",
      "businessName": "Brightside HVAC"
    },
    {
      "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/parked-domain-demo/",
      "clientRecordId": "demo-005"
    },
    {
      "website": "https://excluded-demo.example/",
      "clientRecordId": "demo-006",
      "businessName": "Excluded by input"
    },
    {
      "website": "not a url",
      "clientRecordId": "demo-007"
    }
  ],
  "targetServiceCategories": [
    "roofing",
    "plumbing"
  ],
  "customServiceTerms": [],
  "defaultCountry": "US",
  "maxDomains": 20,
  "maxPagesPerDomain": 4,
  "runTimeBudgetSecs": 270,
  "perDomainTimeBudgetSecs": 60,
  "requestTimeoutSecs": 15,
  "maxConcurrency": 10,
  "maxPageSizeKiB": 2048,
  "maxTotalDownloadMiB": 300,
  "excludedDomains": [
    "excluded-demo.example"
  ]
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `evidence` (type: `string`):

No description

## `runSummary` (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 = {
    "businesses": [
        {
            "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/summit-ridge-roofing/",
            "clientRecordId": "demo-001",
            "businessName": "Summit Ridge Roofing",
            "country": "US",
            "city": "Austin"
        },
        {
            "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing/",
            "clientRecordId": "demo-002",
            "businessName": "Clearwater Plumbing Co.",
            "country": "US",
            "city": "Denver"
        },
        {
            "website": "mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing",
            "clientRecordId": "demo-003",
            "businessName": "Clearwater Plumbing Co. (duplicate CRM row)",
            "country": "US",
            "city": "Aurora"
        },
        {
            "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/brightside-hvac/",
            "clientRecordId": "demo-004",
            "businessName": "Brightside HVAC"
        },
        {
            "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/parked-domain-demo/",
            "clientRecordId": "demo-005"
        },
        {
            "website": "https://excluded-demo.example/",
            "clientRecordId": "demo-006",
            "businessName": "Excluded by input"
        },
        {
            "website": "not a url",
            "clientRecordId": "demo-007"
        }
    ],
    "targetServiceCategories": [
        "roofing",
        "plumbing"
    ],
    "defaultCountry": "US",
    "maxDomains": 20,
    "maxPagesPerDomain": 4,
    "excludedDomains": [
        "excluded-demo.example"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mortenm/local-business-prospect-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 = {
    "businesses": [
        {
            "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/summit-ridge-roofing/",
            "clientRecordId": "demo-001",
            "businessName": "Summit Ridge Roofing",
            "country": "US",
            "city": "Austin",
        },
        {
            "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing/",
            "clientRecordId": "demo-002",
            "businessName": "Clearwater Plumbing Co.",
            "country": "US",
            "city": "Denver",
        },
        {
            "website": "mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing",
            "clientRecordId": "demo-003",
            "businessName": "Clearwater Plumbing Co. (duplicate CRM row)",
            "country": "US",
            "city": "Aurora",
        },
        {
            "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/brightside-hvac/",
            "clientRecordId": "demo-004",
            "businessName": "Brightside HVAC",
        },
        {
            "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/parked-domain-demo/",
            "clientRecordId": "demo-005",
        },
        {
            "website": "https://excluded-demo.example/",
            "clientRecordId": "demo-006",
            "businessName": "Excluded by input",
        },
        {
            "website": "not a url",
            "clientRecordId": "demo-007",
        },
    ],
    "targetServiceCategories": [
        "roofing",
        "plumbing",
    ],
    "defaultCountry": "US",
    "maxDomains": 20,
    "maxPagesPerDomain": 4,
    "excludedDomains": ["excluded-demo.example"],
}

# Run the Actor and wait for it to finish
run = client.actor("mortenm/local-business-prospect-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 '{
  "businesses": [
    {
      "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/summit-ridge-roofing/",
      "clientRecordId": "demo-001",
      "businessName": "Summit Ridge Roofing",
      "country": "US",
      "city": "Austin"
    },
    {
      "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing/",
      "clientRecordId": "demo-002",
      "businessName": "Clearwater Plumbing Co.",
      "country": "US",
      "city": "Denver"
    },
    {
      "website": "mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing",
      "clientRecordId": "demo-003",
      "businessName": "Clearwater Plumbing Co. (duplicate CRM row)",
      "country": "US",
      "city": "Aurora"
    },
    {
      "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/brightside-hvac/",
      "clientRecordId": "demo-004",
      "businessName": "Brightside HVAC"
    },
    {
      "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/parked-domain-demo/",
      "clientRecordId": "demo-005"
    },
    {
      "website": "https://excluded-demo.example/",
      "clientRecordId": "demo-006",
      "businessName": "Excluded by input"
    },
    {
      "website": "not a url",
      "clientRecordId": "demo-007"
    }
  ],
  "targetServiceCategories": [
    "roofing",
    "plumbing"
  ],
  "defaultCountry": "US",
  "maxDomains": 20,
  "maxPagesPerDomain": 4,
  "excludedDomains": [
    "excluded-demo.example"
  ]
}' |
apify call mortenm/local-business-prospect-qualifier --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mortenm/local-business-prospect-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/mQmTbW1xQ7nWNUzrx/builds/g7jhtodSMIlOr6fii/openapi.json
