# FindLaw Law Firm Scraper - Attorney & Law Firm Data Extraction (`datascrapers/findlaw-scraper`) Actor

FindLaw.com law firm profiles with attorney and firm details: contact information, ratings, practice areas, and optional client reviews. Structured JSON per firm.

- **URL**: https://apify.com/datascrapers/findlaw-scraper.md
- **Developed by:** [Data Scrapers](https://apify.com/datascrapers) (community)
- **Stats:** 4 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.10 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

**FindLaw Law Firm Scraper** creates a structured dataset of law firm and attorney profiles collected from lawyers.findlaw.com. Each dataset item represents one law firm and includes its profile details — name, contact information, address, rating, practice areas, and service area — plus, when enabled, its client reviews. Query the source with FindLaw search-result (SRP) pages or individual firm profile URLs, control the result limit with `maxFirms` and `maxPages`, and retrieve records through the Apify Dataset API or export them as JSON, CSV, Excel, XML, or another supported format.

### Dataset at a glance

| Property | Value |
|---|---|
| Source | FindLaw.com — lawyers.findlaw.com |
| Record unit | One law firm profile |
| Input methods | `startUrls` (SRP pages or profile URLs) |
| Main identifiers | `wldId`, `url` |
| Delivery | Apify Dataset and API |
| Export formats | JSON, CSV, Excel, HTML, XML |
| Update model | Fresh records per Actor run |
| Pricing | Pay-per-event: $1.00 / 1,000 law firm records |

### Coverage and available records

The Actor accepts FindLaw search-result (SRP) pages and individual law firm profile URLs via `startUrls`. From an SRP page it follows result pages up to `maxPages` per starting URL (default `10`, `0` = unlimited) and extracts each firm's profile. `maxFirms` caps the total number of firms collected (`0` = unlimited).

Two conditional enrichments are controlled by toggles:

- **`extractProfileDetails`** (default `true`) — collects the firm's name, address, telephone, aggregate rating, price range, service area, and practice areas from the profile page.
- **`extractReviews`** (default `false`) — collects client reviews, each with rating, reviewer details, review text, helpful count, verification status, and publication date.

The Actor extracts the public profile fields that FindLaw renders on the profile page; it does not require login and returns only publicly listed data.

### Data dictionary

| Field | Type | Nullable | Description | Example |
|---|---:|---|---|---|
| `url` | string | No | Law firm profile URL | `"https://lawyers.findlaw.com/lawyer/firm/..."` |
| `wldId` | string | Yes | FindLaw WLD ID (firm id + profile id) | `"123456"` |
| `title` | string | Yes | Profile page SEO title | `"Smith & Associates Law Firm - Manitowoc, WI Personal Injury Attorneys"` |
| `profile.name` | string | No | Firm or attorney business name | `"Smith & Associates Law Firm"` |
| `profile.description` | string | Yes | Firm description | `"Experienced personal injury attorneys..."` |
| `profile.telephone` | string | Yes | Primary contact phone | `"(555) 123-4567"` |
| `profile.address` | object | Yes | Postal address (street, locality, region, postal code, country) | `{"streetAddress": "123 Main St", ...}` |
| `profile.image` | string | Yes | Profile image URL | `"https://lawyers.findlaw.com/images/..."` |
| `profile.aggregateRating` | object | Yes | Rating value and review count | `{"ratingValue": 4.5, "reviewCount": 28}` |
| `profile.legalName` | string | Yes | Legal business name | `"Smith & Associates LLC"` |
| `profile.priceRange` | string | Yes | Price range indicator | `"$$"` |
| `profile.areaServed` | object/string | Yes | Geographic service area | `"Manitowoc County, WI"` |
| `profile.knowsAbout` | string | Yes | Practice areas | `"Personal Injury Law, Motor Vehicle Accidents"` |
| `profile.sameAs` | array | Yes | Social / profile links | `["https://linkedin.com/company/smithlaw"]` |
| `reviews` | array | Yes | Client reviews; present only when `extractReviews` is on | see below |
| `totalReviews` | integer | Yes | Number of reviews collected for the firm | `1` |

Each item in `reviews` carries `id`, `rating`, `reviewer` (first/last name), `reviewText`, `helpful`, `featuredReview`, `publishedDate`, and `verifyStatus`. The sample records also expose flattened convenience fields (`firmName`, `phone`, `imageUrl`, `address`, `aggregateRating`) that mirror the corresponding `profile` values. The best stable field for deduplication is `wldId`, with `url` as a fallback.

### Example dataset record

The following record was produced from an SRP URL with both `extractProfileDetails` and `extractReviews` enabled.

```json
{
  "url": "https://lawyers.findlaw.com/lawyer/firm/example-law-firm",
  "wldId": "123456",
  "firmName": "Smith & Associates Law Firm",
  "phone": "(555) 123-4567",
  "imageUrl": "https://lawyers.findlaw.com/images/profiles/example.jpg",
  "title": "Smith & Associates Law Firm - Manitowoc, WI Personal Injury Attorneys",
  "address": {
    "@type": "PostalAddress",
    "streetAddress": "123 Main St",
    "addressLocality": "Manitowoc",
    "addressRegion": "WI",
    "postalCode": "54220",
    "addressCountry": "US"
  },
  "aggregateRating": { "@type": "AggregateRating", "ratingValue": 4.5, "reviewCount": 28, "bestRating": 5 },
  "profile": {
    "name": "Smith & Associates Law Firm",
    "description": "Dedicated personal injury attorneys serving Manitowoc County with over 20 years of combined experience.",
    "telephone": "(555) 123-4567",
    "priceRange": "$$",
    "areaServed": "Manitowoc County, WI",
    "knowsAbout": "Personal Injury Law, Motor Vehicle Accidents, Workers Compensation",
    "openingHours": "Mo-Fr 09:00-17:00",
    "sameAs": ["https://facebook.com/smithlaw", "https://linkedin.com/company/smithlaw"]
  },
  "reviews": [
    {
      "id": 1001,
      "rating": 5,
      "reviewer": { "firstName": "John", "lastName": "Doe" },
      "reviewText": "Excellent legal representation. They handled my case with professionalism and care.",
      "helpful": 12,
      "featuredReview": true,
      "publishedDate": "2025-11-15T10:30:00Z",
      "verifyStatus": { "verified": true, "source": "FindLaw" }
    }
  ]
}
```

### Query and input reference

| Input | Type | Required | Default | Accepted values | Description |
|---|---:|---|---|---|---|
| `startUrls` | array | Yes | SRP prefill | SRP or profile URLs | URLs to start from. |
| `extractProfileDetails` | boolean | No | `true` | `true` / `false` | Collect profile details (name, address, phone, ratings). |
| `extractReviews` | boolean | No | `false` | `true` / `false` | Collect client reviews per firm. |
| `maxFirms` | integer | No | `0` | `0` = unlimited | Maximum firms to collect. |
| `maxPages` | integer | No | `10` | `0` = unlimited | Maximum SRP pages per starting URL. |
| `proxyConfiguration` | object | No | Apify `RESIDENTIAL` | proxy config | Proxy settings; residential recommended. |

A minimal request:

```json
{
  "startUrls": [{ "url": "https://lawyers.findlaw.com/motor-vehicle-accidents-plaintiff/wisconsin/manitowoc/" }],
  "maxFirms": 20
}
```

An advanced request with reviews:

```json
{
  "startUrls": [{ "url": "https://lawyers.findlaw.com/motor-vehicle-accidents-plaintiff/wisconsin/manitowoc/" }],
  "extractProfileDetails": true,
  "extractReviews": true,
  "maxFirms": 20,
  "maxPages": 10,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

### Retrieve the data through the API

1. Start the Actor with a JSON input.
2. Wait for the run to finish, or use the synchronous `?waitForFinish=` endpoint when appropriate.
3. Read items from the run's default dataset.
4. Paginate or export the dataset.

A Python example using the Apify client:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("datascrapers/findlaw-scraper").call(
    run_input={
        "startUrls": [{"url": "https://lawyers.findlaw.com/motor-vehicle-accidents-plaintiff/wisconsin/manitowoc/"}],
        "extractProfileDetails": True,
        "extractReviews": True,
        "maxFirms": 20,
    }
)
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(len(items), "firms")
```

For other languages, use the generated API tab on the Actor page. Never place a real token in a URL or example.

### Data quality and record handling

- **Conditional fields** — `reviews` and `totalReviews` are present only when `extractReviews` is on; `profile` sub-fields depend on `extractProfileDetails`.
- **Completeness** — firms may omit optional fields such as `priceRange`, `sameAs`, or `legalName` when the source does not list them.
- **Deduplication** — deduplicate on `wldId` (or `url`). Re-runs can repeat the same firm.
- **Retries** — requests are retried with backoff; a residential proxy is recommended for reliable access.
- **Normalization** — address is preserved as a structured `PostalAddress` object; ratings are numeric with `bestRating` where present.
- **Raw versus derived** — all fields are source values; the Actor does not derive additional metrics.

### Export and pipeline examples

| Destination | Recommended method | Typical use |
|---|---|---|
| PostgreSQL / Supabase | Dataset API or webhook consumer | CRM / lead storage |
| Google Sheets | Apify integration | Prospect lists for outreach |
| S3 / cloud storage | Scheduled export or integration | Market snapshots by region |
| CRM (HubSpot/Salesforce) | Webhook or integration | Firm and contact enrichment |

### Pricing and cost examples

Billing is pay-per-event. Each law firm record written to the dataset is one billable result at $0.001, equivalent to **$1.00 per 1,000 law firm records**.

| Records | Estimated base cost |
|---:|---:|
| 1,000 firms | $1.00 |
| 10,000 firms | $10.00 |

Estimates assume the standard tier. Enabling `extractReviews` does not add a separate per-review charge for this Actor; the billable unit is the firm record.

### Limitations and responsible data use

- The Actor collects publicly accessible FindLaw directory data only.
- Profile fields depend on what each firm lists; some fields may be empty.
- No historical snapshots are guaranteed unless you store the exported datasets yourself.
- The Actor does not access non-public or login-gated information.
- You are responsible for complying with applicable privacy, contractual, and legal requirements when using the data.

### Dataset questions

#### What does one dataset item represent?

One law firm (or attorney) profile, optionally with its client reviews attached.

#### Which field should I use as a unique identifier?

Use `wldId` when present; fall back to `url`.

#### Are fields nullable or conditional?

Yes. `reviews`, `totalReviews`, and several `profile` sub-fields are conditional on the toggles and on what the source lists for a firm.

#### Can I retrieve the records as CSV or JSON?

Yes. Export from the run's dataset in JSON, CSV, Excel, HTML, or XML, or read the dataset through the API.

#### What counts as a billable result?

Each law firm record written to the dataset. Reviews do not add a separate per-item charge.

#### Does the Actor return historical data?

No. Each run returns the records available at crawl time. Schedule recurring runs to build your own history.

### Related datasets from Data Scrapers

- **Yelp Scraper** — business listings with reviews; comparable for local business and contact data.
- **Clutch.co Company Scraper** — company profiles and reviews for B2B service providers.
- **LinkedIn Company Scraper** — company details and employee data for firm research.
- **Trustpilot Scraper** — review and reputation data for businesses.
- **Glassdoor Jobs Scraper** — job and employer data for market analysis.

### Data Scrapers support

Need an additional field, record type, or export workflow? Contact Data Scrapers at stardustspotlight@gmail.com. Include a sample source URL, the required fields, the expected record volume, and your preferred delivery format.

# Actor input Schema

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

URLs to start scraping from. Enter SRP (search result) pages or individual law firm profile pages.

## `extractProfileDetails` (type: `boolean`):

Extract detailed law firm profile information from the page (name, address, phone, ratings, etc.).

## `extractReviews` (type: `boolean`):

Extract client reviews for each law firm from the reviews API.

## `maxFirms` (type: `integer`):

Maximum number of law firms to scrape (0 = unlimited).

## `maxPages` (type: `integer`):

Maximum number of search result pages to follow per starting URL (0 = unlimited).

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

Proxy settings for anti-bot protection. Apify Residential proxies are recommended for reliable scraping.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://lawyers.findlaw.com/motor-vehicle-accidents-plaintiff/wisconsin/manitowoc/"
    }
  ],
  "extractProfileDetails": true,
  "extractReviews": false,
  "maxFirms": 20,
  "maxPages": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `run` (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 = {
    "startUrls": [
        {
            "url": "https://lawyers.findlaw.com/motor-vehicle-accidents-plaintiff/wisconsin/manitowoc/"
        }
    ],
    "maxFirms": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("datascrapers/findlaw-scraper").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 = {
    "startUrls": [{ "url": "https://lawyers.findlaw.com/motor-vehicle-accidents-plaintiff/wisconsin/manitowoc/" }],
    "maxFirms": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("datascrapers/findlaw-scraper").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 '{
  "startUrls": [
    {
      "url": "https://lawyers.findlaw.com/motor-vehicle-accidents-plaintiff/wisconsin/manitowoc/"
    }
  ],
  "maxFirms": 20
}' |
apify call datascrapers/findlaw-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datascrapers/findlaw-scraper"
        }
    }
}
```

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/RlrseWdJCkOeSj0xg/builds/tRw3GuaZpECfeNAj6/openapi.json
