# Lead Qualifier - score scraped leads against your ICP (`jev-tools/lead-qualifier`) Actor

Takes the companies or contacts any scraper produced and scores each one against your own ideal customer profile: a 0-10 fit score, a qualified / review / disqualified verdict, and a reason label. Pay only for leads it actually scored.

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

## Pricing

$5.00 / 1,000 lead scoreds

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

## Lead Qualifier — score scraped leads against your own ICP

You already have a scraper that produces companies or contacts. This scores each
one against **your** ideal customer profile and hands back a sorted list:

| | |
| --- | --- |
| **score** | 0–10 fit, so you can sort and work top-down |
| **verdict** | `qualified` · `review` · `disqualified` |
| **reason** | one label: `strong_icp_match`, `wrong_geography`, `excluded_account`, `no_authority`, … |
| **signals** | the per-signal probabilities behind the score, so you can re-threshold without paying again |

Point it at any dataset — LinkedIn, Apollo, Google Maps, a company-list scraper,
your own CSV — describe who you sell to, and run it.

### Why not just filter by keyword

Keyword rules break on the cases that matter. This run, on a corpus of 240
labelled leads, got all of these right:

- `Lenze SE`, `lenze`, and `Lenze Drive Technologies` all recognised as the same
  excluded competitor — **0.988 accuracy on exclusion matching**
- `Vestlund Nordic AB` recognised as a subsidiary of an excluded customer
- a company in the UK correctly held for `review` rather than killed, when the
  target regions were Germany, Austria, Switzerland, the Netherlands and the
  Nordics — neighbouring markets are a judgement call, not a reject
- `process automation` held for review against a target list of `industrial
  automation` — adjacent, not unrelated
- a perfect-fit company whose only contact was `info@` sent to `review`, because
  there is no decision maker to call

### It is built not to lose your leads

The expensive mistake is throwing away a real lead, so the whole thing is
asymmetric by design. Measured on the labelled corpus:

| | |
| --- | --- |
| Verdict accuracy, three buckets | **0.929** |
| **Qualified leads wrongly disqualified** | **0** |
| **Disqualified leads wrongly passed as qualified** | **0** |
| Precision of the `qualified` bucket | 0.833 |
| Recall of the `qualified` bucket | 0.875 |

Every mistake it does make is one step in the cautious direction — into
`review`, where a human sees it. Uncertainty always widens the net:

- a sparse row is never disqualified, because thin data is not evidence
- a low-confidence judgement is downgraded to `review`, in both directions
- an account showing an active buying trigger is never hard-killed on a weak fit
- the only thing that may disqualify outright is **your own instruction**: your
  exclusion list, or a confidently unrelated industry or region

### What you pay

You are billed **per lead scored**. Not per lead returned, and **never for a
lead that could not be judged** — those come back flagged with `billed: false`.
`maxItems` is a hard ceiling on the run, so the cost is known before you start.

If more than a fifth of the leads cannot be judged, the run **fails** instead of
handing you a list that looks complete but is not. You are not billed for them.

### Input

- **buyerProfile** (required) — who you sell to. `target_industries`,
  `target_size`, `target_regions`, `buyer_roles`, `buying_triggers`, and
  `exclusions` with `competitors`, `existing_customers`, `blocked_domains`.
  Every field optional; more detail means sharper scoring.
- **sourceDatasetId** — any scraper run's dataset. Or paste records into
  **leads** instead.
- **keepVerdicts** / **minScore** — what lands in the output. Everything is
  scored and billed regardless; these only trim the list you get back.
- **maxItems**, **concurrency**, **idField**, **includeAnswers**.

### Output

One row per returned lead, with your original fields kept alongside `score`,
`verdict`, `reason`, `confidence`, `rationale`, `rules_applied` and optionally
`signals`. A `RUN_SUMMARY` record in the key-value store holds the counts,
timing and which verdicts were kept.

### Speed

About 13 leads a second at the default concurrency; 1,000 leads in roughly a
minute and a half.

# Actor input Schema

## `buyerProfile` (type: `object`):

Who you sell to, and who you never want contacted. Every field is optional, but the more you give the sharper the scoring: target\_industries, target\_size, target\_regions, buyer\_roles, buying\_triggers, and exclusions (competitors, existing\_customers, blocked\_domains).

## `sourceDatasetId` (type: `string`):

The dataset ID of any scraper run whose items you want scored. Leave empty and paste records into 'leads' instead.

## `leads` (type: `array`):

Records to score, if you are not reading them from a dataset. Any shape is accepted; the fields are read as they are.

## `idField` (type: `string`):

Falls back to the row number when the field is missing.

## `maxItems` (type: `integer`):

A hard ceiling on how many leads get scored, and therefore on what this run can cost you.

## `keepVerdicts` (type: `array`):

Everything is scored and billed; this only decides what lands in the output dataset.

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

Drop anything scoring below this from the output. 0 keeps everything.

## `concurrency` (type: `integer`):

Parallel judgements. 12 scores about 13 leads a second.

## `includeAnswers` (type: `boolean`):

Adds the calibrated signal probabilities to every row so you can re-threshold the results yourself without paying again.

## Actor input object example

```json
{
  "buyerProfile": {
    "sells": "industrial motion-control retrofit kits",
    "target_industries": [
      "industrial automation",
      "packaging machinery"
    ],
    "target_size": "50-1000 employees",
    "target_regions": [
      "Germany",
      "Netherlands",
      "Nordics"
    ],
    "buyer_roles": [
      "VP Operations",
      "Plant Manager",
      "Automation Lead"
    ],
    "buying_triggers": [
      "hiring automation engineers",
      "new plant or line",
      "recent funding"
    ],
    "exclusions": {
      "competitors": [
        "Acme Drives"
      ],
      "existing_customers": [],
      "blocked_domains": []
    }
  },
  "idField": "id",
  "maxItems": 1000,
  "keepVerdicts": [
    "qualified",
    "review"
  ],
  "minScore": 0,
  "concurrency": 12,
  "includeAnswers": true
}
```

# 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 = {
    "buyerProfile": {
        "sells": "industrial motion-control retrofit kits",
        "target_industries": [
            "industrial automation",
            "packaging machinery"
        ],
        "target_size": "50-1000 employees",
        "target_regions": [
            "Germany",
            "Netherlands",
            "Nordics"
        ],
        "buyer_roles": [
            "VP Operations",
            "Plant Manager",
            "Automation Lead"
        ],
        "buying_triggers": [
            "hiring automation engineers",
            "new plant or line",
            "recent funding"
        ],
        "exclusions": {
            "competitors": [
                "Acme Drives"
            ],
            "existing_customers": [],
            "blocked_domains": []
        }
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("jev-tools/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 = { "buyerProfile": {
        "sells": "industrial motion-control retrofit kits",
        "target_industries": [
            "industrial automation",
            "packaging machinery",
        ],
        "target_size": "50-1000 employees",
        "target_regions": [
            "Germany",
            "Netherlands",
            "Nordics",
        ],
        "buyer_roles": [
            "VP Operations",
            "Plant Manager",
            "Automation Lead",
        ],
        "buying_triggers": [
            "hiring automation engineers",
            "new plant or line",
            "recent funding",
        ],
        "exclusions": {
            "competitors": ["Acme Drives"],
            "existing_customers": [],
            "blocked_domains": [],
        },
    } }

# Run the Actor and wait for it to finish
run = client.actor("jev-tools/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 '{
  "buyerProfile": {
    "sells": "industrial motion-control retrofit kits",
    "target_industries": [
      "industrial automation",
      "packaging machinery"
    ],
    "target_size": "50-1000 employees",
    "target_regions": [
      "Germany",
      "Netherlands",
      "Nordics"
    ],
    "buyer_roles": [
      "VP Operations",
      "Plant Manager",
      "Automation Lead"
    ],
    "buying_triggers": [
      "hiring automation engineers",
      "new plant or line",
      "recent funding"
    ],
    "exclusions": {
      "competitors": [
        "Acme Drives"
      ],
      "existing_customers": [],
      "blocked_domains": []
    }
  }
}' |
apify call jev-tools/lead-qualifier --silent --output-dataset

```

## MCP server setup

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