# Google Maps Rank Tracker (Geo-Grid Local SEO Heatmap) (`latentlark/google-maps-rank-tracker`) Actor

Track where a business ranks on Google Maps across an N×N geo-grid, like Local Falcon. One row per point with organic rank, top competitors and sponsored pins, plus average rank, share of local voice and a heatmap PNG. Pay per grid point.

- **URL**: https://apify.com/latentlark/google-maps-rank-tracker.md
- **Developed by:** [LatentLark](https://apify.com/latentlark) (community)
- **Categories:** SEO tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 1,000 grid point checkeds

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

## Google Maps Rank Tracker (Geo-Grid Local SEO Heatmap)

**For local SEO agencies, freelancers and business owners.** See where a business ranks on **Google Maps** for a keyword at every point of an N×N grid over a city, the same view Local Falcon and similar tools give you, without a monthly subscription.

**Outcome:** one picture that shows where a business is visible on the map and where competitors take the customers, plus the numbers to track it week by week.

- 📍 **Rank at every grid point:** 3×3 up to 9×9 (81 points), searched as if standing at each point.
- 🥇 **Who beats you there:** top 3 competitors per point with rating and review count.
- 📢 **Ads kept separate:** sponsored pins are listed per point and never counted in the organic rank.
- 🗺️ **Heatmap PNG + summary:** average rank, share of local voice (top‑3 %) and a ready-to-share image.
- 💸 **Pay per point:** $0.004 per grid point checked. A 3×3 costs about $0.05, a 7×7 about $0.21. No login, no Google API key.

![Heatmap: Google Maps rank of a downtown Austin dentist for "dentist" at 49 grid points, rank 1 at the center and not found at the edges](https://api.apify.com/v2/key-value-stores/Tv899H9p8Kim9T8M2/records/gmrt-heatmap-7x7-austin-dentist.png?signature=1IAgg16QUG76xV9WCzhH0)

**Need done-for-you setup (custom scrape or n8n wiring)?** → [Fiverr Apify scrape gig](https://www.fiverr.com/latent_lark/scrape-website-data-with-apify-into-clean-csv-excel-or-google-sheets) + [Fiverr n8n automation gig](https://www.fiverr.com/latent_lark/build-n8n-ai-automation-workflows-for-your-business)

### Quick start (first run in about 30 seconds)

1. Click **Try for free** (or **Start** in Console). The form is prefilled with `Swish Dental Downtown`, keyword `dentist`, a 3×3 grid 2 km apart over downtown Austin.
2. Click **Start**. You get 9 rows in the **Output** tab and a heatmap in **Storage → Key-value store → HEATMAP.png**, for about **$0.05**.
3. Replace the business, keyword and center with your own (or your client's). Use 5×5 or 7×7 for a full city.

**Tip:** paste the business's **Google Maps URL** instead of the name for an exact match (useful for chains with many locations).

### What you can do with it

- **Local SEO audits:** show a prospect where they are invisible on the map, one picture, no spreadsheet.
- **Client reporting:** run the same grid weekly and compare average rank over time.
- **Competitor mapping:** see which competitors own the top 3 in each part of town, and who runs Maps ads there.
- **Before/after proof:** run a grid before and after a Google Business Profile change.
- **Pitch material:** pair it with [Google Maps Leads Website Audit & Pitch Generator](https://apify.com/latentlark/local-lead-audit) for the website side.

### Input

| Field | What it does |
|---|---|
| `businessName` / `mapsUrl` / `placeId` | The business to track. URL or Place ID is the most precise |
| `keyword` | What customers type into Google Maps (`dentist`, `plumber near me`) |
| `center` | Address, city or `lat,lng`. Empty = the business's own location |
| `gridSize` | 3, 5, 7 or 9 points per side (9 to 81 points) |
| `gridSpacingKm` or `radiusKm` | Distance between points, or from the center to the edge |
| `maxRank` | Look up to rank 20 (1 request per point), 40 or 60 |
| `maxCompetitorsPerPoint` | Competitors listed per point (default 3) |
| `country` / `language` | Google `gl` / `hl` codes |
| `pinLocation` | Search as if standing at each grid point (default on). Makes ranks independent of the server's location |
| `zoom` | Advanced: map zoom per point (default 15) |
| `proxyConfiguration` | Optional. No proxy by default; use RESIDENTIAL (US) if you get blocked on big or frequent grids |

Example (7×7 over a metro area):

```json
{ "businessName": "Swish Dental Downtown", "keyword": "dentist", "center": "30.2672, -97.7431", "gridSize": 7, "gridSpacingKm": 1.5 }
```

### Output

One dataset item per grid point:

![Dataset: one row per grid point with lat/lng, organic rank, the #1 business at that point and sponsored pin count](https://api.apify.com/v2/key-value-stores/Tv899H9p8Kim9T8M2/records/gmrt-results-table.png?signature=1LuSiwSF7hCPLJyN4rXKs)

```json
{
  "pointIndex": 4, "gridRow": 1, "gridCol": 1, "isCenter": true,
  "lat": 30.2672, "lng": -97.7431,
  "keyword": "dentist", "targetName": "Swish Dental Downtown", "targetPlaceId": "ChIJdWgENLS1RIYReos4IrRuTmQ",
  "rank": 1, "rankLabel": "1", "found": true, "resultsChecked": 20,
  "topCompetitors": [
    { "rank": 1, "name": "Swish Dental Downtown", "rating": 4.5, "reviewCount": 988, "category": "Dentist" },
    { "rank": 2, "name": "Toothbar", "rating": 4.9, "reviewCount": 735, "category": "Dentist" }
  ],
  "adsCount": 1, "targetAdPosition": null,
  "sponsored": [ { "adPosition": 1, "name": "Example Dental Group", "displayUrl": "www.example-dental.com" } ],
  "scrapedAt": "2026-10-26T11:03:45+00:00"
}
```

- `rank` is the **organic** position (ads excluded). It is `null` (label `20+`) when the business isn't in the results checked at that point.
- `sponsored` lists the Maps ads shown at that point; `targetAdPosition` is set when your business itself runs an ad there.

The key-value store also has:

- `SUMMARY`: average rank where found (ARP), average rank over all points with not-found counted as `maxRank + 1` (ATRP), share of local voice (% of points in the top 3), points found, points with ads.
- `HEATMAP.png`: color-coded grid (green 1‑3, yellow 4‑10, orange 11‑20, red not found).

### Run it on a schedule

1. Fill in your business, keyword and grid, then **Save as task**.
2. **Schedule** it, e.g. weekly on Monday `0 7 * * 1`.
3. Send results to a sheet with [Google Sheets Export](https://apify.com/latentlark/sheets-export) or to Slack/email via **Integrations**.

| Grid | Points | Per run | Weekly (≈4.3 runs/month) | Daily (30 runs/month) |
|---|---|---|---|---|
| 3×3 | 9 | $0.046 | ~$0.20/month | ~$1.38/month |
| 5×5 | 25 | $0.11 | ~$0.47/month | ~$3.30/month |
| 7×7 | 49 | $0.206 | ~$0.89/month | ~$6.18/month |
| 9×9 | 81 | $0.334 | ~$1.44/month | ~$10.02/month |

Several keywords? Save one task per keyword (or per client) and schedule each.

### Pricing

Pay per event, no subscription:

| Event | Free plan | Bronze | Silver | Gold+ |
|---|---|---|---|---|
| Actor start | $0.01 | $0.01 | $0.01 | $0.01 |
| Grid point checked | $0.004 | $0.0036 | $0.0032 | $0.0028 |

Example (free plan): a 7×7 grid (49 points) costs $0.01 + 49 × $0.004 = **$0.206**. Paid Apify plans pay 10–30% less per point.

Failed points and input errors are not charged. Set a **maximum cost per run** and the Actor stops cleanly when it reaches it. Platform usage is included.

### How it works and limitations

- At each grid point the Actor loads Google Maps results for your keyword with the map centred on that point, the same list a person sees when they search there. Ranks are a snapshot at run time and can shift by a few places between runs.
- Each grid point is searched with the searcher's location set to that point, like a phone with GPS on. In our tests the same grid gave the same ranks from a German server, a US datacenter and US residential IPs.
- Sponsored (ad) pins are reported separately in `sponsored` and never counted in `rank`. Google shows Maps ads only some of the time, so `adsCount` varies between runs.
- Rank depends on the map zoom: 15 (about 4 km across) mirrors a phone search in a neighbourhood. Lower zoom (13) shows the whole city and ranks barely change between nearby points.
- Public Google Maps data only. No login, no personal data.

### FAQ

**My business shows "20+" (not found) everywhere.** Check the name matches Google Maps exactly, or paste the business's Google Maps URL. Make sure `center` is near the business, use a smaller spacing, or raise `maxRank` to 40/60. The run status message tells you when the business wasn't found at any point.

**The run returned one row with an `error`.** That means the input could not be used (e.g. the address could not be found or the business could not be identified). The run still finishes as succeeded so your schedules stay green, and the row is not charged. Fix the input and run again.

**Why is my rank different from what I see on my phone?** Google personalises results by your history and exact location. This Actor searches logged-out from each grid point, which is the standard way geo-grid tools measure rank.

**Can I track several keywords or locations?** Yes. Save one task per keyword/location and schedule them; each run is billed separately.

**Is a proxy needed?** No for normal use. If you run big grids very often and see failed points, set the proxy to RESIDENTIAL with country US.

### More from LatentLark

- [Google Maps Leads Website Audit & Pitch Generator](https://apify.com/latentlark/local-lead-audit): audit local business websites (SSL, speed, tracking, booking), find owner contacts and get a cold-email pitch.
- [Google Ads Transparency & LinkedIn Ad Library Scraper](https://apify.com/latentlark/competitor-ads-monitor): see which competitors run Google or LinkedIn ads.
- [Google Sheets Export & Import (No OAuth)](https://apify.com/latentlark/sheets-export): send any Actor's results to a Google Sheet on a schedule.

# Actor input Schema

## `businessName` (type: `string`):

The business to track, as it appears on Google Maps (e.g. 'Swish Dental Downtown'). Used to find it near the center. For an exact match, paste the Maps URL or Place ID instead.

## `mapsUrl` (type: `string`):

The business's Google Maps place link. Most precise way to identify it.

## `placeId` (type: `string`):

Google Place ID (starts with ChIJ…).

## `keyword` (type: `string`):

What customers search on Google Maps, e.g. 'dentist', 'plumber near me', 'coffee shop'.

## `center` (type: `string`):

An address, city or 'lat,lng'. Empty = the business's own location.

## `gridSize` (type: `integer`):

Points per side, odd number: 3 = 9 points, 5 = 25, 7 = 49, 9 = 81.

## `gridSpacingKm` (type: `number`):

Spacing between neighbouring grid points. 1 km suits a city center, 2-5 km a metro area. Ignored if 'Radius' is set.

## `radiusKm` (type: `number`):

Alternative to spacing: distance from the center to the grid edge. Spacing = 2 × radius / (grid size − 1).

## `maxRank` (type: `integer`):

How deep to look at each point. 20 = first page of Maps results (1 request per point); 40 or 60 = 2-3 requests per point.

## `maxCompetitorsPerPoint` (type: `integer`):

Top-ranked businesses to list at each point.

## `country` (type: `string`):

2-letter Google country code, e.g. us, gb, de.

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

Google interface language, e.g. en, de, fr.

## `pinLocation` (type: `boolean`):

Tell Google the searcher is standing at each grid point (like a phone with GPS), so results don't depend on the server's location. Recommended.

## `zoom` (type: `number`):

Map zoom used at each point. Maps ranks places inside the visible map, so zoom decides how local each check is. 15 (about 4 km across) mirrors a phone search in a neighbourhood and is the default. 13 = whole-city view (ranks barely change between nearby points); 16-17 = very tight.

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

Grid points checked at the same time.

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

Optional. Default (no proxy) works and costs nothing extra; results are location-pinned per grid point so the server IP doesn't matter. Use RESIDENTIAL (country US) if you hit blocks at large grids or frequent schedules (~$0.0003 per point). GOOGLE_SERP proxy is not supported (it can't fetch Maps results).

## Actor input object example

```json
{
  "businessName": "Swish Dental Downtown",
  "keyword": "dentist",
  "center": "30.2672, -97.7431",
  "gridSize": 3,
  "gridSpacingKm": 2,
  "maxRank": 20,
  "maxCompetitorsPerPoint": 3,
  "country": "us",
  "language": "en",
  "pinLocation": true,
  "zoom": 15,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Rank, lat/lng and top competitors at each point.

## `summary` (type: `string`):

Average rank, share of local voice (top-3 %), points found.

## `heatmap` (type: `string`):

Color-coded rank grid.

# 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 = {
    "businessName": "Swish Dental Downtown",
    "keyword": "dentist",
    "center": "30.2672, -97.7431",
    "gridSize": 3,
    "gridSpacingKm": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("latentlark/google-maps-rank-tracker").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 = {
    "businessName": "Swish Dental Downtown",
    "keyword": "dentist",
    "center": "30.2672, -97.7431",
    "gridSize": 3,
    "gridSpacingKm": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("latentlark/google-maps-rank-tracker").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 '{
  "businessName": "Swish Dental Downtown",
  "keyword": "dentist",
  "center": "30.2672, -97.7431",
  "gridSize": 3,
  "gridSpacingKm": 2
}' |
apify call latentlark/google-maps-rank-tracker --silent --output-dataset

```

## MCP server setup

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

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/MimoYU1j3mT7416RC/builds/4f6dj0mVlKkeBEaYf/openapi.json
