# Google Maps Lead Cleaner: Dedupe, Remove Fake & Closed Listings (`callbacklocal/google-maps-lead-cleaner`) Actor

Clean Google Maps data: dedupe leads, remove fake lead-farm listings, closed businesses and off-category results, merge duplicates, format phones from any country, optionally return only new leads. $0.0025 per cleaned kept lead; dropped rows free. Plus platform usage.

- **URL**: https://apify.com/callbacklocal/google-maps-lead-cleaner.md
- **Developed by:** [Callback Local](https://apify.com/callbacklocal) (community)
- **Categories:** Lead generation, Business, Automation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 cleaned lead rows

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

### What does Google Maps Lead Cleaner do?

**Google Maps Lead Cleaner** removes fake listings (lead farms), duplicates and closed businesses from your Google Maps leads. Give it [Google Maps Scraper](https://apify.com/compass/crawler-google-places) results and get back only real, open businesses in your category.

It also drops off-category results, standardizes phone numbers from any country to E.164 and adds sales flags. Pricing is **$0.0025 USD per cleaned kept lead** (pay per event). Dropped rows and already-seen (history) leads are not charged. You also pay normal Apify platform usage for the run.

Use it to **clean Google Maps data**, **dedupe Google Maps leads** and **remove fake listings** before they reach your CRM or cold-calling list. It does not scrape Google itself. It cleans data you already have, so it works as a filter step after any Google Maps scraping run, from the Apify Console, the API, a schedule or an AI agent.

> Tested on real data from two trades in two areas of the Atlanta metro. See the limits section before relying on it at scale.

> **Try it in one click:** the input form comes prefilled with 8 made-up demo listings. Press Start and see 8 rows become 3 leads: a duplicate merged, a closed shop and 3 fake look-alike listings dropped. Add `Plumber` to **Target categories** and the off-category auto shop goes too, leaving 2.

> ⭐ **Found this useful? A quick review on the Apify Store helps a lot.** [Leave a review](https://apify.com/callbacklocal/google-maps-lead-cleaner/reviews)

### Why use Google Maps Lead Cleaner?

When you search Google Maps for a trade in a small area, Google does not stop at real matches. It pads the list with whatever is nearby: auto shops, suppliers, construction companies, even software companies. A scraper copies that padding faithfully.

We tested this on real data:

- **Sandy Springs, GA plumbers:** three searches returned **94 businesses. Only 26 were plumbers. 68 (72%) were off-category junk.**
- **Marietta, GA HVAC:** two searches returned **100 businesses**. 53 were off-category, and **9 were mass-made fake listings** such as "Halcy HVAC Repair Marietta", "Gravix HVAC Repair Marietta" and "Metric HVAC Repair Marietta": the same name pattern, near-sequential phone numbers, no website, almost no reviews.

What you get:

- 🎯 **Category filter:** say `["Plumber"]` and only plumbers stay.
- 🚪 **Closed filter:** permanently or temporarily closed businesses are removed by default.
- 🕵️ **Fake-listing (lead farm) filter:** batches of look-alike, no-website, no-review listings are removed or flagged.
- 🆕 **Only new leads since your last run:** skip businesses you already received. Weekly repeat pulls return only what is new.
- 🧹 **Cleanup:** merges duplicate listings, formats phones from any country (`+14045551234` and `(404) 555-1234`, or `+442079460018` and `+44 20 7946 0018`) and flags `no_website`, `unclaimed_profile`, `low_reviews`, `out_of_area_phone`.
- ⚙️ **Apify platform:** schedules, API, webhooks, integrations and monitoring come built in.

Real results: **94 rows → 25 open plumbers** (Sandy Springs) and **100 rows → 36 real HVAC leads**, with all 9 fake listings caught and no real company caught (Marietta). With history on, a repeat Sandy Springs pull delivered **10 new leads and skipped 15 already seen**.

### What data does Google Maps Lead Cleaner output?

One row per real business:

| Field | Type | Description |
|---|---|---|
| `title` | string | Business name |
| `phoneE164` | string | Phone in E.164, for example `+17704218400` |
| `phoneDisplay` | string | Phone formatted for people, for example `(770) 421-8400` |
| `website` | string | Real website (Facebook, Instagram and Yelp pages do not count) |
| `address`, `city` | string | Address from Google Maps |
| `categoryName` | string | Google's main category |
| `reviewsCount`, `totalScore` | number | Review count (highest across merged listings) and rating |
| `flags` | array | Sales flags, see below |
| `placeIds` | array | Google place IDs merged into this lead |
| `duplicateCount` | number | How many extra listings were merged in |
| `isNew` | boolean | Present when "Only new leads" is on |

Also: `phoneExt`, `phoneCountry` (two-letter country of the phone), `otherPhones`, `url`, `sourceRowIndexes`, and `leadFarmReason` (flag mode only).

**Flags**

| Flag | Meaning |
|---|---|
| `no_website` | No real website |
| `unclaimed_profile` | The owner has not claimed the Google profile |
| `low_reviews` | Fewer reviews than your threshold (default 10) |
| `invalid_phone` | No usable phone number |
| `out_of_area_phone` | US only: area code belongs to another state than the listing (often a national call center; check it, it is not proof of anything). Toll-free and non-US numbers are never flagged |
| `off_category` | Only in flag mode: not in your target categories |
| `lead_farm_suspect` | Only in flag mode: part of a batch of look-alike fake listings |
| `permanently_closed` / `temporarily_closed` | Only when Drop closed is off |

### How to clean Google Maps data

1. Run the [Google Maps Scraper](https://apify.com/compass/crawler-google-places) as usual.
2. Start Google Maps Lead Cleaner and paste the scraper items into **Listings**, or give it the scraper run's **Dataset ID**.
3. Set **Target categories**, for example `Plumber` or `HVAC contractor`, `Air conditioning contractor`. Matching is case-insensitive and partial, against Google's `categoryName` and `categories`.
4. Optional: turn on **Only new leads since my last run** and give the list a **History key**, for example `atlanta-plumbers`.
5. Run it. The run status tells you what was kept and dropped, for example: `Cleaned 100 listings into 36 leads. Dropped: 1 closed, 53 off-category, 9 suspected fake listings.`
6. Download the clean leads as JSON, CSV, Excel or HTML, or read them with the API.

### Clean Google Maps data automatically after every scrape

Skip the copy and paste. Chain the cleaner to your scraper once and every scrape comes back clean.

1. Open your Google Maps Scraper Actor or saved task in Apify Console and go to the **Integrations** tab.
2. Add an Actor integration, pick **Google Maps Lead Cleaner** and choose the event **Run succeeded**.
3. In the cleaner's input, set **Dataset ID** to `{{resource.defaultDatasetId}}` (Apify swaps in the scraper run's dataset each time), then set your **Target categories** and other options. Leave **Listings** empty.
4. Save. From now on, each successful scraper run starts the cleaner on that run's results.

Tip: pair it with **Only new leads since my last run** and a **History key** on a scheduled scraper task, and each run delivers only businesses you have not seen before.

Integration input example:

```json
{
  "datasetId": "{{resource.defaultDatasetId}}",
  "targetCategories": ["Plumber"],
  "onlyNewSinceLastRun": true,
  "historyKey": "atlanta-plumbers"
}
```

### How much does it cost to clean Google Maps data?

**$0.0025 USD per cleaned kept lead** (pay per event). You are charged once for each lead delivered to the output dataset.

- Dropped rows (closed, off-category, suspected fake, no phone) are **not** charged.
- Already-seen leads skipped by history ("Only new leads since my last run") are **not** charged.
- You also pay normal Apify platform usage for the run (compute and storage). That is usually tiny because the Actor only processes data you already have.
- There is also a tiny Actor Start event ($0.00005) when the run begins.
- The Google Maps Scraper bills separately for its own run.

### Input

See the **Input** tab for every option. The main ones:

| Input | Default | What it does |
|---|---|---|
| Listings (`items`) | 8 demo listings (prefill) | Paste Google Maps Scraper items. Use this or Dataset ID. A Dataset ID wins if both are set |
| Dataset ID (`datasetId`) | none | Dataset from a Google Maps Scraper run |
| Target categories (`targetCategories`) | empty (keep all) | Categories to keep, for example `["Plumber"]` |
| Off-category leads (`categoryMode`) | drop | `drop` removes them, `flag` keeps them with `off_category` |
| Drop closed businesses (`dropClosed`) | on | Removes permanently or temporarily closed listings |
| Drop leads with no phone (`dropNoPhone`) | off | Removes leads without a valid phone |
| Default phone country (`defaultCountry`) | US | Country for numbers written without `+`, for example `GB`. Each listing's own `countryCode` wins |
| Suspected fake listings (`leadFarmMode`) | drop | `drop` removes them, `flag` keeps them with `lead_farm_suspect`, `off` skips the check |
| Only new leads since my last run (`onlyNewSinceLastRun`) | off | Skips businesses already delivered under the same History key |
| History key (`historyKey`) | default | One history per list, for example `atlanta-plumbers` |
| Low reviews threshold (`lowReviewsThreshold`) | 10 | Fewer reviews than this gets `low_reviews` |
| Merge near-duplicate listings (`mergeNearDuplicates`) | on | The same business listed twice becomes one lead |

Example:

```json
{
  "datasetId": "YOUR_GOOGLE_MAPS_SCRAPER_DATASET_ID",
  "targetCategories": ["Plumber"],
  "leadFarmMode": "drop",
  "onlyNewSinceLastRun": true,
  "historyKey": "sandy-springs-plumbers"
}
```

### Output

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

```json
[
  {
    "title": "Coolray Heating & Air Conditioning",
    "phoneE164": "+17704218400",
    "phoneDisplay": "(770) 421-8400",
    "website": "https://www.coolray.com/",
    "categoryName": "Air conditioning contractor",
    "reviewsCount": 11254,
    "flags": [],
    "duplicateCount": 0,
    "isNew": true
  },
  {
    "title": "Eardley's Inc",
    "phoneE164": "+17706350111",
    "phoneDisplay": "(770) 635-0111",
    "website": null,
    "categoryName": "HVAC contractor",
    "reviewsCount": 1,
    "flags": ["no_website", "unclaimed_profile", "low_reviews"],
    "duplicateCount": 0,
    "isNew": true
  }
]
```

### How the fake-listing (lead farm) check works

A lead is **weak** when it has no real website and fewer reviews than your low reviews threshold. Two weak leads are linked when they have **near-sequential phones** (same area code and exchange, last 4 digits within 20 of each other; outside North America, same number except the last 4 digits; toll-free ignored) or **the same name template** (identical name after the first word, with the city in it or the same phone exchange, for example `* HVAC Repair Marietta`). A connected group of **3 or more** weak leads is a suspected lead farm. Leads with a real website or many reviews are never linked, so real multi-location brands and franchises are not caught. Use `flag` mode to review suspects instead of dropping them.

### New leads since your last run

History lives in a **named key-value store in your own Apify account**, `maps-lead-cleaner-history`, one record per History key (record name `history-<key>`). It holds only match keys: each Google place ID plus a backup key of normalized phone and name, for listings whose place ID changed. Only leads actually delivered are added, so if a run is cut short, the rest still count as new next time. To start over, use a new History key or delete that record. Named stores are kept until you delete them and use a little of your Apify storage.

### Limits (honest version)

- **It trusts Google's categories.** If Google labels a plumber as "Contractor", a `Plumber` filter drops it, and if Google labels a car AC shop as "Air conditioning repair service", an HVAC filter keeps it. Add more target categories if your trade uses several labels.
- **The fake-listing check needs a batch.** It catches groups of 3 or more look-alikes. A lone fake, or fakes with real-looking websites and reviews, can get through. A real tiny business that sits inside such a batch would be caught too.
- **The out-of-area phone check is US only.** It uses a static US area-code map, so a business that kept an out-of-state number after moving gets flagged too. Phones from other countries are cleaned and formatted, but not checked for area.
- **Tested on two trades in two areas so far:** Sandy Springs, GA plumbers (20 and 94 listings) and Marietta, GA HVAC (100 listings), plus synthetic test sets. Results elsewhere may differ.
- **Duplicates are rare inside one scraper run,** because the Google Maps Scraper already removes repeats. Merging matters most when you combine several runs or datasets.
- **History is per Apify account and per History key.**
- **Not a scraper.** You need Google Maps Scraper output first.

### FAQ

#### How much does it cost?

**$0.0025 USD per cleaned kept lead** (pay per event). Dropped rows and already-seen (history) leads are not charged. You also pay normal Apify platform usage for the run, plus a tiny Actor Start event ($0.00005).

#### How do I remove duplicates from Google Maps results?

Paste your scraper results into **Listings**, or set **Dataset ID** to the scraper run's dataset. Keep **Merge near-duplicate listings** on (the default). The Actor merges the same business listed twice into one lead and keeps the best phone, website and review count. Chain it after your scraper so every scrape comes back deduped.

#### How do I find / remove fake Google Maps listings?

Set **Suspected fake listings** to `drop` (default) to remove them, or `flag` to keep them tagged as `lead_farm_suspect` so you can review. The check looks for batches of look-alike, no-website, low-review listings with near-sequential phones or the same name template. Real businesses with a website or many reviews are not linked into those groups.

#### How do I clean Google Maps data after a scrape?

Run your Google Maps scraper as usual, then start this Actor with that run's **Dataset ID**, or chain it under **Integrations** so every successful scrape starts the cleaner automatically (see "Clean Google Maps data automatically after every scrape" above). Set your **Target categories** and download the clean leads as JSON, CSV, Excel or HTML.

#### Which scrapers does it work with?

Any Google Maps scraper whose output has the usual place fields. It was built on [compass/crawler-google-places](https://apify.com/compass/crawler-google-places) output and also reads the output of [compass/google-maps-extractor](https://apify.com/compass/google-maps-extractor), [vortex_data/google-maps](https://apify.com/vortex_data/google-maps), [scraperlink/google-maps-scraper](https://apify.com/scraperlink/google-maps-scraper) and [scrapesage/google-maps-scraper](https://apify.com/scrapesage/google-maps-scraper). Pass the scraper run's Dataset ID, or chain it as shown above.

Data from other tools or a CSV export works too. Common alternative field names are read automatically, for example `name` for `title`, `phoneNumber` or `phones` for `phone`, `place_id` for `placeId`, `category` for `categoryName`, `rating` and `ratingCount` for the score and review count, `formattedAddress` for `address`, and `businessStatus: CLOSED_PERMANENTLY` for closed businesses.

#### I want to see what was removed instead of dropping it.

Set Off-category leads to `flag`, Suspected fake listings to `flag`, and turn off Drop closed businesses. Everything is kept and tagged.

#### Can I use it from an AI agent or the Apify API?

Yes. See the **API** tab. Anything that can start an Apify run with JSON input can use it.

#### Does it contact the businesses?

No. It only cleans and returns data.

#### Privacy and data

Each run saves a small `RUN_SIGNALS` record to your own run's key-value store (run id, input and output size, duration and a hash of the input, no lead data) for abuse checks. It is not sent anywhere else.

This Actor does not scrape anything. It only reads the listings you give it and returns a cleaned copy to your own Apify storage. Your input may already contain personal data, for example a sole trader's name or mobile number. You are responsible for having a lawful reason to keep and use it under GDPR, CCPA and similar laws.

#### Feedback

Found a wrong drop or a fake that got through? Open an issue in the **Issues** tab with the listing name and city.

### Changelog

#### Nov 4, 2026 (build 0.3.9)

- Pricing is live at **$0.0025 USD per cleaned kept lead** (pay per event). README, listing and cost FAQ updated to match. Dropped and already-seen rows stay free.
- FAQ expanded in buyers' words: remove duplicates, find/remove fake listings, clean Google Maps data after a scrape.
- Field aliases for other scrapers' column names shipped in 0.3.8 (Nov 2): `name`, `phoneNumber`, `place_id`, `category`, `rating`, `formattedAddress`, `businessStatus` and more.

# Actor input Schema

## `items` (type: `array`):

Google Maps scraper results (for example items from compass/crawler-google-places). Use this OR datasetId. Prefilled with 8 made-up demo listings (a duplicate, a closed shop, an auto shop and 3 look-alike fake listings) so one click on Start shows what gets cleaned. Replace them with your own data. If a dataset ID is set, the dataset is used and this list is ignored.

## `datasetId` (type: `string`):

A dataset from a Google Maps Scraper run (pick it from your storages or paste its ID). Read-only: the Actor only reads it. When set, it is used instead of Listings. Running it after a scraper via Integrations? Put {{resource.defaultDatasetId}} here and each scraper run's results are cleaned automatically.

## `lowReviewsThreshold` (type: `integer`):

A business with fewer reviews than this gets the low_reviews flag.

## `mergeNearDuplicates` (type: `boolean`):

Merge different listings that look like the same business (similar name plus same phone or address).

## `targetCategories` (type: `array`):

Only keep leads whose Google category matches one of these (case-insensitive, partial match OK), for example \["Plumber"]. Checks categoryName and categories. Empty = keep every category.

## `categoryMode` (type: `string`):

drop (default): remove off-category leads. flag: keep them and add the off_category flag. Only used when Target categories is set.

## `dropClosed` (type: `boolean`):

Remove businesses Google marks as permanently or temporarily closed. Off: keep them with a permanently_closed or temporarily_closed flag.

## `dropNoPhone` (type: `boolean`):

Remove leads with no valid phone number.

## `defaultCountry` (type: `string`):

Two-letter country code (for example US, CA, GB, AU) used to read phone numbers written without a + country code. A listing's own countryCode from Google Maps Scraper wins when present. Numbers with a + prefix keep their own country.

## `leadFarmMode` (type: `string`):

Catches batches of mass-made listings, for example 'Halcy HVAC Repair Marietta', 'Gravix HVAC Repair Marietta', 'Metric HVAC Repair Marietta': 3 or more leads with no website and few reviews that share a name template or near-sequential phone numbers. drop (default): remove them. flag: keep them with the lead_farm_suspect flag and a leadFarmReason. off: skip the check.

## `onlyNewSinceLastRun` (type: `boolean`):

Skip businesses this Actor already delivered to you under the same History key. New leads get isNew: true. History is saved in your own named key-value store 'maps-lead-cleaner-history'.

## `historyKey` (type: `string`):

Name for this list's history, for example 'atlanta-plumbers'. Use a different key per list you track. Letters, numbers and -\_.!'() are kept, other characters become \_.

## Actor input object example

```json
{
  "items": [
    {
      "title": "Demo Peachtree Plumbing",
      "categoryName": "Plumber",
      "phone": "(404) 555-0142",
      "website": "https://example.com/peachtree-plumbing",
      "address": "100 Demo St, Sandy Springs, GA 30328",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 212,
      "totalScore": 4.8,
      "placeId": "demo-place-01",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-01"
    },
    {
      "title": "Demo Peachtree Plumbing LLC",
      "categoryName": "Plumber",
      "phone": "+1 404-555-0142",
      "website": "https://example.com/peachtree-plumbing",
      "address": "100 Demo Street, Sandy Springs, GA 30328",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 9,
      "totalScore": 4.6,
      "placeId": "demo-place-02",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-02"
    },
    {
      "title": "Demo Riverside Drain & Sewer",
      "categoryName": "Plumber",
      "phone": "(770) 555-0188",
      "website": "https://example.com/riverside-drain",
      "address": "200 Sample Ave, Sandy Springs, GA 30350",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 87,
      "totalScore": 4.7,
      "placeId": "demo-place-03",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-03"
    },
    {
      "title": "Demo Old Town Plumbers",
      "categoryName": "Plumber",
      "phone": "(404) 555-0170",
      "address": "300 Example Rd, Sandy Springs, GA 30328",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 41,
      "totalScore": 4.1,
      "permanentlyClosed": true,
      "placeId": "demo-place-04",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-04"
    },
    {
      "title": "Demo Quick Lube Auto Repair",
      "categoryName": "Auto repair shop",
      "phone": "(404) 555-0123",
      "website": "https://example.com/quick-lube",
      "address": "400 Test Blvd, Sandy Springs, GA 30328",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 150,
      "totalScore": 4.4,
      "placeId": "demo-place-05",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-05"
    },
    {
      "title": "Halcy Plumbing Repair Sandy Springs",
      "categoryName": "Plumber",
      "phone": "(470) 555-0101",
      "address": "Sandy Springs, GA",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 1,
      "totalScore": 5,
      "placeId": "demo-place-06",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-06"
    },
    {
      "title": "Gravix Plumbing Repair Sandy Springs",
      "categoryName": "Plumber",
      "phone": "(470) 555-0102",
      "address": "Sandy Springs, GA",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 0,
      "placeId": "demo-place-07",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-07"
    },
    {
      "title": "Metric Plumbing Repair Sandy Springs",
      "categoryName": "Plumber",
      "phone": "(470) 555-0103",
      "address": "Sandy Springs, GA",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 2,
      "totalScore": 5,
      "placeId": "demo-place-08",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-08"
    }
  ],
  "lowReviewsThreshold": 10,
  "mergeNearDuplicates": true,
  "targetCategories": [],
  "categoryMode": "drop",
  "dropClosed": true,
  "dropNoPhone": false,
  "defaultCountry": "US",
  "leadFarmMode": "drop",
  "onlyNewSinceLastRun": false,
  "historyKey": "default"
}
```

# Actor output Schema

## `leads` (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 = {
    "items": [
        {
            "title": "Demo Peachtree Plumbing",
            "categoryName": "Plumber",
            "phone": "(404) 555-0142",
            "website": "https://example.com/peachtree-plumbing",
            "address": "100 Demo St, Sandy Springs, GA 30328",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 212,
            "totalScore": 4.8,
            "placeId": "demo-place-01",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-01"
        },
        {
            "title": "Demo Peachtree Plumbing LLC",
            "categoryName": "Plumber",
            "phone": "+1 404-555-0142",
            "website": "https://example.com/peachtree-plumbing",
            "address": "100 Demo Street, Sandy Springs, GA 30328",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 9,
            "totalScore": 4.6,
            "placeId": "demo-place-02",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-02"
        },
        {
            "title": "Demo Riverside Drain & Sewer",
            "categoryName": "Plumber",
            "phone": "(770) 555-0188",
            "website": "https://example.com/riverside-drain",
            "address": "200 Sample Ave, Sandy Springs, GA 30350",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 87,
            "totalScore": 4.7,
            "placeId": "demo-place-03",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-03"
        },
        {
            "title": "Demo Old Town Plumbers",
            "categoryName": "Plumber",
            "phone": "(404) 555-0170",
            "address": "300 Example Rd, Sandy Springs, GA 30328",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 41,
            "totalScore": 4.1,
            "permanentlyClosed": true,
            "placeId": "demo-place-04",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-04"
        },
        {
            "title": "Demo Quick Lube Auto Repair",
            "categoryName": "Auto repair shop",
            "phone": "(404) 555-0123",
            "website": "https://example.com/quick-lube",
            "address": "400 Test Blvd, Sandy Springs, GA 30328",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 150,
            "totalScore": 4.4,
            "placeId": "demo-place-05",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-05"
        },
        {
            "title": "Halcy Plumbing Repair Sandy Springs",
            "categoryName": "Plumber",
            "phone": "(470) 555-0101",
            "address": "Sandy Springs, GA",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 1,
            "totalScore": 5,
            "placeId": "demo-place-06",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-06"
        },
        {
            "title": "Gravix Plumbing Repair Sandy Springs",
            "categoryName": "Plumber",
            "phone": "(470) 555-0102",
            "address": "Sandy Springs, GA",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 0,
            "placeId": "demo-place-07",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-07"
        },
        {
            "title": "Metric Plumbing Repair Sandy Springs",
            "categoryName": "Plumber",
            "phone": "(470) 555-0103",
            "address": "Sandy Springs, GA",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 2,
            "totalScore": 5,
            "placeId": "demo-place-08",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-08"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("callbacklocal/google-maps-lead-cleaner").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 = { "items": [
        {
            "title": "Demo Peachtree Plumbing",
            "categoryName": "Plumber",
            "phone": "(404) 555-0142",
            "website": "https://example.com/peachtree-plumbing",
            "address": "100 Demo St, Sandy Springs, GA 30328",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 212,
            "totalScore": 4.8,
            "placeId": "demo-place-01",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-01",
        },
        {
            "title": "Demo Peachtree Plumbing LLC",
            "categoryName": "Plumber",
            "phone": "+1 404-555-0142",
            "website": "https://example.com/peachtree-plumbing",
            "address": "100 Demo Street, Sandy Springs, GA 30328",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 9,
            "totalScore": 4.6,
            "placeId": "demo-place-02",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-02",
        },
        {
            "title": "Demo Riverside Drain & Sewer",
            "categoryName": "Plumber",
            "phone": "(770) 555-0188",
            "website": "https://example.com/riverside-drain",
            "address": "200 Sample Ave, Sandy Springs, GA 30350",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 87,
            "totalScore": 4.7,
            "placeId": "demo-place-03",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-03",
        },
        {
            "title": "Demo Old Town Plumbers",
            "categoryName": "Plumber",
            "phone": "(404) 555-0170",
            "address": "300 Example Rd, Sandy Springs, GA 30328",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 41,
            "totalScore": 4.1,
            "permanentlyClosed": True,
            "placeId": "demo-place-04",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-04",
        },
        {
            "title": "Demo Quick Lube Auto Repair",
            "categoryName": "Auto repair shop",
            "phone": "(404) 555-0123",
            "website": "https://example.com/quick-lube",
            "address": "400 Test Blvd, Sandy Springs, GA 30328",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 150,
            "totalScore": 4.4,
            "placeId": "demo-place-05",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-05",
        },
        {
            "title": "Halcy Plumbing Repair Sandy Springs",
            "categoryName": "Plumber",
            "phone": "(470) 555-0101",
            "address": "Sandy Springs, GA",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 1,
            "totalScore": 5,
            "placeId": "demo-place-06",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-06",
        },
        {
            "title": "Gravix Plumbing Repair Sandy Springs",
            "categoryName": "Plumber",
            "phone": "(470) 555-0102",
            "address": "Sandy Springs, GA",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 0,
            "placeId": "demo-place-07",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-07",
        },
        {
            "title": "Metric Plumbing Repair Sandy Springs",
            "categoryName": "Plumber",
            "phone": "(470) 555-0103",
            "address": "Sandy Springs, GA",
            "city": "Sandy Springs",
            "state": "Georgia",
            "reviewsCount": 2,
            "totalScore": 5,
            "placeId": "demo-place-08",
            "url": "https://www.google.com/maps/place/?q=place_id:demo-place-08",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("callbacklocal/google-maps-lead-cleaner").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 '{
  "items": [
    {
      "title": "Demo Peachtree Plumbing",
      "categoryName": "Plumber",
      "phone": "(404) 555-0142",
      "website": "https://example.com/peachtree-plumbing",
      "address": "100 Demo St, Sandy Springs, GA 30328",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 212,
      "totalScore": 4.8,
      "placeId": "demo-place-01",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-01"
    },
    {
      "title": "Demo Peachtree Plumbing LLC",
      "categoryName": "Plumber",
      "phone": "+1 404-555-0142",
      "website": "https://example.com/peachtree-plumbing",
      "address": "100 Demo Street, Sandy Springs, GA 30328",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 9,
      "totalScore": 4.6,
      "placeId": "demo-place-02",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-02"
    },
    {
      "title": "Demo Riverside Drain & Sewer",
      "categoryName": "Plumber",
      "phone": "(770) 555-0188",
      "website": "https://example.com/riverside-drain",
      "address": "200 Sample Ave, Sandy Springs, GA 30350",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 87,
      "totalScore": 4.7,
      "placeId": "demo-place-03",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-03"
    },
    {
      "title": "Demo Old Town Plumbers",
      "categoryName": "Plumber",
      "phone": "(404) 555-0170",
      "address": "300 Example Rd, Sandy Springs, GA 30328",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 41,
      "totalScore": 4.1,
      "permanentlyClosed": true,
      "placeId": "demo-place-04",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-04"
    },
    {
      "title": "Demo Quick Lube Auto Repair",
      "categoryName": "Auto repair shop",
      "phone": "(404) 555-0123",
      "website": "https://example.com/quick-lube",
      "address": "400 Test Blvd, Sandy Springs, GA 30328",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 150,
      "totalScore": 4.4,
      "placeId": "demo-place-05",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-05"
    },
    {
      "title": "Halcy Plumbing Repair Sandy Springs",
      "categoryName": "Plumber",
      "phone": "(470) 555-0101",
      "address": "Sandy Springs, GA",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 1,
      "totalScore": 5,
      "placeId": "demo-place-06",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-06"
    },
    {
      "title": "Gravix Plumbing Repair Sandy Springs",
      "categoryName": "Plumber",
      "phone": "(470) 555-0102",
      "address": "Sandy Springs, GA",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 0,
      "placeId": "demo-place-07",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-07"
    },
    {
      "title": "Metric Plumbing Repair Sandy Springs",
      "categoryName": "Plumber",
      "phone": "(470) 555-0103",
      "address": "Sandy Springs, GA",
      "city": "Sandy Springs",
      "state": "Georgia",
      "reviewsCount": 2,
      "totalScore": 5,
      "placeId": "demo-place-08",
      "url": "https://www.google.com/maps/place/?q=place_id:demo-place-08"
    }
  ]
}' |
apify call callbacklocal/google-maps-lead-cleaner --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,callbacklocal/google-maps-lead-cleaner"
        }
    }
}
```

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/CVTXSsMxaazDohC3m/builds/cbyUvyHbl8dHcnp4K/openapi.json
