# B2B Leads List Builder — Maps + Email + Phone Enrichment (`bovi/b2b-leads-list-builder`) Actor

Give it a city + industry, get a ready-to-work B2B prospect list: company, website, email, phone, address, industry, LinkedIn — one flat row per lead, in one run. Maps search → website visit → email + phone harvest → MX-verify. No chaining actors.

- **URL**: https://apify.com/bovi/b2b-leads-list-builder.md
- **Developed by:** [Vitalii Bondarev](https://apify.com/bovi) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.90 / 1,000 b2b leads

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.md):

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

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.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/platform/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

## B2B Leads List Builder — Maps + Email + Phone Enrichment

**Give it a city + an industry. Get back a ready-to-work B2B prospect list — company name, website, email, phone, address, industry, and LinkedIn — as one flat row per lead, in a single run.**

Most "leads" tools hand you either raw map listings (name + address, no way to reach anyone) or a domain-only list you then have to feed into a *second* actor to find emails, and maybe a *third* for phones. This actor runs that whole waterfall for you in one pass:

````

Google Maps search  →  visit each business website  →  harvest email + phone + socials  →  MX-verify  →  flat lead row

````

No chaining actors. No stitching datasets together. One input, one output, ready for your CRM or sequencer.

---

### What you get — one flat row per lead

| Field | Description |
|-------|-------------|
| `company_name` | Business name from Google Maps |
| `website` | Business website URL |
| `email` | Best harvested email (MX-verified when verification is on) |
| `phone` | Phone number (from Maps and/or the website) |
| `address` | Full street address |
| `city` / `state` / `country` | Address split into parts for filtering & dedupe |
| `industry` | Primary category (e.g. "Marketing agency", "Dentist", "Plumber") |
| `maps_rating` / `maps_review_count` | Google Maps social proof — qualify before you reach out |
| `linkedin_url` | Company LinkedIn profile, when linked from the site |
| `all_emails` | Every distinct email found (not just the primary) |
| `email_status` | `valid` · `role` · `risky` · `invalid` · `found` · `none` |
| `email_source` | Where the email came from (`website_contact` / `website`) |
| `social_links` | Other social profiles found (Twitter/X, Facebook, Instagram, …) |
| `parse_confidence` | 0–1 quality signal per row |
| `scraped_at` | UTC timestamp |

By default the actor returns **only reachable leads** — every row carries at least an email or a phone. Name-only listings you can't actually contact are dropped (and never charged). Flip `requireContact` off if you also want the no-contact places.

---

### Why one run instead of three

The cheapest way to get to a usable prospect list today is to chain: a Maps scraper → an email finder → a contact extractor, exporting and re-importing a dataset between each. That's three runs, three bills, and a brittle pipeline.

This actor bakes the proven contact-enrichment logic from our `email-finder` and `website-contact-extractor` directly into the Maps crawl. For each place that has a website, it fetches the homepage plus the highest-yield contact pages (contact / about / imprint / team), de-obfuscates the common `name [at] domain [dot] com` tricks, pulls emails, phones and social profiles, and — when `verifyEmails` is on — MX-verifies each address so you know the domain actually accepts mail before you send.

---

### Input

```jsonc
{
  "queries": [
    "marketing agencies in Austin TX",
    "dentists in San Francisco CA",
    "plumbers near Denver CO 80202"
  ],
  "maxResults": 50,          // places per query (1–300, auto-paginated)
  "requireContact": true,    // only return leads with an email or phone
  "verifyEmails": true,      // MX-verify each harvested email
  "language": "en",
  "country": "us",
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
````

**Tips**

- One query ≈ one "industry in a city". For full coverage of a large metro, split into narrower queries (per neighborhood or sub-category) — Google itself caps a single area at ~120–300 places.
- Residential proxy is required: Google Maps blocks datacenter IPs. The `GOOGLE_SERP` proxy group does **not** support Maps — leave the default `RESIDENTIAL`.

***

### Output example

```json
{
  "company_name": "Acme Marketing Co",
  "website": "https://acme.com",
  "email": "hello@acme.com",
  "phone": "+1 512-555-0100",
  "address": "500 Congress Ave, Austin, TX 78701, USA",
  "city": "Austin",
  "state": "TX",
  "country": "US",
  "industry": "Marketing agency",
  "maps_rating": 4.7,
  "maps_review_count": 88,
  "linkedin_url": "https://linkedin.com/company/acme",
  "all_emails": ["hello@acme.com", "info@acme.com"],
  "email_status": "valid",
  "email_source": "website_contact",
  "parse_confidence": 1.0,
  "scraped_at": "2026-06-14T12:00:00Z"
}
```

***

### Pricing

**Pay per enriched lead.** You're charged only for billable leads — rows with a company name and at least one reachable contact (email or phone). Map listings that yield no contact are dropped at no charge, so you're not paying for rows you can't use.

> Example: a run that returns **100 enriched leads** costs **100 × the per-lead price**. Empty shells dropped along the way are free.

Platform compute (proxy, runtime) is billed to your own Apify account at Apify's standard rates, as with every Store actor.

***

### Use cases

- **SDR / outbound** — build a targeted list of "industry in city" prospects with verified emails, ready to drop into your sequencer.
- **Local market research** — map every competitor in a category and metro, with ratings and review counts to gauge market density.
- **Recruiting / agency prospecting** — find businesses in a vertical and reach the right inbox without buying a seat in an enrichment SaaS.
- **CRM enrichment** — feed a list of "category + city" searches and get flat rows you can import directly.

***

### Notes & legal

This actor collects **publicly available** business contact information (the same data a person sees on Google Maps and on the businesses' own public websites). You are responsible for using the output in compliance with applicable laws and regulations (including GDPR/CCPA and anti-spam rules such as CAN-SPAM) and with the terms of the platforms you operate on. Verify consent and legitimate interest before sending marketing communications. The actor does not access private, gated, or login-protected data.

Email verification is performed at the MX layer (does the domain accept mail?). It does not guarantee that a specific mailbox exists — a full SMTP probe is unreliable on cloud infrastructure where outbound port 25 is blocked. `email_status` is an honest signal, not a delivery guarantee.

# Actor input Schema

## `queries` (type: `array`):

One or more Google Maps searches — typically an industry + a city. Each query returns up to 'maxResults' enriched leads. Examples: 'dentists in Austin TX', 'marketing agencies San Francisco CA', 'plumbers near Denver CO 80202'.

## `proxyConfiguration` (type: `object`):

Apify proxy settings. Google Maps requires residential proxies — datacenter IPs are blocked. Default: Apify RESIDENTIAL group. Note: GOOGLE\_SERP proxy does NOT support Maps URLs.

## `maxResults` (type: `integer`):

Maximum number of places to process per search query. The actor paginates automatically (20 per page) up to 300. Google itself caps a single area at roughly 120–300 places; for fuller city coverage, split into narrower queries (per neighborhood or subcategory).

## `requireContact` (type: `boolean`):

When on (default), only leads that carry at least one email OR phone are returned and billed — name-only rows you can't actually contact are dropped at no charge. Turn off to also return places with no harvested contact.

## `verifyEmails` (type: `boolean`):

Contact enrichment is always on — the actor visits each business website (homepage + high-yield contact pages, with de-obfuscation) to extract public emails and social links. When this is enabled, every harvested email is MX-verified (does the domain accept mail?) and flagged valid / role / risky / invalid, with the best one surfaced as the lead's 'email'. Default: on.

## `language` (type: `string`):

Two-letter BCP-47 language code for result language. Default: 'en' (English).

## `country` (type: `string`):

Two-letter ISO country code for result localisation (affects which businesses appear, and the default 'country' on each lead). Default: 'us'.

## Actor input object example

```json
{
  "queries": [
    "marketing agencies in Austin TX"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxResults": 20,
  "requireContact": true,
  "verifyEmails": true,
  "language": "en",
  "country": "us"
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset of flat lead rows (company\_name, website, email, phone, address, city, state, country, industry, maps\_rating, maps\_review\_count, linkedin\_url, email\_status, email\_source, scraped\_at).

# 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 = {
    "queries": [
        "marketing agencies in Austin TX"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    },
    "maxResults": 20,
    "language": "en",
    "country": "us"
};

// Run the Actor and wait for it to finish
const run = await client.actor("bovi/b2b-leads-list-builder").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 = {
    "queries": ["marketing agencies in Austin TX"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
    "maxResults": 20,
    "language": "en",
    "country": "us",
}

# Run the Actor and wait for it to finish
run = client.actor("bovi/b2b-leads-list-builder").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 '{
  "queries": [
    "marketing agencies in Austin TX"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxResults": 20,
  "language": "en",
  "country": "us"
}' |
apify call bovi/b2b-leads-list-builder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=bovi/b2b-leads-list-builder",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "B2B Leads List Builder — Maps + Email + Phone Enrichment",
        "description": "Give it a city + industry, get a ready-to-work B2B prospect list: company, website, email, phone, address, industry, LinkedIn — one flat row per lead, in one run. Maps search → website visit → email + phone harvest → MX-verify. No chaining actors.",
        "version": "0.1",
        "x-build-id": "tlWjlyd619QrEmh5N"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/bovi~b2b-leads-list-builder/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-bovi-b2b-leads-list-builder",
                "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/bovi~b2b-leads-list-builder/runs": {
            "post": {
                "operationId": "runs-sync-bovi-b2b-leads-list-builder",
                "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/bovi~b2b-leads-list-builder/run-sync": {
            "post": {
                "operationId": "run-sync-bovi-b2b-leads-list-builder",
                "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": [
                    "queries"
                ],
                "properties": {
                    "queries": {
                        "title": "Search Queries (city + industry)",
                        "type": "array",
                        "description": "One or more Google Maps searches — typically an industry + a city. Each query returns up to 'maxResults' enriched leads. Examples: 'dentists in Austin TX', 'marketing agencies San Francisco CA', 'plumbers near Denver CO 80202'.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Apify proxy settings. Google Maps requires residential proxies — datacenter IPs are blocked. Default: Apify RESIDENTIAL group. Note: GOOGLE_SERP proxy does NOT support Maps URLs.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    },
                    "maxResults": {
                        "title": "Max Leads Per Query",
                        "minimum": 1,
                        "maximum": 300,
                        "type": "integer",
                        "description": "Maximum number of places to process per search query. The actor paginates automatically (20 per page) up to 300. Google itself caps a single area at roughly 120–300 places; for fuller city coverage, split into narrower queries (per neighborhood or subcategory).",
                        "default": 20
                    },
                    "requireContact": {
                        "title": "Only Reachable Leads (has email or phone)",
                        "type": "boolean",
                        "description": "When on (default), only leads that carry at least one email OR phone are returned and billed — name-only rows you can't actually contact are dropped at no charge. Turn off to also return places with no harvested contact.",
                        "default": true
                    },
                    "verifyEmails": {
                        "title": "Verify Emails (MX check)",
                        "type": "boolean",
                        "description": "Contact enrichment is always on — the actor visits each business website (homepage + high-yield contact pages, with de-obfuscation) to extract public emails and social links. When this is enabled, every harvested email is MX-verified (does the domain accept mail?) and flagged valid / role / risky / invalid, with the best one surfaced as the lead's 'email'. Default: on.",
                        "default": true
                    },
                    "language": {
                        "title": "Language",
                        "enum": [
                            "en",
                            "es",
                            "fr",
                            "de",
                            "it",
                            "pt",
                            "ja",
                            "ko",
                            "zh"
                        ],
                        "type": "string",
                        "description": "Two-letter BCP-47 language code for result language. Default: 'en' (English).",
                        "default": "en"
                    },
                    "country": {
                        "title": "Country",
                        "enum": [
                            "us",
                            "gb",
                            "ca",
                            "au",
                            "de",
                            "fr",
                            "es",
                            "it",
                            "jp",
                            "br",
                            "mx",
                            "in"
                        ],
                        "type": "string",
                        "description": "Two-letter ISO country code for result localisation (affects which businesses appear, and the default 'country' on each lead). Default: 'us'.",
                        "default": "us"
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
