# Carbon Lead Scanner (`lexicaq/carbon-lead-scanner`) Actor

Carbon Lead Scanner discovers and qualifys local business leads. It searches selected regions and business categories, collects official websites and publicly listed contact details, crawls websites for business information and email addresses, and verifies email domains using DNS/MX checks.

- **URL**: https://apify.com/lexicaq/carbon-lead-scanner.md
- **Developed by:** [max](https://apify.com/lexicaq) (community)
- **Categories:** Agents, Lead generation, AI
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

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

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use 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

## Carbon Lead Scanner

Carbon Lead Scanner turns a business category and a target region into a qualified, evidence-backed lead list. It combines local listings, search results, supplied websites, and directory pages; identifies official business domains; analyzes those websites; extracts publicly visible contact information; checks website and email-domain infrastructure; and ranks each result with transparent scoring.

Use it for local prospecting, market research, sales-list preparation, and website intelligence. Every run is configurable: choose the market, geography, target email-lead volume, discovery sources, crawl depth, verification rules, score threshold, and exports instead of being locked to one niche or location.

### What it does

1. Finds candidate companies through the selected discovery sources.
2. Normalizes domains and removes duplicates.
3. Inspects official websites and selected high-value pages.
4. Extracts public email addresses, phone numbers, addresses, descriptions, and social-profile links.
5. Checks HTTPS availability, DNS resolution, and optional email-domain MX records.
6. Detects website technologies, advertising pixels, and booking systems when requested.
7. Scores leads on a 0-100 scale and records the evidence behind the score.
8. Writes a dataset and the selected professional export files.

### Configure a run

Only four fields are required: **industry**, **region**, **qualified-lead target**, and **discovery sources**. The scanner provides sensible defaults for crawl limits, verification, filtering, reporting, discovery budgets, and the Google Maps Actor ID; every optional setting can still be changed in the Apify form.

If you choose **Provided business websites** or **Seed or directory pages**, provide at least one corresponding URL. Brave Search requires a Brave API key. The Google Maps Actor ID is only used when you select **Apify Google Maps Actor**; otherwise you can ignore it. A platform `APIFY_TOKEN` can be used for a nested Maps Actor when running on Apify; local runs can supply `apifyToken` directly.

#### Important settings

| Setting | Default | What it controls |
|---|---:|---|
| `targetCount` | Required | Target number of returned leads. With the default `requireEmail: true`, this means public business email leads, not phone-only businesses. The Actor checks candidates until it reaches this number or the configured sources/budgets are exhausted. |
| `maxCandidatesPerSource` | `100` | Discovery buffer per source. It is automatically raised to at least `targetCount x 5`, because many listings have no usable website or contact data. |
| `maxDiscoveryRounds` | `3` | Reserved compatibility setting for older custom Maps Actors. The maintained default Maps Actor runs each configured keyword/location job once because it already searches the geographic area comprehensively. |
| `googleMapsRunTimeoutSecs` | `1200` | Maximum time for one nested Apify Maps scan. If it reaches the limit, already-written map records are kept and the scanner proceeds to website checks and exports; this prevents the parent run from reaching Apify's one-hour timeout. |
| `maxDiscoveryRequests` | `40` | Hard cap across discovery API, directory, and nested Maps requests. Use it to control third-party usage and cost. |
| `maxTotalCandidates` | `200` | Maximum unique official websites inspected after discovery. It is always raised to at least `targetCount x 5`, so the scan has enough candidates to reach the target where sources permit. |
| `additionalRegions` | Empty | Districts, nearby towns, or municipalities to search separately. Useful for a metropolitan area such as Munich plus Schwabing, Garching, and Unterhaching. |
| `queryVariants` | Empty | Industry synonyms, local-language terms, or related categories. Each is combined with the selected region(s). |
| `overpassEndpoints` | Built-in fallbacks | Optional preferred Overpass endpoints. Enter your own endpoint here for higher reliability or local, cost-free OSM use. |
| `wikidataRadiusKm` | `25` | Radius used by the built-in Wikidata nearby-business query. |
| `crawlDepth` | `1` | How deeply official websites are checked; see the crawl-level table below. |
| `maxPagesPerWebsite` | `4` | Absolute maximum pages fetched for one business, regardless of crawl depth. |
| `concurrency` | `6` | Parallel website checks. Lower this for cautious, slower crawling; raise it carefully for faster runs. |
| `requestTimeoutSecs` | `20` | Per-request timeout. Slow or unavailable pages are skipped after this period. |
| `minFitScore` | `50` | Minimum 0-100 evidence score a candidate must achieve to be exported. |
| `enableGeminiEnrichment` | `false` | Opt-in, bounded website intelligence. No public website text is sent to Gemini unless you enable it and provide a key. |
| `geminiModel` | `gemini-2.5-flash-lite` | Stable low-cost default for high-volume structured website extraction. Select `gemini-2.5-flash` only when stronger reasoning is worth the higher cost. |
| `geminiMaxEnrichments` | `50` | Hard cap on eligible websites sent to Gemini. Leads beyond the cap remain fully usable with deterministic crawl data. |
| `geminiMaxInputChars` | `12000` | Maximum cleaned public website text sent for one lead. Lower it to reduce spend. |
| `geminiConcurrency` | `2` | Independent cap for simultaneous Gemini calls, protecting against rate limits and bursts. |
| `requireVerifiedMx` | `false` | Keep only public email domains with usable MX records and at least one resolvable advertised mail server. |
| `requireEmail` | `true` | Require a usable public business email in every returned target lead. Disable only if phone-only leads are acceptable. |
| `genericEmailsOnly` | `false` | Keep only role inboxes such as `info@`, `contact@`, or `office@`. |
| `requireValidPhone` | `false` | Reject a candidate only when its discovered phone has an implausible format. This is not a live-call check. |
| `excludeBookingSystems` | `false` | Exclude businesses where a booking tool is detected; useful when selling booking software. |

#### Crawl-depth levels

| Level | Pages inspected | Best use |
|---:|---|---|
| `0` | Homepage only | Fast technical triage; may miss emails listed only on Contact or Imprint pages. |
| `1` | Homepage plus linked high-value pages such as Contact, Imprint, and About | Recommended default for lead research. It usually finds public contact details without excessive crawling. |
| `2` | Level 1 plus one additional level of linked high-value internal pages | Deep research for smaller lead targets. Slower and subject to `maxPagesPerWebsite`. |

The Actor stays on the same website origin, honors `robots.txt` when enabled, and prioritizes contact-oriented pages rather than crawling an entire site.

### Discovery sources

| Source | Credential | Suitable for | Considerations |
|---|---|---|---|
| OpenStreetMap | None | Local businesses with mapped websites | Coverage and tags vary by place and industry. |
| Wikidata knowledge graph | None | Supplementary official websites, phones, addresses, and descriptions for notable/local entities | Coverage is selective. Use a custom SPARQL query for a precise niche. |
| Custom open-data or directory JSON | Optional source-specific key | Municipal data portals, trade associations, tourism lists, permitted directory APIs | You configure the endpoint and field mapping. It must contain official business website URLs. |
| Provided business websites | None | Direct research lists | You supply the official websites to analyze. |
| Seed or directory pages | None | Associations, directories, and curated lists | Crawl only pages you are permitted to use. |
| Brave Search API | Brave API key | Niche and broader web discovery | API quota and cost apply. |
| Official Google Places API | Google Cloud API key with billing | High-quality local business discovery with official website, address, phone, business status, and Maps evidence | Uses Google Maps Platform pay-as-you-go billing; set a strict request budget and API-key restrictions. |
| Apify Google Maps Actor | Apify token | Location-based business research | Nested Actor usage and Store pricing apply. |

#### Source setup guides

##### OpenStreetMap and your own Overpass endpoint

No key is required. For a normal city search, leave **OpenStreetMap fallback searches** empty and the scanner uses geocoding plus Overpass. For a large region, enter several precise Nominatim queries or use **Additional nearby regions** and **Industry synonyms**. Public Overpass services are shared infrastructure, so keep the request budget conservative. If you operate an Overpass instance yourself, add its full interpreter URL in **Custom Overpass endpoints**; it is tried before public fallbacks.

##### Wikidata

No key is required. Select **Wikidata knowledge graph**, choose a radius, and the scanner performs a nearby-business query around the selected region. It only accepts results that expose an official website, then crawls that website exactly like every other lead.

For a specialist category, use **Custom Wikidata SPARQL queries**. Each query must return a `website` variable. It can also return `item`, `itemLabel`, `phone`, `address`, and `description`; these become source-provenance fields in the result. Run and validate an advanced query in the [Wikidata Query Service](https://query.wikidata.org/) before placing it in the input form.

##### Custom municipal, association, or open-data JSON

Select **Custom open-data or directory JSON** and add one object per permitted endpoint in **Custom public-directory JSON sources**. No key is required by the scanner itself. If that endpoint requires an API key, add its documented header in `headers`; use only the key issued by that data provider, never an Apify token.

```json
[
  {
    "url": "https://data.example.gov/api/businesses",
    "recordsPath": "results.items",
    "websiteField": "website",
    "nameField": "name",
    "phoneField": "telephone",
    "emailField": "email",
    "addressField": "address",
    "descriptionField": "category",
    "headers": { "X-API-Key": "YOUR_PROVIDER_KEY" }
  }
]
````

`recordsPath` is the location of the record array inside the JSON response. Leave it blank if the response itself is an array. The `websiteField` is mandatory because the scanner intentionally crawls official company websites, not directory-listing pages.

##### Brave Search API

Create a Brave Search API key, enter it in **Brave Search API key**, then select **Brave Search API**. The key can alternatively be provided as `BRAVE_API_KEY` for local runs. Use `maxDiscoveryRequests` to limit the number of paid requests. Query variants and additional regions are automatically combined into multiple precise searches.

##### Google Maps through Apify

Select **Apify Google Maps Actor** only when you explicitly want this paid optional source. The default Actor ID is `microworlds/crawler-google-places`; it is not required for any other source. On the Apify platform, the platform token is supplied automatically. For a local run, provide `apifyToken` or set `APIFY_TOKEN`.

The default Maps Actor expects `keywords` and `location` (or `custom_geolocation`), not `searchStringsArray`. The scanner now supplies `keywords: [industry]` and `location: region` itself. Add `queryVariants` and `additionalRegions` to make separate keyword/location jobs. For advanced use, `googleMapsInput` may contain `keywords`, `location`, or `custom_geolocation`; it is passed using the current documented contract. The optional Maps Actor contact add-on is deliberately disabled: this scanner crawls and verifies each official website itself, so it does not silently add contact-enrichment fees.

Maps scans can be slow for large cities because the nested Actor divides the area into many map segments. `googleMapsRunTimeoutSecs` defaults to 20 minutes so the parent Actor always has time left to crawl, validate, score, and export results. A timed-out nested scan is not discarded: the scanner reads its already-written dataset records and continues. Raise this limit only when you also increase the parent run timeout in Apify's **Run options**.

##### Official Google Places API — recommended Maps source

Select **Official Google Places API** to use Google’s documented Places API directly inside this scanner. This is the recommended replacement for the nested public Apify Google Maps Actor when you are on Apify’s Creator plan: it does not call another Apify Store Actor.

1. Create or select a Google Cloud project.
2. Enable **Places API (New)** and attach a billing account.
3. Create an API key, restrict it to **Places API (New)**, and ideally restrict it to the Apify runtime only if your Google Cloud setup supports a safe server-side restriction.
4. Paste the key into **Google Places API key** or set `GOOGLE_PLACES_API_KEY` for a local run.
5. Select **Official Google Places API**, set a country code such as `DE` or `US`, and keep `maxDiscoveryRequests` within your intended Google API budget.

The scanner uses the official Text Search (New) endpoint and asks only for the business name, address, official website, public phone, business status, primary type, and Maps evidence URL. It skips permanently closed businesses and records only entries with an official website, which the normal website crawler then verifies and enriches. Google bills Places requests by requested fields and usage, so this source is not free; the response field mask and request budget are intentionally explicit. Follow Google Maps Platform terms, including applicable limits on storing or displaying Google-sourced content.

##### Gemini website enrichment — optional, bounded, and evidence-grounded

Gemini is never required for discovery, qualification, email extraction, DNS/MX checks, or scoring. Enable it only when you want an additional structured reading of already-crawled public website text. It returns a concise summary, explicit services, explicit customer segments, a cautious outreach angle, confidence, and up to three evidence quotes that must occur verbatim in the supplied website text.

1. Create a Gemini API key in [Google AI Studio](https://aistudio.google.com/app/apikey).
2. Enable **Gemini website enrichment** in the Actor input.
3. Paste the key into **Gemini API key**. It is secret in Apify; for local runs, use `GEMINI_API_KEY` instead.
4. Keep the default **Gemini 2.5 Flash-Lite** for the strongest low-cost, high-volume option. Choose **Gemini 2.5 Flash** only if you accept a higher cost for deeper reasoning.
5. Start with `geminiMaxEnrichments: 10`, `geminiConcurrency: 1`, and `geminiMaxInputChars: 8000`; inspect the `gemini` section of `SUMMARY.json` before increasing limits.

The integration uses Google’s Generate Content API with JSON-only output, low temperature, bounded input/output sizes, independent concurrency, timeout handling, and retries only for temporary rate-limit or server errors. Every result is application-validated after JSON parsing. If Gemini fails, times out, is rate-limited, produces invalid output, or reaches its per-run cap, the lead remains available and deterministic crawl results are retained. AI output never contributes points to `fitScore`, never changes the acceptance decision, and never creates or verifies contact details.

Gemini receives only the bounded public website text already fetched by the crawler, plus the company name, URL, industry, and region. Do not enable it for pages or data you are not permitted to send to Google. The `AI Intelligence` Excel sheet, raw JSON, and dataset `ai` view preserve the status, model, structured output, grounded evidence quotes, and a non-sensitive failure note.

#### Source choices that are intentionally not built in

Yelp’s current free access is an evaluation trial and its listings do not consistently provide an official website suitable for compliant website-first qualification. OpenCorporates is useful for legal-entity enrichment, but its standard limits and reuse licence make it unsuitable as a broad free website-discovery source. Common Crawl and Internet Archive data can be stale and therefore are not used to claim a current contact method. These can be connected through a permitted custom JSON source only when you have a compliant, current data feed.

### Outputs

The Actor always writes qualified leads to the Apify dataset. Select any combination of the following standalone exports for the run:

| File | Purpose |
|---|---|
| `RESULTS.json` | Clean lead-record array for integrations. |
| `REPORT.json` | Detailed structured report containing run metadata, summary, leads, and optional rejected candidates. |
| `RESULTS.csv` | Universal table export for simple imports. |
| `RESULTS.xlsx` | Formatted workbook with an executive summary, qualified leads, technical intelligence, raw data, and rejected-candidate audit. |
| `REPORT.html` | Responsive, searchable report for browser review. |
| `REPORT.pdf` | Presentation-ready PDF with executive metrics, score distribution, qualification funnel, lead directory, and website-intelligence table. |
| `SUMMARY.json` | Compact metrics and limitation notes for the run. |

The Excel, HTML, and PDF files are designed for review as well as export: they use clear hierarchy, score-focused visual treatment, structured tables, and explanatory notes. The PDF is generated only when **Executive PDF intelligence report** is selected.

### Run locally

Requirements: Node.js 20 or newer.

```bash
npm install
cp examples/local-input.json examples/my-input.json
## Review and set every field in examples/my-input.json for your own run.
npm run build
node dist/src/main.js --input examples/my-input.json --output-dir output
```

The local input file is an explicit example. Generated files are written to the directory passed with `--output-dir`.

For a no-paid-source Munich configuration with OpenStreetMap, Wikidata, regional expansion, MX checks, and all report formats, start from [`examples/munich-hair-salons-local.json`](examples/munich-hair-salons-local.json). Review its industry and region settings before use; it deliberately has no Brave, Maps, or custom-directory key.

#### Run locally with Docker

```bash
docker build -t carbon-lead-scanner .
docker run --rm \
  -v "$PWD/examples:/usr/src/app/examples:ro" \
  -v "$PWD/output:/usr/src/app/output" \
  carbon-lead-scanner \
  node dist/src/main.js --input examples/local-input.json --output-dir output
```

### Deploy to Apify

1. Create a new **TypeScript** Actor in Apify Console.
2. Replace the generated source with this project, keeping `.actor/`, `src/`, `examples/`, `Dockerfile`, `package.json`, and `tsconfig.json`.
3. Build the Actor.
4. Open **Input**, set the four required fields, adjust optional settings when needed, and start it.
5. Review the dataset and selected file links under **Output**.

You can also deploy from a local checkout:

```bash
npm install -g apify-cli
apify login
apify push
```

### Understanding verification and scoring

#### Email-domain verification

`emailReachability = verified-domain` means all of the following checks passed:

1. The public email address has a syntactically valid domain.
2. The domain is not on the disposable-email list.
3. DNS returns one or more MX records for the domain.
4. The MX records do not contain a null-MX entry, which explicitly states that the domain does not receive email.
5. The MX hostname is not recognized as a parked or suspicious mail host.
6. At least one advertised MX hostname resolves to an IPv4 or IPv6 address.

This verifies that the domain publishes working mail-routing infrastructure. It does **not** prove that the exact mailbox exists, is monitored, accepts unsolicited messages, or will deliver a message. The Actor deliberately does not issue SMTP `RCPT TO` probes because they are unreliable, frequently blocked, and can create legal or operational problems.

#### Fit score: exact values

The Actor starts with discovery confidence worth 40% of the score, then adds evidence from the official website. The final score is capped at 100. Every accepted lead includes a `scoreSignals` array that lists the points actually awarded.

| Evidence | Points |
|---|---:|
| Discovery confidence | Up to `40` (`sourceConfidence x 0.40`) |
| Public usable business email found | `+20` |
| Email domain matches the official website domain | `+5` |
| Verified mail-domain infrastructure | `+10` |
| Public phone number found | `+10` |
| Public address found | `+5` |
| Description with at least 40 characters | `+5` |
| Public social profile found | `+3` |
| Website technology identified | `+5` |
| Advertising or tracking signal identified | `+3` |
| Working HTTPS | `+2` |
| DNS resolution confirmed | `+2` |

Typical discovery-confidence contributions are approximately `33` for Apify Google Maps, `29` for OpenStreetMap, `28` for provided URLs, and `27` for Brave Search or Nominatim fallback results.

Example: a Google Maps business with a company-domain email, verified mail infrastructure, phone, address, HTTPS, and DNS earns roughly `33 + 20 + 5 + 10 + 10 + 5 + 2 + 2 = 87` before any extra technology, description, social, or advertising signals.

#### Quality tiers

| Tier | Meaning |
|---|---|
| `STRICT` | A usable public email was found. |
| `MODERATE` | No email, but a phone was found and the score is at least 75. |
| `RELAXED` | A phone was found, but the score is below 75. |
| `ULTRA-RELAXED` | No usable public email or phone was found; these normally disappear when `requireContactMethod` is enabled. |

`targetCount` is a completion target, not a promise that the real web contains that many businesses matching the selected filters. By default every returned lead has a public email. The scanner continues through its discovery and website-inspection buffer until it obtains the requested count, then stops. If it still cannot reach the count, `SUMMARY.json` and the run log report `target-not-reached` with the genuine shortfall and source health details rather than presenting a partial set as successful completion. Increase source coverage or the explicitly shown discovery/candidate budgets only when you want the Actor to spend more time or paid-source usage.

### Built-in reliability and intelligence improvements

- **True target-oriented processing:** discovery gathers a larger website pool, then keeps qualifying leads until the target is reached or the configured candidate budget is exhausted.
- **Cost guardrails:** `maxDiscoveryRequests` caps external discovery calls and `maxTotalCandidates` caps website inspections. Both values appear in the summary limitations.
- **Source health report:** `SUMMARY.json` includes `discoverySourceStats` with requests, candidates, status, and a failure or budget note for every selected source.
- **Field provenance:** each lead includes `fieldSources`, showing whether the company name, email, phone, address, description, or website originated from a selected source or the official website crawl.
- **Phone plausibility:** results include `phoneValid`; when enabled, the scanner rejects obvious invalid formats. It does not call or otherwise contact the number.
- **Multi-source deduplication:** official domains are normalized and deduplicated across all sources, with the strongest discovery confidence retained.
- **Evidence-first exports:** JSON, CSV, Excel, HTML, and PDF keep source, evidence URLs, score signals, infrastructure checks, and rejected-candidate reasons.

### Responsible use

Only crawl pages and collect data you are permitted to access. Respect robots.txt, site terms, rate limits, database rights, privacy law, and outreach rules such as GDPR and ePrivacy requirements. Publicly visible contact data is not automatic permission for unsolicited marketing. Retain evidence URLs and establish an appropriate lawful basis before outreach.

### Development checks

```bash
npm test
npm run build
```

The test suite verifies input strictness, source credential rules, URL normalization, and scoring behavior.

# Actor input Schema

## `industry` (type: `string`):

Describe the exact market to find, for example dentists or solar installers.

## `region` (type: `string`):

City, state, country, or another geographic area for discovery.

## `targetCount` (type: `integer`):

The number of qualifying leads to return. By default, every returned target lead must have a usable public business email. The Actor keeps checking the candidate buffer until it reaches this target or the selected sources and configured budgets are exhausted.

## `discoverySources` (type: `array`):

Choose every source to use for this run. Costs and coverage vary by source.

## `openStreetMapSearches` (type: `array`):

Optional Nominatim business searches used directly when supplied, or after Overpass discovery is unavailable.

## `additionalRegions` (type: `array`):

Optional districts, towns, or neighboring municipalities to search separately. This expands coverage without silently changing your main region.

## `queryVariants` (type: `array`):

Optional alternative search phrases such as barber, hairdresser, or Friseur. They are combined with the selected region(s).

## `overpassEndpoints` (type: `array`):

Optional preferred Overpass API endpoints, including your own local or hosted endpoint. Enter full HTTPS URLs; leave empty to use built-in public fallbacks.

## `wikidataQueries` (type: `array`):

Optional advanced SPARQL queries for Wikidata. Each query must return a website variable and may return item, itemLabel, phone, address, and description. Leave empty for the built-in nearby-business query.

## `wikidataRadiusKm` (type: `integer`):

Radius around the selected region used by the built-in Wikidata query.

## `customDirectorySources` (type: `array`):

Optional JSON endpoints from permitted municipal, association, or open-data directories. Every source must declare a URL and the field containing the official business website.

## `startUrls` (type: `array`):

List official business websites to inspect directly. Required only with Provided business websites.

## `seedPages` (type: `array`):

List pages whose external business links may be discovered. Required only with Seed or directory pages.

## `braveApiKey` (type: `string`):

Required when Brave Search API is selected. The key is kept secret.

## `googlePlacesApiKey` (type: `string`):

Required only for Official Google Places API. Create a Google Cloud key with Places API (New) enabled and billing configured. The key is kept secret.

## `googlePlacesLanguageCode` (type: `string`):

Language for Google Places results, for example en or de.

## `googlePlacesRegionCode` (type: `string`):

Optional two-letter country/region code used by Google Places to format and bias results, for example DE or US.

## `googlePlacesPageSize` (type: `integer`):

Results requested per official Google Places API call. Lower values provide tighter cost control; Google permits up to 20.

## `enableGeminiEnrichment` (type: `boolean`):

Optionally send bounded public website text to Gemini for grounded summaries, service extraction, customer segments, and a cautious outreach angle. It never discovers contacts or changes the score.

## `geminiApiKey` (type: `string`):

Required only when Gemini website enrichment is enabled. Create the key in Google AI Studio; it is kept secret and can also be supplied as GEMINI\_API\_KEY locally.

## `geminiModel` (type: `string`):

Flash-Lite is the stable low-cost default for high-volume website extraction. Flash is available when you want stronger reasoning at a higher cost.

## `geminiMaxEnrichments` (type: `integer`):

Hard maximum number of eligible websites sent to Gemini in this run. Remaining leads keep deterministic crawl data without AI enrichment.

## `geminiMaxInputChars` (type: `integer`):

Maximum cleaned public website characters sent to Gemini for each eligible lead. Lower values reduce cost; 12000 preserves useful homepage and contact-page context.

## `geminiMaxOutputTokens` (type: `integer`):

Maximum Gemini output tokens per website. The Actor requests compact JSON only; a lower limit reduces cost.

## `geminiConcurrency` (type: `integer`):

Maximum Gemini API calls in flight. Keep this low to avoid rate limits and unexpected spend.

## `geminiTimeoutSecs` (type: `integer`):

Maximum seconds to wait for one Gemini response before it is retried or safely skipped.

## `geminiRetryCount` (type: `integer`):

Retries for temporary Gemini rate-limit, timeout, and server errors. Invalid responses are not retried repeatedly.

## `geminiMinWebsiteChars` (type: `integer`):

Skip Gemini when the crawled public website text is shorter than this amount, preventing low-value model calls.

## `apifyToken` (type: `string`):

Provide a token for a nested Google Maps Actor when running locally. On Apify, the platform token is available automatically.

## `googleMapsActorId` (type: `string`):

Used only when Apify Google Maps Actor is selected. The default is the maintained Maps Actor with keywords and location inputs.

## `googleMapsInput` (type: `object`):

Optional advanced JSON for the maintained nested Maps Actor. Use keywords (an array), location (a place name), or custom\_geolocation (GeoJSON). The scanner supplies your industry and region automatically when these are omitted.

## `googleMapsRunTimeoutSecs` (type: `integer`):

Maximum time for one nested Maps Actor run. When it reaches this limit, already-collected map records are retained and this Actor continues with website checks and exports instead of allowing the whole run to hit Apify's one-hour timeout.

## `maxCandidatesPerSource` (type: `integer`):

Discovery buffer before duplicates and low-quality candidates are removed. The Actor automatically raises this to at least five times the qualified-lead target.

## `maxDiscoveryRounds` (type: `integer`):

How many rounds each selected discovery source may run while seeking new official website domains. The Actor stops earlier when a round adds no new domains.

## `maxDiscoveryRequests` (type: `integer`):

Hard cap across discovery API and directory requests. It limits third-party usage and cost; increase it only when the selected sources need more query variants.

## `maxTotalCandidates` (type: `integer`):

Hard cap for unique official websites that may be crawled after discovery. It is automatically kept at least five times the qualified-lead target.

## `crawlDepth` (type: `integer`):

0 = homepage only; 1 = homepage plus Contact, Imprint, and About pages; 2 = one further level of those high-value internal pages. maxPagesPerWebsite still limits total requests.

## `maxPagesPerWebsite` (type: `integer`):

Maximum number of pages inspected for each company website.

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

Number of website checks performed in parallel.

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

Maximum wait time before an HTTP request is skipped.

## `respectRobotsTxt` (type: `boolean`):

Use website robots.txt rules when crawling internal pages.

## `userAgent` (type: `string`):

Crawler identification string; replace the example contact with your monitored address.

## `requireHttps` (type: `boolean`):

Reject websites that do not have a working HTTPS URL.

## `verifyDns` (type: `boolean`):

Check whether the website domain resolves in DNS.

## `verifyMx` (type: `boolean`):

Check mail-domain infrastructure; this does not verify an individual mailbox.

## `requireVerifiedMx` (type: `boolean`):

Reject leads whose public email domain has no usable MX record.

## `requireEmail` (type: `boolean`):

When enabled, phone-only businesses are excluded and targetCount means the number of leads with a usable public business email. Disable only when phone-only leads are acceptable.

## `allowPersonalEmailProviders` (type: `boolean`):

Retain Gmail, GMX, Outlook-style and similar personal addresses.

## `genericEmailsOnly` (type: `boolean`):

Keep role inboxes such as info@, contact@, or office@ only.

## `requireValidPhone` (type: `boolean`):

Reject a candidate when its discovered phone number has an implausible length or obviously invalid pattern. This is format validation, not a live call check.

## `requireContactMethod` (type: `boolean`):

Reject candidates where no usable public email or phone number is found.

## `excludeBookingSystems` (type: `boolean`):

Reject businesses where a booking system is detected.

## `detectTechStack` (type: `boolean`):

Collect signature-based CMS and frontend technology signals.

## `detectAdPixels` (type: `boolean`):

Collect common Google, Meta, LinkedIn, and TikTok tracking signals.

## `extractSocials` (type: `boolean`):

Collect public social profile links from company websites.

## `minFitScore` (type: `integer`):

Minimum 0-100 score a lead must reach to be accepted.

## `includeRejected` (type: `boolean`):

Include rejected candidates and their reasons in the audit exports.

## `exportFormats` (type: `array`):

Select every standalone file to generate alongside the Apify dataset.

## `debug` (type: `boolean`):

Write detailed discovery and crawl diagnostics to the run log.

## Actor input object example

```json
{
  "discoverySources": [
    "openstreetmap"
  ],
  "openStreetMapSearches": [],
  "additionalRegions": [],
  "queryVariants": [],
  "overpassEndpoints": [],
  "wikidataQueries": [],
  "wikidataRadiusKm": 25,
  "customDirectorySources": [],
  "startUrls": [],
  "seedPages": [],
  "googlePlacesLanguageCode": "en",
  "googlePlacesRegionCode": "",
  "googlePlacesPageSize": 20,
  "enableGeminiEnrichment": false,
  "geminiModel": "gemini-2.5-flash-lite",
  "geminiMaxEnrichments": 50,
  "geminiMaxInputChars": 12000,
  "geminiMaxOutputTokens": 400,
  "geminiConcurrency": 2,
  "geminiTimeoutSecs": 30,
  "geminiRetryCount": 2,
  "geminiMinWebsiteChars": 500,
  "googleMapsActorId": "microworlds/crawler-google-places",
  "googleMapsInput": {},
  "googleMapsRunTimeoutSecs": 1200,
  "maxCandidatesPerSource": 100,
  "maxDiscoveryRounds": 3,
  "maxDiscoveryRequests": 40,
  "maxTotalCandidates": 200,
  "crawlDepth": 1,
  "maxPagesPerWebsite": 4,
  "concurrency": 6,
  "requestTimeoutSecs": 20,
  "respectRobotsTxt": true,
  "userAgent": "CarbonLeadScanner/2.0 (+contact: your-email@example.com)",
  "requireHttps": true,
  "verifyDns": true,
  "verifyMx": true,
  "requireVerifiedMx": false,
  "requireEmail": true,
  "allowPersonalEmailProviders": false,
  "genericEmailsOnly": false,
  "requireValidPhone": false,
  "requireContactMethod": true,
  "excludeBookingSystems": false,
  "detectTechStack": true,
  "detectAdPixels": true,
  "extractSocials": true,
  "minFitScore": 50,
  "includeRejected": true,
  "exportFormats": [
    "json",
    "csv",
    "xlsx",
    "html",
    "pdf"
  ],
  "debug": false
}
```

# Actor output Schema

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

No description

## `table` (type: `string`):

No description

## `ai` (type: `string`):

No description

## `json` (type: `string`):

No description

## `reportJson` (type: `string`):

No description

## `csv` (type: `string`):

No description

## `excel` (type: `string`):

No description

## `report` (type: `string`):

No description

## `pdf` (type: `string`):

No description

## `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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("lexicaq/carbon-lead-scanner").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("lexicaq/carbon-lead-scanner").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call lexicaq/carbon-lead-scanner --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=lexicaq/carbon-lead-scanner",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Carbon Lead Scanner",
        "description": "Carbon Lead Scanner discovers and qualifys local business leads. It searches selected regions and business categories, collects official websites and publicly listed contact details, crawls websites for business information and email addresses, and verifies email domains using DNS/MX checks.",
        "version": "0.0",
        "x-build-id": "7zAJGJbqY86etnZZB"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/lexicaq~carbon-lead-scanner/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-lexicaq-carbon-lead-scanner",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/lexicaq~carbon-lead-scanner/runs": {
            "post": {
                "operationId": "runs-sync-lexicaq-carbon-lead-scanner",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/lexicaq~carbon-lead-scanner/run-sync": {
            "post": {
                "operationId": "run-sync-lexicaq-carbon-lead-scanner",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "industry",
                    "region",
                    "targetCount",
                    "discoverySources"
                ],
                "properties": {
                    "industry": {
                        "title": "Industry or niche",
                        "minLength": 1,
                        "type": "string",
                        "description": "Describe the exact market to find, for example dentists or solar installers."
                    },
                    "region": {
                        "title": "Region",
                        "minLength": 1,
                        "type": "string",
                        "description": "City, state, country, or another geographic area for discovery."
                    },
                    "targetCount": {
                        "title": "Target lead emails",
                        "minimum": 1,
                        "maximum": 5000,
                        "type": "integer",
                        "description": "The number of qualifying leads to return. By default, every returned target lead must have a usable public business email. The Actor keeps checking the candidate buffer until it reaches this target or the selected sources and configured budgets are exhausted."
                    },
                    "discoverySources": {
                        "title": "Discovery sources",
                        "minItems": 1,
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Choose every source to use for this run. Costs and coverage vary by source.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "openstreetmap",
                                "wikidata",
                                "customDirectory",
                                "providedUrls",
                                "seedPages",
                                "braveSearch",
                                "googlePlaces",
                                "apifyGoogleMaps"
                            ],
                            "enumTitles": [
                                "OpenStreetMap",
                                "Wikidata knowledge graph",
                                "Custom open-data or directory JSON",
                                "Provided business websites",
                                "Seed or directory pages",
                                "Brave Search API",
                                "Official Google Places API",
                                "Apify Google Maps Actor"
                            ]
                        },
                        "default": [
                            "openstreetmap"
                        ]
                    },
                    "openStreetMapSearches": {
                        "title": "OpenStreetMap fallback searches",
                        "type": "array",
                        "description": "Optional Nominatim business searches used directly when supplied, or after Overpass discovery is unavailable.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "additionalRegions": {
                        "title": "Additional nearby regions",
                        "type": "array",
                        "description": "Optional districts, towns, or neighboring municipalities to search separately. This expands coverage without silently changing your main region.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "queryVariants": {
                        "title": "Industry synonyms or variants",
                        "type": "array",
                        "description": "Optional alternative search phrases such as barber, hairdresser, or Friseur. They are combined with the selected region(s).",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "overpassEndpoints": {
                        "title": "Custom Overpass endpoints",
                        "type": "array",
                        "description": "Optional preferred Overpass API endpoints, including your own local or hosted endpoint. Enter full HTTPS URLs; leave empty to use built-in public fallbacks.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "wikidataQueries": {
                        "title": "Custom Wikidata SPARQL queries",
                        "type": "array",
                        "description": "Optional advanced SPARQL queries for Wikidata. Each query must return a website variable and may return item, itemLabel, phone, address, and description. Leave empty for the built-in nearby-business query.",
                        "items": {
                            "type": "string"
                        },
                        "default": []
                    },
                    "wikidataRadiusKm": {
                        "title": "Wikidata search radius (km)",
                        "minimum": 1,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Radius around the selected region used by the built-in Wikidata query.",
                        "default": 25
                    },
                    "customDirectorySources": {
                        "title": "Custom public-directory JSON sources",
                        "type": "array",
                        "description": "Optional JSON endpoints from permitted municipal, association, or open-data directories. Every source must declare a URL and the field containing the official business website.",
                        "items": {
                            "type": "object"
                        },
                        "default": []
                    },
                    "startUrls": {
                        "title": "Known business websites",
                        "type": "array",
                        "description": "List official business websites to inspect directly. Required only with Provided business websites.",
                        "default": [],
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "seedPages": {
                        "title": "Seed or directory pages",
                        "type": "array",
                        "description": "List pages whose external business links may be discovered. Required only with Seed or directory pages.",
                        "default": [],
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "braveApiKey": {
                        "title": "Brave Search API key",
                        "type": "string",
                        "description": "Required when Brave Search API is selected. The key is kept secret."
                    },
                    "googlePlacesApiKey": {
                        "title": "Google Places API key",
                        "type": "string",
                        "description": "Required only for Official Google Places API. Create a Google Cloud key with Places API (New) enabled and billing configured. The key is kept secret."
                    },
                    "googlePlacesLanguageCode": {
                        "title": "Google Places language code",
                        "type": "string",
                        "description": "Language for Google Places results, for example en or de.",
                        "default": "en"
                    },
                    "googlePlacesRegionCode": {
                        "title": "Google Places region code",
                        "type": "string",
                        "description": "Optional two-letter country/region code used by Google Places to format and bias results, for example DE or US.",
                        "default": ""
                    },
                    "googlePlacesPageSize": {
                        "title": "Google Places results per request",
                        "minimum": 1,
                        "maximum": 20,
                        "type": "integer",
                        "description": "Results requested per official Google Places API call. Lower values provide tighter cost control; Google permits up to 20.",
                        "default": 20
                    },
                    "enableGeminiEnrichment": {
                        "title": "Enable Gemini website enrichment",
                        "type": "boolean",
                        "description": "Optionally send bounded public website text to Gemini for grounded summaries, service extraction, customer segments, and a cautious outreach angle. It never discovers contacts or changes the score.",
                        "default": false
                    },
                    "geminiApiKey": {
                        "title": "Gemini API key",
                        "type": "string",
                        "description": "Required only when Gemini website enrichment is enabled. Create the key in Google AI Studio; it is kept secret and can also be supplied as GEMINI_API_KEY locally."
                    },
                    "geminiModel": {
                        "title": "Gemini enrichment model",
                        "enum": [
                            "gemini-2.5-flash-lite",
                            "gemini-2.5-flash"
                        ],
                        "type": "string",
                        "description": "Flash-Lite is the stable low-cost default for high-volume website extraction. Flash is available when you want stronger reasoning at a higher cost.",
                        "default": "gemini-2.5-flash-lite"
                    },
                    "geminiMaxEnrichments": {
                        "title": "Maximum Gemini-enriched websites",
                        "minimum": 1,
                        "maximum": 1000,
                        "type": "integer",
                        "description": "Hard maximum number of eligible websites sent to Gemini in this run. Remaining leads keep deterministic crawl data without AI enrichment.",
                        "default": 50
                    },
                    "geminiMaxInputChars": {
                        "title": "Gemini website-text limit",
                        "minimum": 1000,
                        "maximum": 50000,
                        "type": "integer",
                        "description": "Maximum cleaned public website characters sent to Gemini for each eligible lead. Lower values reduce cost; 12000 preserves useful homepage and contact-page context.",
                        "default": 12000
                    },
                    "geminiMaxOutputTokens": {
                        "title": "Gemini output-token limit",
                        "minimum": 100,
                        "maximum": 2048,
                        "type": "integer",
                        "description": "Maximum Gemini output tokens per website. The Actor requests compact JSON only; a lower limit reduces cost.",
                        "default": 400
                    },
                    "geminiConcurrency": {
                        "title": "Concurrent Gemini requests",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Maximum Gemini API calls in flight. Keep this low to avoid rate limits and unexpected spend.",
                        "default": 2
                    },
                    "geminiTimeoutSecs": {
                        "title": "Gemini request timeout",
                        "minimum": 5,
                        "maximum": 90,
                        "type": "integer",
                        "description": "Maximum seconds to wait for one Gemini response before it is retried or safely skipped.",
                        "default": 30
                    },
                    "geminiRetryCount": {
                        "title": "Gemini retry count",
                        "minimum": 0,
                        "maximum": 3,
                        "type": "integer",
                        "description": "Retries for temporary Gemini rate-limit, timeout, and server errors. Invalid responses are not retried repeatedly.",
                        "default": 2
                    },
                    "geminiMinWebsiteChars": {
                        "title": "Minimum text before Gemini",
                        "minimum": 100,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Skip Gemini when the crawled public website text is shorter than this amount, preventing low-value model calls.",
                        "default": 500
                    },
                    "apifyToken": {
                        "title": "Apify token for the nested Maps run",
                        "type": "string",
                        "description": "Provide a token for a nested Google Maps Actor when running locally. On Apify, the platform token is available automatically."
                    },
                    "googleMapsActorId": {
                        "title": "Google Maps Actor ID",
                        "type": "string",
                        "description": "Used only when Apify Google Maps Actor is selected. The default is the maintained Maps Actor with keywords and location inputs.",
                        "default": "microworlds/crawler-google-places"
                    },
                    "googleMapsInput": {
                        "title": "Additional Google Maps Actor input",
                        "type": "object",
                        "description": "Optional advanced JSON for the maintained nested Maps Actor. Use keywords (an array), location (a place name), or custom_geolocation (GeoJSON). The scanner supplies your industry and region automatically when these are omitted.",
                        "default": {}
                    },
                    "googleMapsRunTimeoutSecs": {
                        "title": "Nested Google Maps run limit (seconds)",
                        "minimum": 60,
                        "maximum": 2700,
                        "type": "integer",
                        "description": "Maximum time for one nested Maps Actor run. When it reaches this limit, already-collected map records are retained and this Actor continues with website checks and exports instead of allowing the whole run to hit Apify's one-hour timeout.",
                        "default": 1200
                    },
                    "maxCandidatesPerSource": {
                        "title": "Candidate buffer per source",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Discovery buffer before duplicates and low-quality candidates are removed. The Actor automatically raises this to at least five times the qualified-lead target.",
                        "default": 100
                    },
                    "maxDiscoveryRounds": {
                        "title": "Maximum discovery rounds",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "How many rounds each selected discovery source may run while seeking new official website domains. The Actor stops earlier when a round adds no new domains.",
                        "default": 3
                    },
                    "maxDiscoveryRequests": {
                        "title": "Maximum discovery requests",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Hard cap across discovery API and directory requests. It limits third-party usage and cost; increase it only when the selected sources need more query variants.",
                        "default": 40
                    },
                    "maxTotalCandidates": {
                        "title": "Maximum website candidates to inspect",
                        "minimum": 1,
                        "maximum": 50000,
                        "type": "integer",
                        "description": "Hard cap for unique official websites that may be crawled after discovery. It is automatically kept at least five times the qualified-lead target.",
                        "default": 200
                    },
                    "crawlDepth": {
                        "title": "Website crawl depth",
                        "minimum": 0,
                        "maximum": 2,
                        "type": "integer",
                        "description": "0 = homepage only; 1 = homepage plus Contact, Imprint, and About pages; 2 = one further level of those high-value internal pages. maxPagesPerWebsite still limits total requests.",
                        "default": 1
                    },
                    "maxPagesPerWebsite": {
                        "title": "Maximum pages per website",
                        "minimum": 1,
                        "maximum": 15,
                        "type": "integer",
                        "description": "Maximum number of pages inspected for each company website.",
                        "default": 4
                    },
                    "concurrency": {
                        "title": "Concurrent website checks",
                        "minimum": 1,
                        "maximum": 30,
                        "type": "integer",
                        "description": "Number of website checks performed in parallel.",
                        "default": 6
                    },
                    "requestTimeoutSecs": {
                        "title": "Request timeout in seconds",
                        "minimum": 5,
                        "maximum": 60,
                        "type": "integer",
                        "description": "Maximum wait time before an HTTP request is skipped.",
                        "default": 20
                    },
                    "respectRobotsTxt": {
                        "title": "Respect robots.txt",
                        "type": "boolean",
                        "description": "Use website robots.txt rules when crawling internal pages.",
                        "default": true
                    },
                    "userAgent": {
                        "title": "Crawler user agent",
                        "type": "string",
                        "description": "Crawler identification string; replace the example contact with your monitored address.",
                        "default": "CarbonLeadScanner/2.0 (+contact: your-email@example.com)"
                    },
                    "requireHttps": {
                        "title": "Require working HTTPS",
                        "type": "boolean",
                        "description": "Reject websites that do not have a working HTTPS URL.",
                        "default": true
                    },
                    "verifyDns": {
                        "title": "Verify DNS",
                        "type": "boolean",
                        "description": "Check whether the website domain resolves in DNS.",
                        "default": true
                    },
                    "verifyMx": {
                        "title": "Verify email-domain MX records",
                        "type": "boolean",
                        "description": "Check mail-domain infrastructure; this does not verify an individual mailbox.",
                        "default": true
                    },
                    "requireVerifiedMx": {
                        "title": "Require confirmed MX",
                        "type": "boolean",
                        "description": "Reject leads whose public email domain has no usable MX record.",
                        "default": false
                    },
                    "requireEmail": {
                        "title": "Require a public email for each target lead",
                        "type": "boolean",
                        "description": "When enabled, phone-only businesses are excluded and targetCount means the number of leads with a usable public business email. Disable only when phone-only leads are acceptable.",
                        "default": true
                    },
                    "allowPersonalEmailProviders": {
                        "title": "Allow personal email providers",
                        "type": "boolean",
                        "description": "Retain Gmail, GMX, Outlook-style and similar personal addresses.",
                        "default": false
                    },
                    "genericEmailsOnly": {
                        "title": "Keep only generic business inboxes",
                        "type": "boolean",
                        "description": "Keep role inboxes such as info@, contact@, or office@ only.",
                        "default": false
                    },
                    "requireValidPhone": {
                        "title": "Require plausible phone format",
                        "type": "boolean",
                        "description": "Reject a candidate when its discovered phone number has an implausible length or obviously invalid pattern. This is format validation, not a live call check.",
                        "default": false
                    },
                    "requireContactMethod": {
                        "title": "Require email or phone",
                        "type": "boolean",
                        "description": "Reject candidates where no usable public email or phone number is found.",
                        "default": true
                    },
                    "excludeBookingSystems": {
                        "title": "Exclude websites with booking systems",
                        "type": "boolean",
                        "description": "Reject businesses where a booking system is detected.",
                        "default": false
                    },
                    "detectTechStack": {
                        "title": "Detect website technologies",
                        "type": "boolean",
                        "description": "Collect signature-based CMS and frontend technology signals.",
                        "default": true
                    },
                    "detectAdPixels": {
                        "title": "Detect advertising and tracking pixels",
                        "type": "boolean",
                        "description": "Collect common Google, Meta, LinkedIn, and TikTok tracking signals.",
                        "default": true
                    },
                    "extractSocials": {
                        "title": "Extract social profiles",
                        "type": "boolean",
                        "description": "Collect public social profile links from company websites.",
                        "default": true
                    },
                    "minFitScore": {
                        "title": "Minimum fit score",
                        "minimum": 0,
                        "maximum": 100,
                        "type": "integer",
                        "description": "Minimum 0-100 score a lead must reach to be accepted.",
                        "default": 50
                    },
                    "includeRejected": {
                        "title": "Include rejected-candidate audit",
                        "type": "boolean",
                        "description": "Include rejected candidates and their reasons in the audit exports.",
                        "default": true
                    },
                    "exportFormats": {
                        "title": "Export formats",
                        "minItems": 1,
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Select every standalone file to generate alongside the Apify dataset.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "json",
                                "csv",
                                "xlsx",
                                "html",
                                "pdf"
                            ],
                            "enumTitles": [
                                "Structured JSON",
                                "CSV table",
                                "Formatted Excel workbook",
                                "Interactive HTML report",
                                "Executive PDF intelligence report"
                            ]
                        },
                        "default": [
                            "json",
                            "csv",
                            "xlsx",
                            "html",
                            "pdf"
                        ]
                    },
                    "debug": {
                        "title": "Verbose debug logging",
                        "type": "boolean",
                        "description": "Write detailed discovery and crawl diagnostics to the run log.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
