# Google Maps Lawyers Scraper (`nice_dev/google-maps-lawyers-scraper`) Actor

Find law firms and lawyers on Google Maps by practice area and city: phone, website, rating, hours, e-mails and social links from the firm site, and state bar license check (NY, FL, CA). Goes past Google's 120-result cap in US cities.

- **URL**: https://apify.com/nice_dev/google-maps-lawyers-scraper.md
- **Developed by:** [Nice Dev](https://apify.com/nice_dev) (community)
- **Categories:** Lead generation, Business, MCP servers
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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

### 🔎 What is Google Maps Lawyers Scraper?

**Google Maps Lawyers Scraper** extracts **law firms and lawyers from [Google Maps](https://www.google.com/maps)**: **name, phone, website, address, rating, reviews, opening hours and coordinates**, for any practice area in any city. It works as a **Google Maps API alternative** for lawyers: run it on a schedule, call it from your code, or plug it into Make, Zapier or n8n.

Pick one or more **practice areas** (divorce, personal injury, DUI, immigration…) and type a **city**, a ZIP code or a country, then click **Start** and download the firms in JSON, CSV or Excel. No login, nothing to set up. In the big US cities it goes **past the 120 firms Google Maps shows for one search**.

### 📋 What data can you extract from Google Maps?

One item per law firm, 65 fields:

| Category | What you get |
| --- | --- |
| 🏷️ **Firm** | name, main category, every Google category, areas of law — `Thompson Law Austin Divorce Attorneys`, `Divorce`, `Family law` |
| 📍 **Address** | full address, street, city, state, ZIP code, country, neighborhood, latitude, longitude, plus code |
| 📞 **Contact** | phone (national and international format), website and its domain, appointment link |
| ⭐ **Reputation** | rating, number of reviews, a review quote, the Google Maps link of the firm |
| 🕒 **Hours and features** | opening hours, hours of online services, "Online appointments", accessibility, the account that manages the listing |
| 🔎 **The search** | which search found the firm and at which position |
| 📝 **Google Maps page** (option) | the description the firm wrote, the number of reviews per star, the latest reviews with their text, stars, date and the firm's answer |
| 🏛️ **State bar** (option) | for firms in New York, Florida and California: the attorneys confirmed as the firm's in the official register, with their bar number, license status (`active`, `inactive`…) and admission year |
| 📧 **Firm's website** (options) | e-mails found on its website, its Facebook, LinkedIn, Instagram, X, YouTube and TikTok links, the areas of law it lists, a free consultation, how it is paid (contingency, flat fee, payment plans…), the languages it speaks, the legal software its pages use (Clio, MyCase, LawPay, Calendly…) |

Every field, with an example, is listed in the **Output** section below. The columns of the options you switch on are `null` while an option is off.

### ✅ Why use Google Maps Lawyers Scraper?

- 🎯 **Made for lawyers**: practice areas are a list to tick, each one is searched as `<area> in <city>`; places that are not law firms (notaries, process servers, courts) are dropped by default.
- 🚀 **Past Google's cap**: Google Maps stops at about 120 firms per search. With **Go past Google's 120-results cap**, a US city is also searched ZIP code by ZIP code, around the centre of the firms found (613 firms instead of 87 for divorce lawyers in Austin, in our test of 11/10, with the 30 ZIP codes the Actor picks).
- 🧩 **Nothing missed, nothing twice**: every firm has its Google place ID, a firm found by several searches is saved — and charged — once.
- 🗂️ **Several searches in one run**: areas × cities, with a cap per search so that one big city cannot eat the whole budget.
- 🔔 **Monitoring built in**: tick **Only new firms**, schedule the Actor, and each run returns only the firms it never delivered before.
- 📧 **E-mails and a profile from the firm's own website**: Google Maps shows no e-mail. Tick the website options and each firm's website is visited once, whatever you tick, for its e-mails, its social profiles and what it says about itself (areas of law, free consultation, fees, languages, software). You pay only for the firms where something was found.
- 🏛️ **Checked at the state bar**: for the firms of New York, Florida and California, the Actor looks the firm up in the official register of its state and returns the attorneys confirmed as the firm's — bar number, license status, admission year. You pay only for the firms where an attorney was confirmed, and **With a matched bar license only** keeps no other firm.
- 🧹 **Free filters**: minimum rating, minimum number of reviews, phone or website required, searched city only, excluded names, firms you already have. A firm a filter drops is never charged.
- 🔌 API, scheduling, monitoring, integrations (Make, Zapier, n8n, Google Sheets…), proxy rotation and JSON/CSV/Excel export via the Apify platform.

### 🚀 How to scrape Google Maps for lawyers

1. Create a free Apify account.
2. Open **Google Maps Lawyers Scraper**, tick one or more **Practice areas** and type a **Location** (e.g. `Austin, TX`).
3. Or paste your own Google Maps URLs into **Google Maps search URLs**: searches, or the URL of an opened firm.
4. Set **Max law firms** (100 by default, 0 = no limit) — and **Max firms per search** when you run several searches — then click **Start**.
5. Download the dataset in JSON, CSV, Excel or via API.

### 💰 How much does it cost to scrape Google Maps?

This Actor uses **pay per event** pricing: **$3.49 per 1,000 law firms** ($1.19 on the Gold plan), plus **$0.01 per run start**. Each option is its own line, charged only for a firm where it found something:

| What you pay for | Free plan | Bronze | Silver | Gold |
| --- | --- | --- | --- | --- |
| Law firm saved (`result`) | $3.49 per 1,000 | $2.49 | $1.69 | $1.19 |
| Google Maps page of the firm: description, reviews per star (`place-details-scraped`, option) | $1.79 per 1,000 | $1.78 | $1.29 | $0.79 |
| Review delivered (`review-scraped`, option, 8 per firm at most) | $0.45 per 1,000 | $0.44 | $0.29 | $0.19 |
| E-mail found on the firm's website (`email-enriched`, option) | $1.69 per 1,000 | $1.29 | $1.19 | $0.79 |
| Social profiles found on the firm's website (`social-enriched`, option) | $1.79 per 1,000 | $1.78 | $1.29 | $0.89 |
| Website profile: areas of law, fees, languages, software (`website-insights`, option) | $1.49 per 1,000 | $1.48 | $1.47 | $1.46 |
| Attorney confirmed at the state bar, NY / FL / CA (`bar-verified`, option) | $2.99 per 1,000 | $2.98 | $2.97 | $2.96 |
| Run start (`apify-actor-start`, one at the default memory) | $0.01 | $0.01 | $0.01 | $0.01 |

Examples on the Gold plan:

- 1,000 divorce lawyers in Texas cities: $1.19 + $0.01 = **$1.20** ($3.50 without a subscription).
- 1,000 firms with **E-mails** ticked, 600 of them getting an e-mail: $1.19 + 600 × $0.00079 + $0.01 = **$1.67** ($4.51 without a subscription).

In detail: you pay for each firm saved (event `result`), plus a small fee when a run starts. The options that open the Google Maps page of each firm add their own events: `place-details-scraped` once for a firm whose description or star breakdown was found, and `review-scraped` for each review delivered. The options that read the firm's website add theirs: `email-enriched` once for a firm where at least one e-mail was found, `social-enriched` once for a firm where at least one social profile was found, and `website-insights` once for a firm whose website gave something of its profile. A firm whose website gave nothing, or could not be read, is charged for none of them. The state bar option adds `bar-verified` once for a firm where at least one attorney was confirmed in the register; a firm in another state, a firm with no attorney confirmed and a firm whose register could not answer are not charged. The price of each event is shown on the Actor page. Filters are free: a firm a filter drops is not charged, including with **With e-mail only**. Platform usage (compute, proxy) is included in the price.

### ⚙️ Input

```json
{
    "practiceAreas": ["divorce lawyer", "personal injury lawyer"],
    "location": "Austin, TX",
    "maxItems": 200
}
```

Several cities, a cap per search, only the firms you have never received, only well-rated ones:

```json
{
    "practiceAreas": ["dui lawyer"],
    "locations": ["Houston, TX", "Dallas, TX", "Miami, FL"],
    "maxItemsPerQuery": 100,
    "minRating": 4.5,
    "minReviewCount": 20,
    "onlyNew": true,
    "stateKey": "dui-texas-florida"
}
```

Or with your own Google Maps URLs, and the Google Maps page of each firm (description, stars, reviews):

```json
{
    "startUrls": [
        { "url": "https://www.google.com/maps/search/divorce+lawyer+in+Austin,+TX" },
        { "url": "https://www.google.com/maps/place/?q=place_id:ChIJFVwD3960RIYRDCDhc0-rbd4" }
    ],
    "includePlaceDetails": true,
    "includeReviews": true,
    "maxItems": 50
}
```

Or the e-mails and social profiles of the firms, keeping only the firms where an e-mail was found:

```json
{
    "practiceAreas": ["personal injury lawyer"],
    "location": "Houston, TX",
    "maxItems": 200,
    "enrichEmails": true,
    "enrichSocials": true,
    "requireEmail": true
}
```

Or the attorneys of the firms at their state bar, keeping only the firms where one was confirmed (New York, Florida and California):

```json
{
    "practiceAreas": ["personal injury lawyer"],
    "locations": ["Brooklyn, NY", "Miami, FL", "Los Angeles, CA"],
    "maxItems": 200,
    "verifyBarLicense": true,
    "requireBarMatch": true
}
```

| Field | Notes |
| --- | --- |
| `practiceAreas` | Areas of law to search, ticked in a list: `divorce lawyer`, `dui lawyer`, `immigration attorney`… Each one is searched as `<area> in <location>`. |
| `query`, `searchQueries` | Your own Google Maps search, as you would type it: `employment attorney`. Write `{location}` where the place goes, or leave it out and the place is added after `in`. Every area and term is searched in every location. |
| `location`, `locations` | City, state, ZIP code or country: `Austin, TX`, `90210`. `locations` adds more places (max 500 searches per run). |
| `startUrls` | Google Maps search URLs, or the URL of an opened firm: `https://www.google.com/maps/search/divorce+lawyer+in+Austin`, `https://www.google.com/maps/place/?q=place_id:ChIJFVwD3960RIYRDCDhc0-rbd4`. A search URL copied with the map position (`https://www.google.com/maps/search/divorce+lawyer/@30.2672,-97.7431,12z`) is searched around that point (the @lat,lng,zoom part). When set, the search fields are ignored. |
| `deepSearch` | Go past Google's cap: a US city is also searched ZIP code by ZIP code. On by default; it stops as soon as the cap of firms is reached. |
| `maxItems` | Stop after this many firms for the whole run (`0` = unlimited). |
| `maxItemsPerQuery` | Cap for EACH search (area × location, or search URL). 0 = no per-search cap. |
| `language` | The language of Google's categories and labels: `fr`, `es`, `de`… Names and addresses stay as listed. |
| `countryCode` | The country that helps Google with an ambiguous place name: `us`, `gb`, `ca`. |
| `includePlaceDetails`, `includeReviews` | Open the Google Maps page of each firm for its description and star breakdown, and for up to 8 of its latest reviews. Off by default: each is an option with its own price. |
| `enrichEmails` | Visit each firm's own website (its home page, and the contact, about or legal pages it links to: 3 pages at most) and add the e-mails published there to `emails` (`email` = the best one, `emailSource` = the page). Only for firms with a website of their own (a Facebook page is not one). Off by default; charged once per firm where an e-mail was found. |
| `enrichSocials` | Add the firm's Facebook, Instagram, LinkedIn, X, YouTube and TikTok links found on those same pages (`socialLinks`, and one column per network). No page more than `enrichEmails` reads; charged once per firm where a profile was found. |
| `websiteInsights` | From those same pages, add the areas of law the firm lists (`websitePracticeAreas`), whether it offers a free consultation, how it is paid (`feeTypes`: `contingency`, `flat_fee`, `hourly`, `payment_plans`, `no_win_no_fee`), the languages it speaks and the legal software its pages use. Charged once per firm where something was found. |
| `verifyBarLicense` | For the firms in New York, Florida and California, look the firm up in the official register of its state bar and add the attorneys confirmed as the firm's: `barStatus`, `barState`, `barMatchMethod`, `barAttorneys` (up to 25: name, bar number, license status, admission year, law school, link) and `barAttorneyCount`. An attorney is the firm's only when his phone number or office address is the firm's: a name alone is never enough. Firms in other states are marked unsupported in `barStatus`. Off by default; charged once per firm where at least one attorney was confirmed. |
| `minRating` | Drop the firms rated below this (`4.5`). Firms without a rating are dropped. 0 = no minimum. |
| `minReviewCount` | Drop the firms with fewer Google reviews (`20`). A firm Google rates without giving its number of reviews is kept (see the limits below). 0 = no minimum. |
| `requirePhone`, `requireWebsite` | Drop the firms without a phone number, or without a website. |
| `requireEmail` | Keep only the firms where an e-mail was found on their website. It switches `enrichEmails` on, so the e-mails of the firms you keep are charged like that option; a firm it drops is not charged at all. |
| `requireBarMatch` | Keep only the firms where an attorney was confirmed at the state bar. It switches `verifyBarLicense` on, so the attorneys of the firms you keep are charged like that option; firms outside New York, Florida and California, and firms whose register could not answer, are dropped, and a firm it drops is not charged at all. |
| `legalOnly`, `skipClosedPlaces`, `sameCityOnly` | On by default for the first two: keep law firms and attorneys only, and drop the firms Google marks closed. `sameCityOnly` drops the firms outside the searched city (or ZIP code); it filters nothing for a state, province or country. |
| `excludeKeywords`, `excludeMapsUrls` | Drop the firms whose name or category contains a word (`Morgan & Morgan`), or that you already collected: Google Maps URLs, place IDs or CIDs of an earlier export (up to 10 000). |
| `onlyNew`, `stateKey`, `resetState` | Monitoring: only the firms never delivered under this memory key (`miami-pi`); `resetState` forgets the memory. |
| Advanced | `proxyConfiguration` (Apify proxy by default, included in the price; the residential proxy is not available), `maxConcurrency`, `maxRequestsPerMinute`, `minRequestIntervalMs`, `maxRequestRetries`, `debugLog`. |

### 📦 Output

A firm (shortened: the columns of the options that are off are `null` and left out here):

```json
{
    "id": "ChIJFVwD3960RIYRDCDhc0-rbd4",
    "url": "https://www.google.com/maps/place/?q=place_id:ChIJFVwD3960RIYRDCDhc0-rbd4",
    "cid": "10539639380085273922",
    "featureId": "0x8644b4dedf035c15:0xde6dab4f73e1200c",
    "name": "Thompson Law Austin Divorce Attorneys",
    "category": "Divorce lawyer",
    "categories": ["Divorce lawyer", "Divorce service", "Family law attorney"],
    "practiceAreas": ["Divorce", "Family law"],
    "address": "3601 S Congress Ave Ste B200, Austin, TX 78704",
    "street": "3601 S Congress Ave Ste B200",
    "city": "Austin",
    "state": "TX",
    "postalCode": "78704",
    "countryCode": "US",
    "neighborhood": "Greater South River City",
    "latitude": 30.2272618,
    "longitude": -97.7593903,
    "plusCode": "66GR+W6",
    "timezone": "America/Chicago",
    "phone": "(737) 299-7508",
    "phoneInternational": "+17372997508",
    "website": "https://austintexaslaw.com/",
    "websiteDomain": "austintexaslaw.com",
    "rating": 4.9,
    "reviewCount": 84,
    "reviewsUrl": "https://search.google.com/local/reviews?placeid=ChIJFVwD3960RIYRDCDhc0-rbd4",
    "open24Hours": true,
    "attributes": ["Online appointments", "Onsite services"],
    "onlineAppointments": true,
    "bookingUrl": "https://austintexaslaw.com/contact",
    "claimed": null,
    "ownerName": "Thompson Law Austin Divorce Attorneys",
    "closed": null,
    "searchQuery": "divorce lawyer in Austin, TX",
    "searchLocation": "Austin, TX",
    "rank": 1,
    "scrapedAt": "2026-10-11T12:00:00.000Z"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV or Excel.

#### All 65 fields

| Fields | What you get |
| --- | --- |
| `id`, `url`, `featureId`, `cid`, `kgmid` | the Google place ID (the key of the firm), its Google Maps link, Google's other ids for the same place |
| `name`, `category`, `categories`, `practiceAreas` | `Thompson Law Austin Divorce Attorneys`, `Divorce lawyer`, every Google category, the areas of law read from them |
| `address`, `street`, `city`, `state`, `postalCode`, `countryCode`, `neighborhood` | the address as Google Maps shows it, and its parts |
| `latitude`, `longitude`, `plusCode`, `timezone` | `30.2272618`, `-97.7593903`, `66GR+W6`, `America/Chicago` |
| `phone`, `phoneInternational` | `(737) 299-7508`, `+17372997508` |
| `website`, `websiteDomain`, `bookingUrl` | the firm's website without tracking, its domain, the appointment or contact link Google gives |
| `rating`, `reviewCount`, `reviewsUrl`, `reviewSnippet` | `4.9`, `84`, the page with all the reviews, a quote from a review |
| `description`, `reviewDistribution`, `reviews` | **option** (Google Maps page): the firm's own description, the number of reviews per star, up to 8 reviews (`reviewId`, `reviewerName`, `reviewerUrl`, `reviewerReviewCount`, `isLocalGuide`, `rating`, `text`, `publishedAt`, `publishedAtText`, `likesCount`, `imageUrls`, `ownerResponse`, `ownerResponseAt`) |
| `openingHours`, `open24Hours`, `additionalOpeningHours` | one line per day, `true` when open 24 hours every day, a second set of hours (online service) |
| `attributes`, `onlineAppointments`, `claimed`, `ownerName`, `imageUrl`, `closed` | Google's features of the place, the account that manages it, the main photo, `permanently` for a place Google marks closed |
| `searchQuery`, `searchLocation`, `rank` | the search that found the firm, its place (or ZIP code), the position in that search |
| `emails`, `email`, `emailSource` | **option** (`enrichEmails`): the e-mails found on the firm's website, the best one first (an address on the firm's own domain before any other), the page where the first was found — `["info@austintexaslaw.com"]`, `info@austintexaslaw.com`, `https://austintexaslaw.com/contact` |
| `socialLinks`, `facebook`, `instagram`, `linkedin`, `twitter`, `youtube`, `tiktok` | **option** (`enrichSocials`): the profile links found on the website, and the first link of each network (`null` when the firm has none there) |
| `websitePracticeAreas`, `freeConsultation`, `feeTypes`, `languages`, `legalSoftware` | **option** (`websiteInsights`): the areas of law the website lists, `true` when it offers a free consultation, `contingency` / `flat_fee` / `hourly` / `payment_plans` / `no_win_no_fee` when it says so, the languages it says are spoken, the tools its pages use — `["Divorce", "Child custody"]`, `true`, `["flat_fee"]`, `["Spanish"]`, `["LawPay", "Calendly"]` |
| `barStatus`, `barState`, `barMatchMethod`, `barAttorneys`, `barAttorneyCount` | **option** (`verifyBarLicense`): `active` / `inactive` / `not_found` / `unsupported_state` / `unavailable`, the register looked up (`NY`, `FL`, `CA`), how the attorneys were found (`phone`, `firm_name`, `attorney_name`), the attorneys confirmed as the firm's and their number — `"active"`, `"NY"`, `"phone"`, `[{ "name": "Yehoshua Gelbstein", "barNumber": "4553004", "status": "Currently registered", "admittedYear": 2008, "lawSchool": "Brooklyn Law School", "profileUrl": "https://data.ny.gov/resource/eqw2-r5nb.json?registration_number=4553004" }]`, `1` |
| `scrapedAt` | ISO timestamp of the run |

### 💡 Tips

#### How to get more results

Leave **Go past Google's 120-results cap** on and set **Max law firms** to `0` for a big city: the city is searched ZIP code by ZIP code, nearest the centre first. For another country, list several towns in **More locations**.

#### How to reduce costs

The price is per firm, so the levers are `maxItems`, `maxItemsPerQuery`, the filters (they are free, a dropped firm costs nothing), `onlyNew` for recurring runs (you never pay twice for the same firm) and `excludeMapsUrls` for firms you already hold. Leave the Google Maps page options and the website options off when you only need what Google Maps gives; tick only the website options you use (each is charged on its own, and a firm's website is visited once however many you tick). The state bar check is worth ticking only for the firms of New York, Florida and California.

#### Several searches in one run

Tick several practice areas and fill **More locations**: the Actor runs one search per area × location (3 areas × 4 cities = 12 searches, up to 500 per run). A firm found by several searches is saved — and charged — once, with the first search that found it in `searchQuery`. Set `maxItemsPerQuery` to give every search its own cap: without it the first searches can use up the whole `maxItems` budget.

#### Monitoring: only the new firms

Tick **Only new firms** (`onlyNew`) and schedule the Actor. The first run returns everything; each later run skips the firms already delivered: they are not saved and not charged. The memory lives in a named key-value store of your account (`google-maps-lawyers-scraper-seen`, up to 150,000 firms per key) and is only updated with firms that really reached the dataset, so a failed run never hides anything. Give each schedule its own `stateKey` (two schedules sharing a key would hide each other's firms), and tick `resetState` once to start over.

#### Places that are not in the searched city

Google often widens a search to the towns around. Tick `sameCityOnly` to keep only the firms of the searched city or ZIP code; the column `searchLocation` tells which search found each firm. A place that is not a city (a state such as `TX` or `Texas`, a province, a country) names nothing to keep a firm in: nothing is dropped for it, and the log says so once. With `deepSearch`, a firm found through a ZIP code is judged against the place you typed, not against that ZIP code.

### 🔌 Integrations and API

Call the Actor via the Apify API, the JavaScript or Python clients, or connect it with integrations and webhooks (Make, Zapier, n8n, Google Sheets, Slack, Airtable…). The dataset can be fetched as JSON or CSV from any tool.

### 🤖 Use with AI agents (MCP)

AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the [Apify MCP server](https://mcp.apify.com), billed to their Apify account like any run. It returns one item per law firm of Google Maps. Actor id: `nice_dev/google-maps-lawyers-scraper`; MCP server with this Actor only: `https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/google-maps-lawyers-scraper`.

Smallest input, for a cheap first call:

```json
{
    "practiceAreas": ["divorce lawyer"],
    "location": "Austin, TX",
    "maxItems": 10
}
```

Key output fields: `name`, `phone`, `website`, `address`, `rating`, `reviewCount`, `practiceAreas` and `url`. The cost per firm and per run start is on the Actor page. Cap each call with `maxItems` and, through the API, with the run option `maxTotalChargeUsd`.

### ❓ FAQ

#### Is it legal to scrape Google Maps?

The Actor only reads what Google Maps shows publicly to any anonymous visitor. It logs in to nothing. Results can contain personal data (the name of a sole practitioner, a phone number), which is protected by GDPR: do not store it without a legitimate reason. You are responsible for using the data in compliance with Google's Terms of Service and applicable law. This Actor is not affiliated with Google.

#### Where do the e-mail addresses come from, and can I use them?

With the website options on, the Actor reads the pages each firm publishes on its own website (home page, contact page, legal notice) and returns the business contact addresses, social profiles and statements shown there — what any visitor sees. It does not log in, guess addresses, fill in contact forms or bypass any protection. An address of a web agency or of a font credited in the footer is not returned as the firm's. Some addresses are personal data (`firstname.lastname@firm.com`): you are responsible for having a lawful basis before using them, for informing the people concerned and for honouring opt-outs. The rules for marketing e-mail differ by country (in the US, the CAN-SPAM Act asks for a clear sender, a postal address and a way to opt out; the GDPR needs a lawful basis in the EU and the UK), and the rules for how a law firm may advertise or contact prospective clients differ by state bar and country: check them before you write to anyone.

#### Where does the bar license information come from?

With **Check the bar license** on, the Actor looks each firm of New York, Florida and California up in the register its state publishes: the New York State Unified Court System open data, The Florida Bar and The State Bar of California. These are public registers of licensed attorneys. An attorney is returned as the firm's only when his phone number or his office address is the firm's; a name alone is never enough, so an attorney of the same name elsewhere is not returned. A firm for which no attorney is confirmed has `barStatus: "not_found"` — it can still be a licensed firm registered under another address or phone number, so read it as "not confirmed", not as "not licensed". A license status is the register's own wording at the time of the run: check it again before you rely on it. The result is not legal advice and not a certification.

#### Does it need a login or a proxy?

No login. The proxy is included in the price: leave the default setting (the residential proxy is not available). With the state bar option, the Florida register is asked through Apify Proxy with addresses in the United States (it turns away every other address): if you switch Apify Proxy off, or use proxy URLs of your own, Florida firms are asked from the machine the run is on and come back `unavailable` unless that machine is in the United States. A request the site turns away is retried at once on a new proxy session, up to 10 times on top of the retries (without a proxy, after a pause of 5 seconds, doubled at each retry up to 150 seconds).

#### Why 65 fields and so many `null`?

Google Maps gives what each firm filled in: a firm without a website has `website: null`. The columns of the options (the Google Maps page of the firm, the firm's website, the state bar) are `null` while the option is off, and an empty list or object when it is on and found nothing — `null` again when it is on but the page could not be read whole (see the known limitations). `freeConsultation` is `true` when the website offers one, `false` when its pages say nothing of it, and `null` when the option is off or no page of the website could be read.

#### Is the data safe to open in Excel or to show on a web page?

Names, categories and reviews are the firms' and the reviewers' own words, copied as they are. A text can begin with `-`, `+`, `=` or `@`: Excel and Google Sheets may read such a cell of a CSV file as a formula or as a number. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. On a web page, escape every field like any text written by a stranger. Every URL field holds an http(s) URL or null.

#### Known limitations

- Google Maps shows about 120 firms for one search; `deepSearch` goes past it for US places typed as a city. A search pasted as a URL, a ZIP code typed as location and places outside the US are not split.
- A firm Google marks as temporarily closed is not told apart: only a place Google marks permanently closed has `closed: "permanently"`.
- `claimed` is `false` for a listing nobody claimed and `null` otherwise; the column does not say a listing is claimed.
- A place URL must carry the Google place ID (`?q=place_id:ChIJ...`) or be the address bar of an opened place; a name alone or a `?cid=` link is refused.
- Sponsored results are kept, with fewer fields: no `rank`, no `website` (Google gives the advertiser's domain only), the address written in full words (`South Capital of Texas Highway`).
- Google's search answer is thinner for some firms (about 1 firm in 7 on a search of Austin, other ones on the next read): beside a `rating` it gives no number of reviews, and only today's line of the opening hours. `reviewCount` is then `null` and `openingHours` empty. With the Google Maps page options (`includePlaceDetails`, `includeReviews`) the page of the firm completes them when it holds them. The page of a firm can be thin too: it is then read once more, and when it is thin again `reviewDistribution` and `reviews` are `null` (not known), never an empty object or list. For a few firms (4 of 20 on a search of Phoenix) the search answer names no main category: `category` is then the category you searched for, as Google lists it in the results; with the Google Maps page options it is the one the page of the firm shows.
- A firm read from its own page (a place pasted in `startUrls`) has no `reviewSnippet`, seldom an `imageUrl` and sometimes no `openingHours` (Google answers today's line alone on some reads, and a part of the week is not given): search results carry all three. The `reviews` option gives the firm's reviews either way.
- The website options give nothing for a firm with no website of its own (a Facebook page is not one), a website that cannot be reached, is built only in JavaScript, hides its addresses in images or answers a firewall's check instead of its pages: the columns are then empty and nothing is charged for that firm. Only the home page and the contact, about and legal pages it links to are read (3 pages at most), so an area of law, a fee or a language that appears elsewhere on the site is not seen. A link to the account of someone else in the text of the site (a testimonial, a partner) can be taken for the firm's profile.
- The state bar check covers New York, Florida and California, by the state of the firm's Google Maps address. New York lists the attorneys of the firm's phone number or address (200 rows read per search at most), Florida the attorneys of the first page of 50 that confirms one (up to 25 are returned, the count says how many were confirmed in what was read, a large firm may have more); for California the Actor reads the profiles of at most 10 candidates per firm. The Florida register does not list the admission year nor the law school (`null`). A firm that registered its attorneys under another phone number and another address than the one on Google Maps is `not_found`. In Florida a common last name can list hundreds of attorneys: the first 3 pages of 50 are read, and a firm not confirmed in them is `unavailable`, never `not_found`. The same in California: a search that lists more than 500 attorneys shows a sample of the register only, so a firm not confirmed by the other searches is `unavailable`. A register that is down or turns the Actor away, or no longer shows the status of the attorneys it lists, leaves its firms `unavailable` (and uncharged) — run it again later.
- `onlyNew` remembers firm ids, not their content: a firm whose rating changed is not returned again.
- Two runs sharing the same `stateKey` at the same time may both return the same new firm.

**A run that reaches its timeout** stops itself about 45 seconds before it: no new page is asked, what it read is saved and, with `onlyNew`, remembered, and the run ends *Succeeded* with "Stopped before the run's timeout". Resurrect it to go on from there, or give the next run a longer timeout (Run options).

**A run the platform stops without warning** (out of memory)

- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and the firms already saved are skipped: none is delivered or charged twice, and `maxItems` still counts them.
- With `onlyNew`, the memory is saved after each write, at most once every 2 seconds: resurrect the stopped run and the firms it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the firms saved in the last 2 seconds once more.

#### Something doesn't work?

The last line of the log counts the firms saved, filtered out and no longer on Google Maps, and the requests that failed after every retry. Those requests are listed, with the reason, in the `FAILED_REQUESTS` record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the cause.

If Google Maps changes its pages, you are told instead of paying for blank rows. If the first 20 firms read all lack their name, categories, coordinates, address or phone number — or the rating, the star breakdown or the reviews (with the options) of firms that have reviews — the run saves nothing more, stops and fails, and its last message names the missing field: at most those first firms are charged. A results page whose firms are there but can no longer be read (their name or identifier moved) is a failed request, never "no firm found". A run of fewer firms (a scheduled `onlyNew` run that finds a few new ones, a small **Max law firms**) is checked at its end, from 5 firms: its firms are already saved, and the run fails with the missing field instead of ending green.

### 🛟 Support

Open an issue in the **Issues** tab with a link to your run: the run log and the `FAILED_REQUESTS` record of the key-value store show exactly which URLs failed and why.

# Actor input Schema

## `practiceAreas` (type: `array`):

Pick one or more areas of law: each one is searched on Google Maps as `<area> in <location>` (e.g. `divorce lawyer in Austin, TX`). Combined with **Search terms** below; firms found by several searches are saved once.

## `query` (type: `string`):

Your own Google Maps search, as you would type it (e.g. `employment attorney`, `abogado de inmigración`). The location below is added as `in <location>`; write `{location}` to place it yourself (e.g. `lawyers near {location}`). Empty = only the practice areas above.

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

Several of your own searches in one run (same rules as **Search term**). Every term and every practice area is searched in every location (max 500 searches per run). 200 characters at most per term.

## `location` (type: `string`):

City, state, ZIP code or country, as typed on Google Maps (e.g. `Austin, TX`, `90210`, `Manchester, UK`).

## `locations` (type: `array`):

Several locations in one run: every practice area and search term is searched in every location (3 areas × 4 cities = 12 searches, max 500). Added to **Location**. 200 characters at most per location.

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

Google Maps search URLs (`https://www.google.com/maps/search/...`) or place URLs (`https://www.google.com/maps/place/...`). A search URL copied with the map position (`https://www.google.com/maps/search/divorce+lawyer/@30.2672,-97.7431,12z`) is searched around that point (the @lat,lng,zoom part). When this list is not empty, the search fields above are ignored; filters, caps, enrichments and monitoring still apply. Max 1 000 URLs.

## `deepSearch` (type: `boolean`):

Google Maps shows at most about 120 places per search. On: a US city is also searched ZIP code by ZIP code (codes around the city center) to find the firms the city-wide search leaves out — several times more firms in a big city. Only US locations; a ZIP code typed as location is searched alone. Stops as soon as **Max law firms** is reached.

## `maxItems` (type: `integer`):

Maximum number of firms to save for the whole run (after deduplication and filters). 0 = no limit.

## `maxItemsPerQuery` (type: `integer`):

Cap for EACH search (practice area or term × location, or search URL), so that the first search cannot use up the whole **Max law firms** budget. 0 = no per-search cap.

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

Language of categories, opening hours and feature labels (names and addresses stay as listed).

## `countryCode` (type: `string`):

Two-letter country code that Google Maps uses to rank and localize results (e.g. `us`, `gb`, `ca`, `au`). The location decides where Google searches; this only helps it when the place name is ambiguous.

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

Google Maps shows no e-mail. On: open the firm's own website (home page + contact / about / legal pages linked from it, 3 pages at most) and add the addresses found there to `emails`. Only for firms with a website of their own. Charged as a separate event, only for the firms where at least one e-mail is found.

## `enrichSocials` (type: `boolean`):

On: add the firm's Facebook, Instagram, LinkedIn, X / Twitter, YouTube and TikTok links found on its website (same pages as the e-mail search, no extra page). Charged as a separate event, only for the firms where at least one profile is found.

## `websiteInsights` (type: `boolean`):

On: from the same website pages, add the practice areas the firm lists, fee signals (free consultation, contingency / no win no fee, flat fee, payment plans), languages spoken, online booking link, and the legal software seen on the site (Clio, MyCase, LawPay, PracticePanther, Smokeball, Filevine, Lawmatics, Calendly…). Charged as a separate event, only for the firms where something is found.

## `verifyBarLicense` (type: `boolean`):

On: for firms in New York, Florida and California, look the firm up in the official register of its state bar (New York State Unified Court System open data, The Florida Bar, The State Bar of California) and add the attorneys confirmed as the firm's, with their bar number, license status and admission year (`barStatus`, `barAttorneys`). An attorney counts only when his phone number or office address is the firm's. Charged once per firm where at least one attorney is confirmed; firms in other states (`unsupported_state`), firms with no attorney confirmed (`not_found`) and firms whose register could not answer (`unavailable`) are not charged.

## `includePlaceDetails` (type: `boolean`):

On: open the firm's own Google Maps page (one more request per firm) and add the description written by the firm (`description`) and the number of reviews per star (`reviewDistribution`).

## `includeReviews` (type: `boolean`):

On: from the same Google Maps page, add up to 8 reviews per firm (Google's most relevant first): text, stars, date, reviewer, and the firm's reply (`reviews`). Google shows more reviews only to signed-in users.

## `minRating` (type: `number`):

Drop the firms rated below this (1 to 5). 0 = no minimum. Firms without any rating are dropped when this is set.

## `minReviewCount` (type: `integer`):

Drop the firms with fewer Google reviews than this. A firm that Google rates without giving its number of reviews is kept. 0 = no minimum.

## `requirePhone` (type: `boolean`):

Drop the firms without a phone number.

## `requireWebsite` (type: `boolean`):

Drop the firms without a website.

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

Drop the firms where no e-mail was found on their website (turns **Find e-mails** on: the e-mails of the firms you keep are charged like that option; a firm this drops is not charged).

## `requireBarMatch` (type: `boolean`):

Drop the firms where no attorney was confirmed in the state bar register (turns **Check the bar license** on: the attorneys of the firms you keep are charged like that option; a firm this drops is not charged). Firms outside NY, FL and CA, and firms whose register could not answer, are all dropped.

## `legalOnly` (type: `boolean`):

Google Maps also returns nearby non-legal places (notaries, process servers, mediators, courts…). On: keep only the places whose Google category is a lawyer, attorney or law firm.

## `skipClosedPlaces` (type: `boolean`):

Drop the places Google marks as permanently closed. A temporary closure is not told apart: those places stay.

## `sameCityOnly` (type: `boolean`):

Google often widens a search to nearby towns. On: drop the firms whose address is not in the searched city (or ZIP code). A place that is no city (a state, a province, a country) filters nothing. Off: keep them, the `searchLocation` field tells which search found each firm.

## `excludeKeywords` (type: `array`):

Drop the firms whose name or category contains one of these words (case and accents ignored), e.g. `Morgan & Morgan` to leave out a national chain. 100 characters at most per word.

## `excludeMapsUrls` (type: `array`):

Google Maps URLs, place IDs (`ChIJ…`) or CIDs from an earlier export: these firms are skipped, not saved and not charged. Up to 10 000.

## `onlyNew` (type: `boolean`):

Skip the firms that a previous run (same **Memory key**) already delivered: they are not saved and not charged. First run = everything is new.

## `stateKey` (type: `string`):

Name of the memory used by **Only new firms**. Give each schedule / task its own key (e.g. `miami-pi`) so that they do not share their memory. Letters, digits, `-` and `_`.

## `resetState` (type: `boolean`):

Forget everything remembered under this **Memory key** before the run: this run returns (and charges) every firm again. Untick it afterwards.

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

Apify Proxy or your own proxies. Keep the default: it is included in the price. The Florida bar answers only to US addresses: with your own proxies, use US ones. The residential Apify proxy is not available in this Actor.

## `maxConcurrency` (type: `integer`):

Maximum number of requests processed in parallel.

## `maxRequestsPerMinute` (type: `integer`):

Most requests to Google Maps in any 60 seconds (results pages and place pages). A budget, not an even pace. Lower it if the log shows HTTP 429 / 403. The firm websites (a few at a time) and the bar registers keep their own pace.

## `minRequestIntervalMs` (type: `integer`):

Smallest gap between two requests to Google Maps, in milliseconds. Spreads them evenly instead of letting them go out in a burst. 0 = no gap.

## `maxRequestRetries` (type: `integer`):

Retries per request before it is marked as failed. Behind a proxy, a request turned away is also retried on a new proxy session up to 10 times without using up these retries.

## `debugLog` (type: `boolean`):

Include debug messages in the run log.

## Actor input object example

```json
{
  "practiceAreas": [
    "divorce lawyer"
  ],
  "searchQueries": [],
  "location": "Austin, TX",
  "locations": [],
  "startUrls": [],
  "deepSearch": true,
  "maxItems": 20,
  "maxItemsPerQuery": 0,
  "language": "en",
  "countryCode": "us",
  "enrichEmails": false,
  "enrichSocials": false,
  "websiteInsights": false,
  "verifyBarLicense": false,
  "includePlaceDetails": false,
  "includeReviews": false,
  "minRating": 0,
  "minReviewCount": 0,
  "requirePhone": false,
  "requireWebsite": false,
  "requireEmail": false,
  "requireBarMatch": false,
  "legalOnly": true,
  "skipClosedPlaces": true,
  "sameCityOnly": false,
  "excludeKeywords": [],
  "excludeMapsUrls": [],
  "onlyNew": false,
  "stateKey": "default",
  "resetState": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 8,
  "maxRequestsPerMinute": 120,
  "minRequestIntervalMs": 0,
  "maxRequestRetries": 5,
  "debugLog": false
}
```

# Actor output Schema

## `results` (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 = {
    "practiceAreas": [
        "divorce lawyer"
    ],
    "location": "Austin, TX",
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("nice_dev/google-maps-lawyers-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 = {
    "practiceAreas": ["divorce lawyer"],
    "location": "Austin, TX",
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("nice_dev/google-maps-lawyers-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 '{
  "practiceAreas": [
    "divorce lawyer"
  ],
  "location": "Austin, TX",
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call nice_dev/google-maps-lawyers-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/google-maps-lawyers-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/SXhYTyooviUwfCh8D/builds/egMCdo182GXfKeSOj/openapi.json
