# Law Firm Leads Scraper - Attorney Emails, Phones & Addresses (`seasoned_seaurchin/vertical-lead-engine`) Actor

Find law firms and attorneys by city: firm name, phone, address, website and rating from Google Maps, plus emails from each firm's own site with MX verification. For legal marketing, court reporting and B2B outreach teams building attorney contact lists.

- **URL**: https://apify.com/seasoned_seaurchin/vertical-lead-engine.md
- **Developed by:** [Z Michael](https://apify.com/seasoned_seaurchin) (community)
- **Categories:** Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 business 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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

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

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

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

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

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

# README

## Law Firm Leads Scraper — Attorney Emails, Phones & Addresses

Build a clean law firm contact list for any US city: **firm name, phone, address, website, rating, review count — plus the email addresses published on each firm's own website, MX-verified.**

Built for legal marketing agencies, court reporters, legal software vendors and law firm business-development teams that need a fresh attorney prospect list by city or practice area — without paying $0.20+ per lead at a legal data broker.

### What you get

| Field | Example |
|---|---|
| `name` | Harper & Cole Injury Attorneys |
| `category` | Personal injury attorney |
| `phone` | +13125550143 |
| `address` | 200 W Adams St #1200, Chicago, IL 60606 |
| `website` | https://harpercolelaw.com |
| `rating` / `reviews` | 4.6 / 187 |
| `emails` | intake@harpercolelaw.com |
| `mxVerified` | true — the domain actually accepts mail |

### Why the emails are usable

Most lead scrapers hand you a regex hit and stop there. This one:

1. Visits the firm's **own** website — homepage plus `/contact`, `/about`, `/attorneys`, and `mailto:` links.
2. **Drops directory and platform links** (FindLaw, Justia, Avvo, Lawyers.com, Martindale) — an email on a directory profile is not the firm's intake address.
3. **Cleans glued-together junk** that kills deliverability: `60606intake@x.com`, `312-555-0143info@x.com`, `USA13125550143contact@x.com` are stripped back to real addresses; domains glued to trailing marketing text are discarded.
4. **MX-verifies the domain** over DNS, so you know the mail domain resolves before you send.

Typical email coverage is **40–55% of firms**. That number is measured, not aspirational: plenty of firms only publish a contact form. Every other record still comes back with a verified phone, address and website, so nothing is wasted — you just won't find an inbox behind every single listing.

### Input

```json
{
  "searchQueries": ["personal injury attorney in Chicago IL", "family law firm in Dallas TX"],
  "maxPlacesPerQuery": 100,
  "enrichEmails": true,
  "maxWebsitesToEnrich": 100,
  "vertical": "law-firm"
}
```

- **searchQueries** — any Google Maps query. `"<practice area> in <city>"` works best: `personal injury attorney in Miami FL`, `immigration lawyer in Los Angeles CA`, `estate planning attorney in Phoenix AZ`.
- **maxPlacesPerQuery** — listings to collect per query (1–500).
- **enrichEmails** — turn website email discovery on/off. Off = faster, cheaper, phone-only list.
- **maxWebsitesToEnrich** — cap on website visits. Match it to `maxPlacesPerQuery` to get emails on every lead.
- **vertical** — a tag added to every record, useful when you merge several practice areas or cities into one sheet.

### Output

One record per firm, written to the run's dataset. Download as JSON, CSV or Excel from Apify, or pull it via the API:

```bash
curl "https://api.apify.com/v2/datasets/<datasetId>/items?format=csv&token=<your-token>" -o law-firms.csv
```

### What people use it for

- **Legal marketing and SEO agencies** — pitch website, local SEO and paid search to firms ranked below page one in a metro.
- **Court reporting and process serving** — build a per-city firm list with a working intake phone number.
- **Legal SaaS and intake software** — seed a CRM with firms by practice area and firm size proxy (review count).
- **Firm business development** — map competing firms in an adjacent practice area before a lateral hire or a new office.
- **Recruiting and M\&A** — pull every firm in a city with more than N reviews as a qualification filter.

### Cost

Pay per result: you are charged per firm delivered, plus a small one-off start fee. Website email enrichment is included in the per-result price. Platform compute is billed separately by Apify and is negligible.

Two practical notes on cost:

- **Run in batches, not in ones.** The first result of a run carries the fixed overhead of loading Google Maps; results 20–100 are nearly free on top. A 20-firm run and a 100-firm run cost almost the same in platform terms.
- **Startup time is about 40 seconds**, then roughly one second per firm. A 100-firm run finishes in about five minutes.

### Notes and limits

- Google Maps returns roughly 120–200 results per query; go narrower (neighbourhood, sub-practice-area) to go deeper than that.
- Not every firm publishes an email — contact-form-only firms come back with `emails: []`.
- `mxVerified` means the **domain** accepts mail — it is not a per-mailbox deliverability guarantee.
- Scrape responsibly: this collects publicly listed business contact data. You are responsible for GDPR/CAN-SPAM and the target sites' terms when you use the list.

### Support

Open an issue on the Actor page and include the run ID plus the query that failed.

# Actor input Schema

## `searchQueries` (type: `array`):

Google Maps queries, e.g. 'personal injury attorney in Chicago IL' or 'family law firm in Dallas TX'. One lead set per query.

## `maxPlacesPerQuery` (type: `integer`):

How many firm cards to scroll through per query. A full page is 120 results; 50-100 is a normal run.

## `enrichEmails` (type: `boolean`):

Visits each firm website (homepage + contact/about pages) and extracts emails, then MX-verifies the domain.

## `maxWebsitesToEnrich` (type: `integer`):

Max number of websites visited for email extraction per run. Keep it equal to or above maxPlacesPerQuery to get emails for every firm.

## `vertical` (type: `string`):

Tag added to every output record, e.g. law-firm, dental, roofing.

## `useApifyProxy` (type: `boolean`):

Keep this on. Google blocks datacenter IPs with captcha pages, which returns zero leads. Residential proxy traffic is included in what you pay per lead.

## `proxyGroups` (type: `array`):

Apify proxy group used for Google Maps. RESIDENTIAL is required: datacenter IPs get captcha-walled by Google.

## Actor input object example

```json
{
  "searchQueries": [
    "personal injury attorney in Chicago IL"
  ],
  "maxPlacesPerQuery": 20,
  "enrichEmails": true,
  "maxWebsitesToEnrich": 20,
  "vertical": "law-firm",
  "useApifyProxy": true,
  "proxyGroups": [
    "RESIDENTIAL"
  ]
}
```

# Actor output Schema

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

Business leads with contact details and verified emails. UTF-8 encoded dataset, downloadable as JSON, CSV or Excel.

## `leadsCsv` (type: `string`):

The same lead list as a CSV file, ready to import into a CRM or spreadsheet.

# 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 = {
    "searchQueries": [
        "personal injury attorney in Chicago IL"
    ],
    "maxPlacesPerQuery": 20,
    "maxWebsitesToEnrich": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("seasoned_seaurchin/vertical-lead-engine").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 = {
    "searchQueries": ["personal injury attorney in Chicago IL"],
    "maxPlacesPerQuery": 20,
    "maxWebsitesToEnrich": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("seasoned_seaurchin/vertical-lead-engine").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "personal injury attorney in Chicago IL"
  ],
  "maxPlacesPerQuery": 20,
  "maxWebsitesToEnrich": 20
}' |
apify call seasoned_seaurchin/vertical-lead-engine --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,seasoned_seaurchin/vertical-lead-engine"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/4GJqLCtbh9u46zSvi/builds/5AyTpeMhpfinE1XQ1/openapi.json
