# Avvo Reviews Scraper (`solidcode/avvo-reviews-scraper`) Actor

\[💰 $1.50 / 1K] Extract reviews from Avvo lawyer profiles by URL or by lawyer-and-location search.

- **URL**: https://apify.com/solidcode/avvo-reviews-scraper.md
- **Developed by:** [SolidCode](https://apify.com/solidcode) (community)
- **Categories:** Developer tools, Lead generation
- **Features:** Limited permissions
- **Stats:** 10 total users, 4 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Avvo Reviews Scraper

Pull client reviews from Avvo lawyer profiles at scale — star ratings, review titles, full review bodies, reviewer names and relationships, posted dates, and the lawyer's official replies. Built for legal-marketing agencies, reputation-management consultants, and attorney-search platforms that need fresh, structured Avvo client feedback delivered straight to a spreadsheet, CRM, or BI dashboard.

### Why This Scraper?

- **Two input modes — URLs or free-text search** — paste lawyer profile URLs directly, or describe lawyers as `"divorce lawyers, San Francisco CA"` / `"John Smith attorney, Austin TX"` and the actor resolves each query to a real Avvo profile automatically.
- **One row per review, with parent context inlined** — every row carries `lawyerName`, `lawyerCity`, `lawyerState`, and `lawyerProfileUrl`, so a multi-lawyer run drops straight into a spreadsheet without a join.
- **Every row names the input that produced it** — `searchQuery` carries your original query through to the result, `inputUrl` carries your pasted profile URL through unchanged, and `searchMatch` flags any lawyer whose office sits outside the city or state you asked for, so a 50-query run stays auditable line by line.
- **Star-rating band filter with both ends** — `minRating` and `maxRating` bracket any slice of the 1–5 scale: `1`–`2` for the negative reviews that need a reply drafted, `4`–`5` for testimonial-grade quotes, or `3` on its own to read the ambivalent middle. Set one end or both.
- **Lawyer replies captured as structured data** — every review row carries a nested `lawyerResponse` object with the response body and posted date when the attorney has replied, so you can measure how proactively each lawyer engages with criticism.
- **"Hired Attorney" badge captured per row** — every review row carries `reviewerRelationship: "Hired Attorney"` when Avvo shows the verified-client badge on the review header, or `null` when the badge is absent — useful for filtering testimonials down to confirmed paying clients.
- **ISO 8601 posted dates on every review** — dates parsed from Avvo's free-text format into machine-sortable timestamps so review trends, recency analysis, and time-series dashboards just work.
- **Lawyer profiles resolved from verified directory data** — lawyer name, city, and state are pulled from Avvo's own structured listing record, not guessed from page headlines, so the parent context columns stay accurate even when Avvo redesigns the profile page.
- **Scales to lawyers with 1 000+ reviews** — top-rated personal-injury and family-law attorneys can carry thousands of client reviews; the actor walks every page and stops cleanly the moment your `maxReviewsPerLawyer` or `maxReviewsTotal` cap is hit.
- **Two overlapping safety caps, shared fairly** — `maxReviewsPerLawyer` bounds each individual lawyer and `maxReviewsTotal` bounds the whole run, so a mistyped URL pointing at a 5 000-review profile can never blow past your budget. The run-wide cap is split evenly across every lawyer and query you supply, so a 300-review budget across 16 cities returns all 16 cities, not the first 11.

### Use Cases

**Reputation Management & Monitoring**

- Track new reviews on a roster of attorney clients and flag negative ones the moment they appear
- Benchmark a single lawyer's review trend against firm partners or regional peers
- Pull every 1- and 2-star review for a partner so the response strategy can be drafted in one sitting
- Audit how often a lawyer replies to negative reviews vs. positive ones

**Lead Generation & Sales Intelligence**

- Build target lists of high-rated attorneys by practice area and city for legal-tech outreach
- Identify lawyers in specific states whose reviews mention pain points your product solves
- Source customer-quote material for case studies — filter to 5-star reviews mentioning specific outcomes

**Market Research & Competitive Intelligence**

- Compare average client satisfaction across practice areas (personal injury vs. family law vs. criminal defense)
- Map regional differences in client review patterns — coastal metros vs. heartland markets
- Quantify how often clients mention price, communication, or outcome in their reviews

**Academic & Journalistic Research**

- Study client satisfaction patterns in legal services at scale
- Analyse how lawyers frame their replies to negative feedback
- Measure review volume and recency as proxies for an attorney's online visibility

**Aggregator Platforms & Legal Directories**

- Feed Avvo client reviews into a multi-source attorney comparison tool
- Power a lawyer-discovery app with verified third-party feedback
- Augment internal CRM records with public review counts and average star ratings per attorney

### Getting Started

#### Single Lawyer by URL

The simplest run — pull every review on one profile:

```json
{
    "lawyerUrls": [
        "https://www.avvo.com/attorneys/95827-ca-james-arrasmith-5150864.html"
    ],
    "maxReviewsPerLawyer": 50
}
```

#### Multiple Lawyers, Negative Reviews Only

Reputation triage across a roster of clients — the band from 1 to 2 stars keeps just the negative reviews and drops everything above them:

```json
{
    "lawyerUrls": [
        "https://www.avvo.com/attorneys/94104-ca-john-doe-12345.html",
        "https://www.avvo.com/attorneys/10001-ny-jane-roe-67890.html",
        "https://www.avvo.com/attorneys/60601-il-mark-smith-24680.html"
    ],
    "minRating": 1,
    "maxRating": 2,
    "maxReviewsPerLawyer": 100
}
```

#### Search by Practice Area + City

When you don't have profile URLs in hand — describe each lawyer in plain English:

```json
{
    "lawyerSearch": [
        "personal injury, Los Angeles, CA",
        "divorce lawyers, San Francisco, CA",
        "criminal defense, Houston, TX"
    ],
    "maxReviewsTotal": 100
}
```

#### Mixed Input — URLs and Searches Together

```json
{
    "lawyerUrls": [
        "https://www.avvo.com/attorneys/94104-ca-john-doe-12345.html"
    ],
    "lawyerSearch": [
        "estate planning, Boston, MA"
    ],
    "minRating": 4,
    "maxReviewsPerLawyer": 200,
    "maxReviewsTotal": 500
}
```

### Input Reference

#### What to Scrape

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `lawyerUrls` | string\[] | `[]` | Avvo lawyer profile URLs (e.g. `https://www.avvo.com/attorneys/94104-ca-john-doe-12345.html`). Paste one URL per lawyer. Each URL produces one set of review rows. |
| `lawyerSearch` | string\[] | `[]` | Free-text queries like `"divorce lawyers, San Francisco CA"` or `"John Smith attorney, Austin TX"`. Each query is resolved to its top matching Avvo lawyer profile, and that lawyer's reviews are collected. |

#### Filters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `minRating` | integer (1–5) | unset | Lowest star rating to keep. Leave empty for no lower limit. |
| `maxRating` | integer (1–5) | unset | Highest star rating to keep. Leave empty for no upper limit. Combine the two to pull a band — `minRating: 1` with `maxRating: 2` returns only 1- and 2-star reviews. |

#### Limits

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxReviewsPerLawyer` | integer | `100` pre-filled | Cap on reviews collected per lawyer. The field starts at `100`; change it to any number you like, or clear it (or set `0`) to collect every available review. |
| `maxReviewsTotal` | integer | unset | Optional safety cap on the total number of reviews across all lawyers. Shared evenly across your lawyers and queries, so every one of them is represented. |

### Output

One row per review. Lawyer-context fields are inlined on every row so a multi-lawyer dataset drops straight into a spreadsheet.

```json
{
    "lawyerName": "James Arrasmith",
    "lawyerProfileUrl": "https://www.avvo.com/attorneys/95827-ca-james-arrasmith-5150864.html",
    "lawyerSlug": "james-arrasmith",
    "lawyerCity": "Sacramento",
    "lawyerState": "CA",
    "reviewId": "12345678",
    "reviewerName": "Maria",
    "reviewerRelationship": "Hired Attorney",
    "stars": 5,
    "title": "Outstanding family law representation",
    "body": "James handled my custody case with compassion and skill. He kept me informed at every step, returned calls the same day, and the outcome exceeded my expectations.",
    "postedAt": "2024-09-12",
    "lawyerResponse": {
        "body": "Thank you Maria — it was a privilege working with you and your family.",
        "postedAt": "2024-09-15"
    },
    "inputUrl": null,
    "searchQuery": "family lawyer, Sacramento CA",
    "searchMatch": "city",
    "recordType": "review"
}
```

#### Lawyer Context

| Field | Type | Description |
|-------|------|-------------|
| `lawyerName` | string | Lawyer's display name as listed on Avvo |
| `lawyerProfileUrl` | string | Canonical Avvo profile URL |
| `lawyerSlug` | string | URL slug segment of the lawyer (e.g. `james-arrasmith`) |
| `lawyerCity` | string | Lawyer's primary office city |
| `lawyerState` | string | Two-letter US state code (e.g. `CA`) |
| `inputUrl` | string | null | The profile URL you supplied, copied through character for character. Avvo rewrites profile URLs to its own canonical form, so `lawyerProfileUrl` can differ from what you pasted. Join your input list to your results on this field. `null` for lawyers found by search. |
| `searchQuery` | string | null | The search query this lawyer was matched from, copied through verbatim. `null` for lawyers you supplied by profile URL. Join your input list to your results on this field. |
| `searchMatch` | string | null | How closely the matched lawyer's office fits the location you searched: `"city"` (same city and state), `"state"` (right state, different city), or `"out-of-area"` (Avvo listed nobody in that state for that search). `null` for lawyers you supplied by profile URL. |

#### Review Content

| Field | Type | Description |
|-------|------|-------------|
| `reviewId` | string | Avvo's stable identifier for the review |
| `stars` | integer (1–5) | Star rating chosen by the reviewer |
| `title` | string | Headline the reviewer gave the review |
| `body` | string | Full review text |
| `postedAt` | string | Date the review was posted, ISO 8601 (`YYYY-MM-DD`) |
| `recordType` | string | Always `"review"` — present for forward compatibility with future record types |

#### Reviewer & Lawyer Response

| Field | Type | Description |
|-------|------|-------------|
| `reviewerName` | string | Reviewer's display name. May be the literal `"anonymous"` when the reviewer chose anonymity |
| `reviewerRelationship` | string | null | `"Hired Attorney"` when Avvo shows the verified-client badge on the review header, otherwise `null`. Useful for filtering down to reviews from confirmed paying clients. |
| `lawyerResponse` | object | null | The lawyer's official reply when present, with `body` and `postedAt` (ISO 8601). `null` when the lawyer has not replied |

### Tips for Best Results

- **Start small** — run a single lawyer URL with `maxReviewsPerLawyer: 20` first to confirm the data shape matches your downstream pipeline, then scale up.
- **Bracket the band, don't just set a floor** — `minRating: 1` on its own keeps every review, because 1 star is already the bottom of the scale. Add `maxRating: 2` and you get the negative subset that actually drives outreach, response drafting, and crisis monitoring. Most tools only report averages; that band is where the real lift lives.
- **Use `maxReviewsTotal` to bound large runs** — Avvo profile sizes vary wildly: some lawyers have 5 reviews, top-rated personal-injury attorneys can have over 1 000. If you're running 50 lawyers and only have budget for 5 000 rows, set `maxReviewsTotal: 5000` as a hard ceiling. The budget is divided across all 50, so each one still shows up in your results; leave it unset when you want depth on a handful of lawyers rather than coverage across many.
- **Mine `lawyerResponse` for engagement signals** — a lawyer who replies to most negative reviews behaves very differently from one who never replies. The nested `lawyerResponse` field is rich material for benchmarking attorney engagement.
- **Prefer `lawyerUrls` when you know the specific attorney** — `lawyerSearch` resolves each query to the FIRST matching Avvo profile for that practice area + city + state. If you need a specific named lawyer, paste the URL.
- **Combine input types in one run** — mixing `lawyerUrls` and `lawyerSearch` in a single run is fully supported; both arrays are deduplicated and processed end-to-end.
- **Reviewer names of `"anonymous"` are real, not bugs** — Avvo lets reviewers post anonymously, and the actor preserves the literal value. Filter them out client-side if you need named-only reviews.

### Pricing

**From $1.50 per 1,000 reviews** — pay only for review rows you actually receive. No compute charges — you only pay per review returned. Your rate depends on your Apify discount tier, and the table below shows the total cost at each volume. These tier rates take effect on **12 September 2026**: Gold stays at $1.50 per 1,000, while the No-discount, Bronze and Silver rates change on that date. Until then every tier pays $1.50 per 1,000.

| Results | No discount | Bronze | Silver | Gold |
|---------|-------------|--------|--------|------|
| 100 | $0.17 | $0.17 | $0.16 | $0.15 |
| 1,000 | $1.75 | $1.70 | $1.60 | $1.50 |
| 10,000 | $17.50 | $17.00 | $16.00 | $15.00 |
| 100,000 | $175.00 | $170.00 | $160.00 | $150.00 |

A "result" is one review row in the output dataset. Apify platform fees (storage, transfer) are additional and depend on your plan.

### Integrations

Export data in JSON, CSV, Excel, XML, or RSS. Connect to 1,500+ apps via:

- **Zapier** / **Make** / **n8n** — Workflow automation, no-code pipelines
- **Google Sheets** — Direct spreadsheet export for analysts and ops teams
- **Slack** / **Email** — Notifications on new negative reviews or run completion
- **Webhooks** — Trigger your own systems on each scheduled run
- **Apify API** — Full programmatic access for embedding into your own product

### Legal & Ethical Use

This actor collects only data that is publicly visible to any visitor of an Avvo lawyer profile — client reviews, star ratings, posted dates, and lawyer replies that Avvo itself displays without authentication. Users are responsible for complying with Avvo's Terms of Service and applicable laws around personal data, attorney advertising, and fair use. Do not use extracted reviews for harassment, defamation, deceptive advertising, or any illegal purpose, and respect reviewer anonymity where it is preserved on the source page.

# Actor input Schema

## `lawyerUrls` (type: `array`):

Avvo lawyer profile URLs (e.g. https://www.avvo.com/attorneys/94104-ca-john-doe-12345.html). Paste one URL per lawyer. Each URL produces one set of review rows.

## `lawyerSearch` (type: `array`):

Free-text queries like 'divorce lawyers, San Francisco CA' or 'John Smith attorney, Austin TX'. Each query is resolved to its top matching Avvo lawyer profile, and that lawyer's reviews are scraped. Use this when you don't have profile URLs in hand.

## `minRating` (type: `integer`):

Lowest star rating to keep (1-5). Leave empty for no lower limit. Pair it with the maximum below to pull a band, e.g. 1 and 2 for negative reviews only.

## `maxRating` (type: `integer`):

Highest star rating to keep (1-5). Leave empty for no upper limit. Set it to 2 (with the minimum at 1) to collect only 1- and 2-star reviews, or to 3 to exclude the glowing ones.

## `maxReviewsPerLawyer` (type: `integer`):

Cap on the number of reviews captured per lawyer. Set to 0 (or leave empty) to collect every available review. The actor stops requesting new pages once the cap is reached but keeps the full last page if it slightly overshoots.

## `maxReviewsTotal` (type: `integer`):

Optional safety cap on the total number of reviews collected across all lawyers. The budget is shared evenly across every lawyer and search query you supply, so a tight cap still covers your whole list instead of stopping partway through it. Leave empty for no cap.

## Actor input object example

```json
{
  "lawyerUrls": [],
  "lawyerSearch": [],
  "minRating": null,
  "maxReviewsPerLawyer": 100
}
```

# Actor output Schema

## `overview` (type: `string`):

Compact table of reviews: lawyer, stars, title, posted date, and the search query each row came from.

## `detail` (type: `string`):

Full review rows including reviewer info, the lawyer's response (when available), and the exact input that produced each row.

# 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 = {
    "lawyerUrls": [],
    "lawyerSearch": [],
    "maxReviewsPerLawyer": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("solidcode/avvo-reviews-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 = {
    "lawyerUrls": [],
    "lawyerSearch": [],
    "maxReviewsPerLawyer": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("solidcode/avvo-reviews-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 '{
  "lawyerUrls": [],
  "lawyerSearch": [],
  "maxReviewsPerLawyer": 100
}' |
apify call solidcode/avvo-reviews-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,solidcode/avvo-reviews-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/FmopOPaGgvddAGjhy/builds/BkkGgbIKNyPFsg0K8/openapi.json
