# Lead Qualifier — Google Maps No-Website Leads & AI Openers (`crawlem/lead-qualifier`) Actor

Find Google Maps businesses with no website, a broken site or only a Facebook page, audit their sites, and get an AI outreach opener for each lead.

- **URL**: https://apify.com/crawlem/lead-qualifier.md
- **Developed by:** [Eugene Coetzee](https://apify.com/crawlem) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 ai outreach openers

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

**Find local businesses with no website, a broken site, or only a Facebook page — and get a ready-to-send outreach opener for each.**

Lead Qualifier takes the places you scraped with [Google Maps Scraper](https://apify.com/compass/crawler-google-places) and tells you which ones actually need a web agency. Businesses with **no website**, a **broken website** or **only a social or booking page** come first. Every business that does have a website gets a **quick website audit**: HTTPS, mobile-friendliness, speed, whether Google can index it, contact buttons, outdated technology and more. That produces a **0–100 "needs help" score**, plain-English reasons, the services to pitch, and an optional **AI-written first line for your cold email** that mentions one real, observed problem.

It runs on the Apify platform, so you get API access, scheduling, integrations (Zapier, Make, Google Sheets, webhooks) and run monitoring out of the box. It uses lightweight HTTP checks, with no browser, so runs are fast and cheap.

### What does Lead Qualifier do?

- **Finds the easy wins.** Listings with no website, a website that is down or returns an error, an expired security certificate, or only a Facebook / Instagram / Linktree / booking page.
- **Audits every real website.** HTTPS and "Not secure" warnings, mobile viewport, server response time, a site hidden from Google (robots.txt / noindex), old copyright year, missing click-to-call or contact form, free website-builder addresses, outdated technology, LocalBusiness structured data, meta description and analytics.
- **Scores and explains.** A 0–100 score, a tier (`hot`, `warm`, `cold`, `no_website`, `social_only`, `broken_site`, …), the top reasons in plain English, and the services to pitch.
- **Writes the opener.** Two short, friendly sentences (25–35 words): **one** issue the owner can check themselves, then your offer. No invented claims, no hype.
- **Cleans up Google Maps noise.** Groups duplicate listings and branches of the same business by name, phone number and address, so you never pitch "you have no website" to a branch of a business that has one.

### Why use Lead Qualifier?

- **Web design and SEO agencies:** start outreach with businesses that clearly need a website or a fix, not with a raw list of 500 places.
- **Freelancers:** get a short, personal first line for every lead instead of writing each one by hand.
- **Lead generation services:** hand clients a qualified list with reasons and services attached.
- **Pay only for what you use:** listings without a website of their own are free to score. See [pricing](#how-much-does-it-cost-to-qualify-google-maps-leads).

### How to use Lead Qualifier

1. Run [Google Maps Scraper](https://apify.com/compass/crawler-google-places) for a search such as "dentist in Cape Town".
2. Open Lead Qualifier and choose that run's dataset in **Google Maps Scraper dataset ID**.
3. Set **What you offer** (e.g. "website redesign and local SEO") so openers match your service.
4. Click **Start**. In our tests, 100 Google Maps leads finished in under a minute.
5. Open the **Outreach** view in the Output tab, filter by tier, and export to CSV, Excel or Google Sheets.

No Google Maps data yet? The input form is prefilled with example businesses and test websites, so you can click **Start** straight away and see every kind of result.

### Chain it after Google Maps Scraper

1. In [Google Maps Scraper](https://apify.com/compass/crawler-google-places), search for your niche and area and run it. Keep the default output fields: title, website, phone, category, address, rating and reviews are all used.
2. In Lead Qualifier, click the **Google Maps Scraper dataset ID** field and **pick the dataset with the dataset picker**. Picking it there gives this Actor permission to read it. A typed-in ID of a dataset the Actor has no access to fails with a clear "Can't read dataset" message.
3. **Add Only these categories (`categoryKeywords`).** Google Maps results almost always include unrelated places: a search for dentists also returns banks, pharmacies and hotels nearby. Add words such as `dentist` and `dental`. Leads whose Maps category doesn't match are skipped **before** any website is fetched, and they are never charged.
4. Start the run. To automate the whole pipeline, add an [integration](https://docs.apify.com/platform/integrations) on the Google Maps Scraper Actor that starts Lead Qualifier with the new dataset whenever a scrape finishes.

Calling it from the API:

```json
{
    "datasetId": "YOUR_GOOGLE_MAPS_DATASET_ID",
    "categoryKeywords": ["dentist", "dental"],
    "agencyOffer": "website redesign and local SEO",
    "openerMinScore": 40
}
```

### Input

All fields are optional except one lead source. See the **Input** tab for the full form.

| Field | Default | What it does |
|---|---|---|
| `datasetId` | – | Google Maps Scraper dataset, chosen with the dataset picker. |
| `businesses` | – | Business objects in Google Maps Scraper format (title, website, phone, categoryName, address, …). |
| `urls` | – | Plain website URLs, if you don't use Google Maps. |
| `categoryKeywords` | – | Only process leads whose Maps category contains one of these words. Others are skipped and free. |
| `minScore` | 0 | Only output leads scoring at least this much. Leads that couldn't be checked are always included, free. |
| `generateOpener` | true | Write an AI outreach opener for each qualifying lead. |
| `openerMinScore` | 40 | Only write (and charge for) openers at or above this score. No-website, social-only and broken-site leads always qualify. |
| `agencyOffer` | website redesign and local SEO | Your service, used in the opener. |
| `openerLanguage` | English | Language of the opener. |
| `maxLeads` | 500 | Maximum number of unique leads processed. |
| `maxConcurrency` | 20 | Websites checked in parallel. |

### Output

One row per lead, **best leads first** (hot, warm, broken, social only, no website, cold; then rows that couldn't be checked). Two ready-made table views: **Overview** (score, tier, top reasons) and **Outreach** (phone, website, pitch, opener, and an **opener status** that says why a row has no opener). You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

| Business | Tier | Score | Top reasons | Opener |
|---|---|---|---|---|
| Oakview Dental | no\_website | 95 | No website listed on Google Maps | Oakview Dental has no website listed on Google Maps. We build simple, fast sites for dental practices so new patients can find your hours and book online. |
| Kloof Street Barbers | warm | 55 | No HTTPS — browsers mark the site as 'Not secure' · Not mobile-friendly (no viewport meta tag) · Copyright notice says 2019 — site looks unmaintained | Visitors to your site see a 'Not secure' label next to the address. We can fix that and bring the site up to date so it works well on phones. |
| Harbour Plumbing Co | broken\_site | 90 | Website returns an HTTP 404 error | Anyone clicking the website link on your Google Maps listing lands on an error page. We can get it working again and keep it running smoothly. |
| Maple Physio (Facebook only) | social\_only | 92 | Only has a social media page — no website of its own | Maple Physio's only web presence is a Facebook page. We help physiotherapists set up their own site so patients can find and book you directly. |
| Northside Smiles | cold | 7 | No major issues found | – |

Simplified JSON for the first two rows (fictional businesses):

```json
[
    {
        "name": "Oakview Dental",
        "category": "Dentist",
        "address": "12 Oakview Rd, Springfield",
        "phone": "+1 555 0142",
        "website": null,
        "score": 95,
        "tier": "no_website",
        "reasons": ["No website listed on Google Maps"],
        "topReasons": "No website listed on Google Maps",
        "recommendedServices": ["new website build"],
        "reputationOpportunity": false,
        "contactable": true,
        "duplicateOf": null,
        "opener": "Oakview Dental has no website listed on Google Maps. We build simple, fast sites for dental practices so new patients can find your hours and book online.",
        "openerStatus": "written",
        "status": "ok"
    },
    {
        "name": "Kloof Street Barbers",
        "category": "Barber shop",
        "phone": "+1 555 0178",
        "website": "http://kloofstreetbarbers.example/",
        "finalUrl": "http://kloofstreetbarbers.example/",
        "score": 55,
        "tier": "warm",
        "reasons": [
            "No HTTPS — browsers mark the site as 'Not secure'",
            "Not mobile-friendly (no viewport meta tag)",
            "Copyright notice says 2019 — site looks unmaintained",
            "No LocalBusiness structured data for Google",
            "No analytics or ad tracking (GA4, Tag Manager, Meta pixel)"
        ],
        "topReasons": "No HTTPS — browsers mark the site as 'Not secure' · Not mobile-friendly (no viewport meta tag) · Copyright notice says 2019 — site looks unmaintained",
        "recommendedServices": ["SSL certificate / HTTPS setup", "mobile-responsive redesign", "website refresh", "local SEO / structured data", "analytics & conversion tracking"],
        "signals": { "https": false, "has_viewport_meta": false, "copyright_year": 2019, "server_wait_ms": 640, "platform": "wordpress" },
        "opener": "Visitors to your site see a 'Not secure' label next to the address. We can fix that and bring the site up to date so it works well on phones.",
        "openerStatus": "written",
        "status": "ok"
    }
]
```

### Data fields

| Field | Description |
|---|---|
| `name`, `category`, `address`, `phone`, `mapsUrl` | From Google Maps. |
| `website`, `finalUrl`, `domain` | The listed website and where it ended up after redirects. |
| `socialUrl` | The social, link or booking page listed instead of a website. |
| `relatedWebsite` | For a branch: the website of the business it belongs to. |
| `score` | 0–100 "needs help" score (higher = better lead). `null` when the site couldn't be checked. |
| `tier` | `hot` (70–100), `warm` (40–69), `cold` (0–39), `no_website`, `social_only`, `broken_site`, `unverified`, `branch_of_known_site`. |
| `reasons`, `topReasons` | Every issue found, and the three most visible ones as one line. |
| `recommendedServices` | What to pitch, e.g. "mobile-responsive redesign", "local SEO / structured data". |
| `reputationOpportunity` | Rating under 4.0 or fewer than 10 reviews: a review-generation pitch. |
| `contactable` | `false` when there is no website of its own and no phone number. |
| `duplicateOf` | Set on extra listings of the same business. |
| `opener` | The AI outreach opener, or `null`. |
| `openerStatus` | Why the row has or lacks an opener: `written`; `free_plan_limit` (the free plan's 10 openers went to better leads); `below_openerMinScore`; `not_contactable` (no website of its own and no phone); `no_pitchable_issue` (nothing an owner would recognise); `unverified_or_error`; `duplicate_or_branch`; `generation_failed` (drafts kept breaking our quality rules or the AI service was unavailable; not charged); `disabled` (openers turned off, or the AI service rejected the key); `charge_limit` (your maximum charge couldn't cover it); `run_stopped` (the run was aborted or hit its timeout before this opener was written). |
| `signals` | Every raw check (response time, platform, schema, robots.txt, …) for your own filtering. |
| `status`, `error`, `checkedAt` | `ok` or `error`, the error message, and when the lead was checked. |

### How much does it cost to qualify Google Maps leads?

**Free Apify plan: 10 AI openers per run.**

Pricing is **pay per event**. You're charged for exactly two things:

| Event | Price | When it's charged |
|---|---|---|
| Website audited (`lead-scored`) | **$0.004** per lead ($4 per 1,000) | A website was fetched and scored: `hot`, `warm`, `cold` or `broken_site`. |
| AI opener (`ai-opener`) | **$0.005** per opener | An opener was written and delivered. Openers that break our quality rules are discarded and not charged. |
| Everything else | **Free** | `no_website`, `social_only`, branches, duplicates, `unverified`, errors, uncontactable leads, and leads skipped by `categoryKeywords`. |

**Worked example: 100 dentists from Google Maps.** About a quarter of the listings have their own website. That's 25 websites audited ($0.10) and 72 openers written ($0.36), for **about $0.46 for the whole list**. The 75 listings without a website cost nothing to score; you only pay for the openers written for them.

On Apify's free plan, openers are limited to **10 per run**. They go to your **best leads**, with at least one from each tier present (hot, warm, broken site, social only, no website), so you see the full range. Every lead is still scored and delivered; the rest show `openerStatus: free_plan_limit`, and the run log and status message say when the limit was reached.

### Tips for better results and lower cost

- **Control spend with `minScore` and `openerMinScore`.** For example, `openerMinScore: 70` writes openers only for your hottest leads. `minScore: 40` drops cold leads from the output (and from the audit charge).
- **Always set `categoryKeywords` for Google Maps data.** Unrelated places are skipped before any fetch and cost nothing.
- **Word `agencyOffer` the way you'd say it to a client:** "website redesign and local SEO", "mobile-friendly websites for clinics", "Google Business Profile setup". The opener's second sentence is built around it.
- **Use the Outreach view** and filter `contactable = true` to get a call or email list straight away.
- **Allow enough run time for big lists.** Unresponsive sites are retried for up to 20 seconds, so 500 leads can take several minutes. If a run hits its timeout anyway, everything audited so far is still delivered.
- **Leave `maxConcurrency` at 20.** Higher values rarely speed things up and may trigger more bot protection on target sites.

### Known limitations

- **No JavaScript rendering.** Sites built entirely in the browser (React / Vite single-page apps) and "loader" pages come out as `unverified` ("Couldn't load the full homepage — verify manually"), and they're free. The Actor never scores an empty shell.
- **Response times are measured from our servers.** We time the server's wait (excluding connection setup), but part of any delay can still be distance. That's why the thresholds are generous (3 s and 5 s).
- **Grouping is heuristic.** Listings are matched by name, phone number and street address. A shared reception number can merge different practitioners at one practice, and two unrelated businesses with the same distinctive name in one run could be grouped.
- **Copyright years added by JavaScript aren't read.** A footer that fills in the year in the browser counts as "no year found", which is never penalised.
- **Bot protection.** Sites behind strict bot protection (Cloudflare challenges, 403 or 429 responses) are marked `unverified` and are free. Check them in your browser.

### FAQ, disclaimers and support

**Why are some rows free?**
You only pay for websites we actually audit. Listings with no website, only a social or booking page, branches and duplicates of another listing, sites we couldn't check, errors, and leads without any contact method are all delivered free, so you can still use them.

**Why doesn't this row have an opener?**
Check the `openerStatus` column in the Outreach view. It says exactly why: for example `below_openerMinScore` (lower `openerMinScore` to include it), `not_contactable`, `free_plan_limit`, or `generation_failed`. You're only charged for rows with `written`.

**Why is a site "broken" if it loads for me?**
A site is `broken_site` only for a clear failure: a 404/410 or server error, a domain that doesn't resolve, a refused connection, a bad SSL certificate, or no response. A site that doesn't answer within 10 seconds is **retried once with 20 seconds** before it counts ("Website didn't respond within 20 seconds (may be down or very slow)"). A very slow site may still load for you, and that's worth mentioning to the owner.

**What if my run is aborted or times out?**
Every lead audited so far is delivered, best first, with the openers already written. Leads that were still waiting show `openerStatus: run_stopped`. You only pay for rows that were delivered.

**Why is a site "unverified"?**
We couldn't see the real homepage. The site blocked automated checks, served a JavaScript "loader" page, or had a certificate chain that browsers may accept but our check can't. Open it in your browser: it may be fine, or it may be a lead.

**How are openers written? Will they make things up?**
Openers are written by Claude (Anthropic) from structured facts only: the business name and category from Google Maps, one issue we observed, and your offer. The model never sees the website's content. Every opener is checked before delivery: exactly two sentences and at most 40 words, no invented claims about customers ("may" and "can", never "can't find you"), and no mention of AI or scores. Drafts that break a rule are rewritten; if they keep failing, the lead gets no opener and you aren't charged.

**Is it legal to use these leads for outreach?**
The Actor only reads publicly available business information. You are responsible for making sure your outreach complies with the laws that apply to you and your recipients, such as **GDPR**, **POPIA** and **CAN-SPAM**: lawful basis, opt-out, identifying yourself, and respecting "do not contact" requests.

**Something looks wrong, or you need a custom version?**
Open an issue in the **Issues** tab with the run ID. Custom checks, other languages and CRM integrations are available on request.

# Actor input Schema

## `datasetId` (type: `string`):

The dataset produced by a Google Maps Scraper run. Pick it with the dataset picker so this Actor is allowed to read it. Every place in it is scored. Leave empty if you use the fields below.

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

Business objects in Google Maps Scraper shape. Fields used: title, website, phone, categoryName, address, city, totalScore, reviewsCount, url, placeId. All are optional. The prefilled examples are test sites that show each result type (no website, social page only, broken, blocked, scored).

## `urls` (type: `array`):

Plain website URLs to audit, e.g. https://example.com. A missing scheme is fine.

## `categoryKeywords` (type: `array`):

Optional. Only process leads whose Google Maps category contains one of these words (case-insensitive), e.g. "dentist", "dental". Other leads are skipped before any website is fetched and are never charged. Leads without a category (plain URLs) are skipped when this is set.

## `minScore` (type: `integer`):

Only output (and pay for) leads scoring at least this much (0–100). Leads the Actor could not verify because the site blocks automated checks are always included, free of charge.

## `generateOpener` (type: `boolean`):

Write a short, personalised first line for cold outreach that references one real issue found on the site. Charged per successful opener.

## `openerMinScore` (type: `integer`):

Only write (and charge for) an opener when the lead scores at least this much (0–100). Leads with no website, only a social media page, or a broken website always get one.

## `agencyOffer` (type: `string`):

Your service, used to tailor the opener.

## `openerLanguage` (type: `string`):

Language to write the opener in, e.g. English, Spanish, Afrikaans.

## `maxLeads` (type: `integer`):

Hard cap on unique leads processed (after removing duplicate domains).

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

How many websites to check in parallel.

## Actor input object example

```json
{
  "businesses": [
    {
      "title": "Example Consulting",
      "website": "https://example.com/",
      "categoryName": "Consultant",
      "phone": "+1 555 0100",
      "address": "1 Example Way, Springfield",
      "totalScore": 4.6,
      "reviewsCount": 41,
      "placeId": "sample-1"
    },
    {
      "title": "Joe's Plumbing",
      "categoryName": "Plumber",
      "phone": "+27 21 555 0101",
      "address": "12 Long St, Cape Town",
      "totalScore": 4.9,
      "reviewsCount": 6,
      "placeId": "sample-2"
    },
    {
      "title": "Nails by Thandi",
      "website": "https://www.facebook.com/nailsbythandi",
      "categoryName": "Nail salon",
      "totalScore": 3.8,
      "reviewsCount": 22,
      "placeId": "sample-3"
    },
    {
      "title": "Expired Cert Bakery",
      "website": "https://expired.badssl.com/",
      "categoryName": "Bakery",
      "totalScore": 4.4,
      "reviewsCount": 88,
      "placeId": "sample-4"
    },
    {
      "title": "Ghost Domain Garage",
      "website": "https://lead-qualifier-test-does-not-exist.co.za/",
      "categoryName": "Auto repair shop",
      "placeId": "sample-5"
    },
    {
      "title": "HTTP Only Hardware",
      "website": "http://httpforever.com/",
      "categoryName": "Hardware store",
      "totalScore": 4.1,
      "reviewsCount": 15,
      "placeId": "sample-6"
    },
    {
      "title": "Old Town Physics Tutors",
      "website": "http://info.cern.ch/",
      "categoryName": "Tutoring service",
      "totalScore": 4.7,
      "reviewsCount": 12,
      "placeId": "sample-7"
    }
  ],
  "urls": [
    "https://httpbin.org/status/403",
    "https://www.google.com/lead-qualifier-missing-page",
    "wordpress.org",
    "https://www.python.org",
    "https://www.example.com/contact"
  ],
  "minScore": 0,
  "generateOpener": true,
  "openerMinScore": 40,
  "agencyOffer": "website redesign and local SEO",
  "openerLanguage": "English",
  "maxLeads": 500,
  "maxConcurrency": 20
}
```

# Actor output Schema

## `results` (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": [
        {
            "title": "Example Consulting",
            "website": "https://example.com/",
            "categoryName": "Consultant",
            "phone": "+1 555 0100",
            "address": "1 Example Way, Springfield",
            "totalScore": 4.6,
            "reviewsCount": 41,
            "placeId": "sample-1"
        },
        {
            "title": "Joe's Plumbing",
            "categoryName": "Plumber",
            "phone": "+27 21 555 0101",
            "address": "12 Long St, Cape Town",
            "totalScore": 4.9,
            "reviewsCount": 6,
            "placeId": "sample-2"
        },
        {
            "title": "Nails by Thandi",
            "website": "https://www.facebook.com/nailsbythandi",
            "categoryName": "Nail salon",
            "totalScore": 3.8,
            "reviewsCount": 22,
            "placeId": "sample-3"
        },
        {
            "title": "Expired Cert Bakery",
            "website": "https://expired.badssl.com/",
            "categoryName": "Bakery",
            "totalScore": 4.4,
            "reviewsCount": 88,
            "placeId": "sample-4"
        },
        {
            "title": "Ghost Domain Garage",
            "website": "https://lead-qualifier-test-does-not-exist.co.za/",
            "categoryName": "Auto repair shop",
            "placeId": "sample-5"
        },
        {
            "title": "HTTP Only Hardware",
            "website": "http://httpforever.com/",
            "categoryName": "Hardware store",
            "totalScore": 4.1,
            "reviewsCount": 15,
            "placeId": "sample-6"
        },
        {
            "title": "Old Town Physics Tutors",
            "website": "http://info.cern.ch/",
            "categoryName": "Tutoring service",
            "totalScore": 4.7,
            "reviewsCount": 12,
            "placeId": "sample-7"
        }
    ],
    "urls": [
        "https://httpbin.org/status/403",
        "https://www.google.com/lead-qualifier-missing-page",
        "wordpress.org",
        "https://www.python.org",
        "https://www.example.com/contact"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlem/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 = {
    "businesses": [
        {
            "title": "Example Consulting",
            "website": "https://example.com/",
            "categoryName": "Consultant",
            "phone": "+1 555 0100",
            "address": "1 Example Way, Springfield",
            "totalScore": 4.6,
            "reviewsCount": 41,
            "placeId": "sample-1",
        },
        {
            "title": "Joe's Plumbing",
            "categoryName": "Plumber",
            "phone": "+27 21 555 0101",
            "address": "12 Long St, Cape Town",
            "totalScore": 4.9,
            "reviewsCount": 6,
            "placeId": "sample-2",
        },
        {
            "title": "Nails by Thandi",
            "website": "https://www.facebook.com/nailsbythandi",
            "categoryName": "Nail salon",
            "totalScore": 3.8,
            "reviewsCount": 22,
            "placeId": "sample-3",
        },
        {
            "title": "Expired Cert Bakery",
            "website": "https://expired.badssl.com/",
            "categoryName": "Bakery",
            "totalScore": 4.4,
            "reviewsCount": 88,
            "placeId": "sample-4",
        },
        {
            "title": "Ghost Domain Garage",
            "website": "https://lead-qualifier-test-does-not-exist.co.za/",
            "categoryName": "Auto repair shop",
            "placeId": "sample-5",
        },
        {
            "title": "HTTP Only Hardware",
            "website": "http://httpforever.com/",
            "categoryName": "Hardware store",
            "totalScore": 4.1,
            "reviewsCount": 15,
            "placeId": "sample-6",
        },
        {
            "title": "Old Town Physics Tutors",
            "website": "http://info.cern.ch/",
            "categoryName": "Tutoring service",
            "totalScore": 4.7,
            "reviewsCount": 12,
            "placeId": "sample-7",
        },
    ],
    "urls": [
        "https://httpbin.org/status/403",
        "https://www.google.com/lead-qualifier-missing-page",
        "wordpress.org",
        "https://www.python.org",
        "https://www.example.com/contact",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("crawlem/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 '{
  "businesses": [
    {
      "title": "Example Consulting",
      "website": "https://example.com/",
      "categoryName": "Consultant",
      "phone": "+1 555 0100",
      "address": "1 Example Way, Springfield",
      "totalScore": 4.6,
      "reviewsCount": 41,
      "placeId": "sample-1"
    },
    {
      "title": "Joe'\''s Plumbing",
      "categoryName": "Plumber",
      "phone": "+27 21 555 0101",
      "address": "12 Long St, Cape Town",
      "totalScore": 4.9,
      "reviewsCount": 6,
      "placeId": "sample-2"
    },
    {
      "title": "Nails by Thandi",
      "website": "https://www.facebook.com/nailsbythandi",
      "categoryName": "Nail salon",
      "totalScore": 3.8,
      "reviewsCount": 22,
      "placeId": "sample-3"
    },
    {
      "title": "Expired Cert Bakery",
      "website": "https://expired.badssl.com/",
      "categoryName": "Bakery",
      "totalScore": 4.4,
      "reviewsCount": 88,
      "placeId": "sample-4"
    },
    {
      "title": "Ghost Domain Garage",
      "website": "https://lead-qualifier-test-does-not-exist.co.za/",
      "categoryName": "Auto repair shop",
      "placeId": "sample-5"
    },
    {
      "title": "HTTP Only Hardware",
      "website": "http://httpforever.com/",
      "categoryName": "Hardware store",
      "totalScore": 4.1,
      "reviewsCount": 15,
      "placeId": "sample-6"
    },
    {
      "title": "Old Town Physics Tutors",
      "website": "http://info.cern.ch/",
      "categoryName": "Tutoring service",
      "totalScore": 4.7,
      "reviewsCount": 12,
      "placeId": "sample-7"
    }
  ],
  "urls": [
    "https://httpbin.org/status/403",
    "https://www.google.com/lead-qualifier-missing-page",
    "wordpress.org",
    "https://www.python.org",
    "https://www.example.com/contact"
  ]
}' |
apify call crawlem/lead-qualifier --silent --output-dataset

```

## MCP server setup

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