Google Maps Rank Tracker: Rank Grid API for Local SEO
Pricing
from $4.20 / 1,000 grid point checkeds
Google Maps Rank Tracker: Rank Grid API for Local SEO
Geo-grid local rank tracker for Google Maps: rank at every grid point, top 3 competitors and a heatmap. A Local Falcon alternative, MCP-ready.
Pricing
from $4.20 / 1,000 grid point checkeds
Rating
0.0
(0)
Developer
Ocius Data
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
2 hours ago
Last modified
Security
Limited permissionsShare
Google Maps Rank Grid Tracker (Local SEO)
What the three most-used geo-grid trackers in the Store do not give you: at every point, the business ranked just above you (competitorAbove), its rating and reviews gap, and a plain-language "why this rank" (rankExplanation). Every run also includes the rank change since your last run and a colour HTML heatmap, at no extra cost.
Google Maps Rank Grid Tracker checks where a business ranks on Google Maps at every point of a geo-grid around a centre, the way Local Falcon, BrightLocal or Local Viking do. Give a business (name, place ID or Maps URL), one or more keywords and a grid (3x3 to 9x9, spacing in km or miles). For each point you get the rank of the business (1 to 20), the top 3 competitors with rating and reviews count, and, if you want, all 20 businesses Google shows there. Each keyword also gets a free summary row with average rank, share of local voice (points in the top 3), best and worst point and a text heatmap. You pay only per grid point checked successfully.
Why this geo-grid rank tracker
- Who to overtake, point by point.
competitorAbovenames the business ranked just above yours at each point, with its rating and reviews gap, andrankExplanationsays it in one sentence ("Rank 4. To enter the top 3 (quick win), overtake ..."). Points at rank 4 to 6 are flagged as quick wins. (Checked on 3 November 2026: the three most-used geo-grid trackers compare you with the overall leader or list the top results, but none names the business directly above you at each point.) - Rank change since the last run, built in. Each point gets
previousRank,rankChange(+ means you moved up) andchangeStatus; the summary row gets the change of the average rank and of the share of local voice. The previous ranks are kept in a named key-value store in your account; there is nothing to set up. - HTML heatmap. A colour heatmap for every keyword (record
HEATMAP), linked from the summary row and the run's status message, ready to share with a client. - Real Google Maps results per point. Each point is the same search Google Maps runs when a user looks for the keyword with the map centred there. No browser, no estimates.
- Exact matching by place ID. The Actor looks the business up first and matches it by place ID or CID at every point, so two branches of a chain or similar names are never confused.
- Competitors at every point. The top 3 businesses per point, and a ranking of the competitors that appear most often in the top 3 across the grid.
- Ready-made metrics. Average rank, average total rank (not found counted as 21), share of local voice, points in the top 3 and top 10, best and worst point, and a heatmap you can paste in a report.
- Fair billing. One
grid-pointevent per point with Google results. Failed points, points with no businesses at all and the summary rows are free. Your maximum cost per run is respected. - Clear status per point. Every point ends as
OK,NO_RESULTS,BLOCKEDorERRORin theRUN_SUMMARYrecord. If more than 20% of points fail, the run is marked as failed so you notice. - Safe on long runs. Progress is saved after every point. A platform restart never duplicates rows or charges twice.
How to use it
- Identify the business with one of:
- Business name, as it appears on Google Maps, for example
Expert Dental - Midtown. The Actor finds its place ID and location. - Google Maps URL of the listing (
https://www.google.com/maps/place/...orhttps://maps.app.goo.gl/...). Best for one branch of a chain. - Place ID (
ChIJ...). With a place ID only, also give the centre.
- Business name, as it appears on Google Maps, for example
- Add up to 10 keywords, as customers type them:
dentist,emergency plumber,pizza delivery. - Choose the grid: size (3, 5, 7 or 9 points per side) and spacing between points in km or miles. By default the grid is centred on the business; you can give a centre latitude and longitude or a centre address instead.
- Set language and country (for example
esandcofor Colombia). - Run the Actor. The status message already gives the result in one line, for example:
"dentist": avg rank 4.63 (up 0.4 since last run); top 3 in 2 of 9 points; 6 quick wins at rank 4-6; main competitor: .... Then open the Overview, Grid points and Summary per keyword views, the HTML heatmap, or download JSON, CSV or Excel. - Schedule the same input weekly: from the second run on, every point shows how the rank changed.
Example input: a 7x7 grid with 1 mile spacing for two keywords.
{"businessName": "Expert Dental - Midtown","keywords": ["dentist", "emergency dentist"],"gridSize": 7,"spacing": 1,"distanceUnit": "mi","language": "en","country": "us"}
How big is the grid? Side length = (grid size - 1) x spacing. A 5x5 grid with 1 km spacing covers 4 x 4 km; a 9x9 grid with 2 km spacing covers 16 x 16 km.
Output example and field dictionary
The dataset has two kinds of rows, told apart by recordType (same value as rowType): one row per point and keyword (point) and one free summary row per keyword (summary). The first view, Overview, shows both.
One row per point and keyword (recordType: "point"):
{"recordType": "point","rowType": "point","status": "OK","keyword": "dentist","pointIndex": 13,"row": 3,"col": 3,"isCenter": true,"lat": 40.750371,"lng": -73.978035,"distanceFromCenterKm": 0,"rank": 1,"found": true,"inTop3": true,"isQuickWin": false,"previousRank": 2,"rankChange": 1,"changeStatus": "IMPROVED","rankExplanation": "Rank 1: first local result here. Closest challenger: Diamond District Dental NYC - Midtown Dentist (4.9 stars, 611 reviews).","competitorAbove": null,"resultsCount": 20,"businessName": "Expert Dental - Midtown","businessPlaceId": "ChIJgSvKJARZwokRGGDLFY2oPEc","top1Name": "Expert Dental - Midtown","top2Name": "Diamond District Dental NYC - Midtown Dentist","top3Name": "My NYC Dentist - 34th Street Dental","top3": [{"rank": 1, "name": "Expert Dental - Midtown", "placeId": "ChIJgSvKJARZwokRGGDLFY2oPEc", "cid": "5133162999205027864", "rating": 4.5, "reviewsCount": 2314, "category": "Dentist"},{"rank": 2, "name": "Diamond District Dental NYC - Midtown Dentist", "placeId": "ChIJO8Bn7eRYwokRwZxgpuBFKlU", "cid": "6136794273412062401", "rating": 4.9, "reviewsCount": 611, "category": "Dentist"},{"rank": 3, "name": "My NYC Dentist - 34th Street Dental", "placeId": "ChIJex3pOaxZwokRqFhjqqYmnx0", "cid": "2134467245661968552", "rating": 4.7, "reviewsCount": 503, "category": "Dentist"}],"matchedBy": "placeId/cid","zoom": 14,"language": "en","country": "us","sourceUrl": "https://www.google.com/maps/search/dentist/@40.750371,-73.978035,14z?hl=en&gl=us","checkedAt": "2026-11-02T02:43:23.405Z"}
| Field | Meaning | When it is null |
|---|---|---|
recordType, rowType | point for a grid point, summary for the summary of one keyword (both fields carry the same value). | Never |
status | OK, NO_RESULTS, or, for a point that could not be checked, BLOCKED, ERROR, TIMEOUT or NOT_PROCESSED (free status row). | Never |
keyword | Keyword searched. | Never |
pointIndex, row, col | Point number (1 = north-west corner, row by row) and its position. Row 1 is the northernmost row, column 1 the westernmost. | Never |
isCenter, distanceFromCenterKm | Whether this is the centre point, and its distance from the centre. | Never |
lat, lng | Coordinates of the point. | Never |
rank | Position of the business among the first 20 Google Maps results at this point. | When the business is not in the first 20 |
found, inTop3 | Whether the business appears in the first 20, and in the first 3. | On status rows of points that were not checked |
isQuickWin | The business is at rank 4, 5 or 6: one to three places from the top 3. | On status rows |
previousRank | Rank at the same point in the previous run with the same business, keyword and grid. | First run, point not in the top 20 last time, or comparison turned off |
rankChange | Places gained since the previous run (+ = moved up, - = moved down). "Not in the top 20" counts as 21. | First run or point not comparable |
changeStatus | IMPROVED, DECLINED, UNCHANGED, NEW_IN_TOP20, LOST_FROM_TOP20, FIRST_RUN or NOT_COMPARABLE (the point failed in the previous run). | On status rows |
rankExplanation | One sentence on why the business has this rank here and who to overtake. | Never |
competitorAbove | The business ranked directly above yours: rank, name, place ID, CID, rating, reviews count, category, ratingGap and reviewsGap (positive = it has more). | When your business is rank 1 or not in the top 20 |
businessRating, businessReviewsCount, businessCategory | Rating, reviews count and main category of your business as Google shows them at this point. | When the business is not in the top 20 |
top1Rating, top1ReviewsCount | Rating and reviews count of the first result. | When Google shows no business or no rating |
dataQuality, warnings | OK, CHECK or NOT_CHECKED, and the reasons: MATCHED_BY_NAME (no place ID found, exact name used), FEW_RESULTS (fewer than 10 businesses here), NO_BUSINESSES_AT_POINT, BUSINESS_RATING_MISSING, or the status of a point that was not checked. | Never (empty list when nothing to flag) |
resultsCount | Businesses Google returned at this point (up to 20). | Never |
businessName, businessPlaceId | The tracked business. | businessPlaceId when only a name was given and the lookup found nothing |
top1Name, top2Name, top3Name | Names of the first three businesses, flat for spreadsheets. | When Google shows fewer businesses |
top3 | First three businesses: rank, name, place ID, CID, rating, reviews count, main category, all categories, address, website and coordinates. | Empty list when no results; not present on status rows |
businesses | Only with Include all businesses per point: all businesses at the point with rank, place ID, CID, rating, reviews count, category, address, coordinates and website. | Not present otherwise |
matchedBy | placeId/cid (exact) or name (exact business name, used only when no identifier could be found). | Never |
zoom, language, country | Search settings used. | Never |
sourceUrl | The same search on Google Maps, to check it by hand. | Never |
input, checkedAt | Input of the run and time of the check (ISO 8601, UTC). | Never |
One summary row per keyword (recordType: "summary", free):
| Field | Meaning |
|---|---|
status | OK (every point checked), PARTIAL (some points failed) or FAILED (no point checked). |
insight | The result in one sentence with this run's numbers: average rank and its change, points in the top 3, points improved and declined, quick wins and main competitor. |
business | Name, place ID, CID, rating, reviews count, category, address, coordinates and website of the tracked business. |
gridSize, spacingKm, centerLat, centerLng, centerSource | Grid used and where its centre came from. |
pointsTotal, pointsChecked, pointsFailed | Points in the grid, points checked and points that failed. |
pointsFound, pointsNotFound, pointsInTop3, pointsInTop10 | Points where the business is in the first 20, not in the first 20, in the top 3 and in the top 10. |
averageRank | Average rank over the points where the business was found (null if found nowhere). |
averageTotalRank | Average rank over all checked points, counting "not found" as 21. Lower is better; use it to compare runs. |
shareOfLocalVoice | Percentage of checked points where the business is in the top 3. |
shareOfPointsInTop10, shareOfPointsFound | Percentage of checked points in the top 10 and in the first 20. |
bestPoint, worstPoint | Row, column, coordinates and rank of the best and worst point. |
topCompetitors | The 5 businesses that appear most often in the top 3 across the grid, with their appearances, average rank in the top 3, rating and reviews count. |
quickWinPoints, quickWins | Number and list of points at rank 4 to 6, with the business in third place there. |
previousRunAt | Time of the previous run used for the comparison (ISO 8601, UTC). Null on the first run. |
previousAverageRank, averageRankChange | Average rank of the previous run and the change (+ = better). |
previousAverageTotalRank, averageTotalRankChange | The same for the average total rank. |
previousShareOfLocalVoice, shareOfLocalVoiceChange | Share of local voice of the previous run and the change in percentage points. |
previousPointsInTop3, pointsImproved, pointsDeclined, pointsUnchanged | Top-3 points last time, and how many points moved up, down or stayed. Null on the first run. |
heatmapUrl | Link to the colour HTML heatmap of this run (record HEATMAP). |
dataQuality, warnings | OK or CHECK, with MATCHED_BY_NAME, SOME_POINTS_NOT_CHECKED or BUSINESS_NOT_FOUND_ANYWHERE. |
heatmap, heatmapRows | Text heatmap, north on top: the rank at each point, -- when not in the first 20, ?? when the point failed or was not checked, the centre in brackets. |
Heatmap example (5x5, 1 km, the same run):
1 1 1 1 --1 1 1 2 --1 1 [ 1] 1 --2 2 1 -- ---- -- -- -- --
Key-value store records
| Record | Content |
|---|---|
RUN_SUMMARY | Resolved business and centre, status count per point, the summary and insight of every keyword, the comparison settings, proxy usage, warnings and the reconciliation between rows saved and events charged. |
HEATMAP | Colour HTML heatmap, one grid per keyword, with the change since the previous run on every cell and the competitors most often in the top 3. Self-contained (no scripts). |
STATE | Internal progress, so a platform restart never duplicates rows or charges. |
INPUT | The input of the run. |
The named key-value store maps-rank-grid-history (field History store name) keeps one record per business, keyword and grid with the rank at every point of the last run. Delete it to start the comparison over. Turn Compare with the previous run off to skip it.
The output tab links every view, the grid points as CSV, the HTML heatmap and RUN_SUMMARY.
Pricing and cost calculator
Typical job cost: a 5x5 grid for 1 keyword costs about USD 0.15 (25 points); a 5x5 grid for 3 keywords about USD 0.45 (75 points). Platform compute is included; the summary rows, the comparison with the previous run and the HTML heatmap are free.
Apify Store discounts: grid-point costs 15% less on Silver and 30% less on Gold and above.
Pay per event: USD 0.006 per grid-point, one per point and keyword checked successfully. The only other charge is Apify's standard start event (apify-actor-start), USD 0.00005 per run at the default memory.
| Event | When it is charged |
|---|---|
grid-point | One grid point with Google Maps results, saved to the dataset (whether the business is in the first 20 or not). |
Free plan: the USD 5 of monthly usage included in the Apify Free plan covers about 830 grid points (USD 0.006 each): about 33 scans of a 5x5 grid or 17 scans of a 7x7 grid for one keyword.
Never charged: failed points, points where Google lists no business at all, the summary rows, invalid inputs and the business lookup. Your maximum cost per run is respected: the Actor stops before checking a point it cannot charge.
Points per run = grid size x grid size x keywords. Speed: a 5x5 grid for one keyword finished in 8 to 19 seconds in five test runs on 4 November 2026.
| Scan | Points | Cost |
|---|---|---|
| 3x3, 1 keyword | 9 | USD 0.054 |
| 5x5, 1 keyword | 25 | USD 0.15 |
| 7x7, 1 keyword | 49 | USD 0.29 |
| 9x9, 1 keyword | 81 | USD 0.49 |
| 7x7, 5 keywords | 245 | USD 1.47 |
| Weekly 7x7 for 3 keywords, 4 weeks | 588 per month | USD 3.53 per month |
Formula: points × 0.006. Prices shown are for the Free and Bronze plans; Silver and Gold pay less. Defects: if a run delivers wrong ranks because of a defect in the Actor, open an issue with the run ID. Defects are fixed with priority, usually within 72 hours.
Integrations: schedules, API, webhooks, Sheets and AI agents
Schedules. Save your input as a task and schedule it weekly in Schedules to follow your local rankings over time. Each run compares itself with the previous one automatically (rankChange per point, averageRankChange and shareOfLocalVoiceChange per keyword).
API. Run the Actor and get the results in one call:
curl -X POST "https://api.apify.com/v2/acts/ocius-data~google-maps-rank-grid/run-sync-get-dataset-items?token=YOUR_API_TOKEN&format=json" \-H "Content-Type: application/json" \-d '{"businessName": "Expert Dental - Midtown", "keywords": ["dentist"], "gridSize": 5, "spacing": 1}'
Python, with the official apify-client package:
from apify_client import ApifyClientclient = ApifyClient("YOUR_API_TOKEN")run = client.actor("ocius-data/google-maps-rank-grid").call(run_input={"businessName": "Expert Dental - Midtown", "keywords": ["dentist"], "gridSize": 7})for row in client.dataset(run["defaultDatasetId"]).iterate_items():if row["rowType"] == "summary":print(row["keyword"], row["averageTotalRank"], row["shareOfLocalVoice"])print(row["heatmap"])
Webhooks. In the task, open Integrations, add a webhook for ACTOR.RUN.SUCCEEDED and download the dataset from resource.defaultDatasetId.
Google Sheets, Zapier, Make and n8n. Use the Apify integration or app. Filter rows by rowType to keep points and summaries in separate sheets.
MCP and AI agents. Add ocius-data/google-maps-rank-grid to the Apify MCP server (https://mcp.apify.com) and an agent can run a grid with plain inputs such as {"businessName": "...", "keywords": ["..."]}.
Statuses and errors
Every point has a row in the dataset with its status. Points that could not be checked get a free status row with dataQuality: "NOT_CHECKED" and the reason in rankExplanation. The same counts are in the RUN_SUMMARY record.
| Status | Meaning | Charged | What to do |
|---|---|---|---|
OK | Google returned businesses at this point; the rank (or "not found") is saved. | Yes | Nothing |
NO_RESULTS | Google lists no business for this keyword at this point (for example over water). The row is saved with resultsCount: 0. | No | Nothing, or use a smaller spacing. |
BLOCKED | Google kept blocking after all attempts and proxy changes. A free status row is saved. | No | Run again later. |
ERROR | Unexpected response from Google. A free status row is saved. | No | Open an issue with the run ID. |
NOT_PROCESSED | Your maximum cost per run or the timeout was reached first. | No | Raise the limit. |
RUN_SUMMARY also shows the resolved business and centre, the summary of every keyword, the proxy used, warnings (for example "business not found at any point") and the reconciliation between rows saved and events charged.
Known limits
- Depth: ranks 1 to 20 (the first page of Google Maps results). A business below position 20 is reported as not found.
- Results change with the searcher. Google ranks local results by the map position and also by where the searcher's IP is, and results move during the day. By default the Actor uses Apify datacenter IPs for the United States and a residential IP in the selected country elsewhere (the same residential IP for the whole grid). Expect small differences between runs; compare trends over several runs, not one point.
- Zoom changes how far Google looks around each point. Keep the same zoom between runs. The default (14) is a neighbourhood view of about 7 x 5 km.
- Name-only matching is used only when the business cannot be found by name lookup; it requires the exact name as shown on Google Maps.
- Data: business listing data only. No reviews, reviewer names, phone numbers or e-mails are collected.
FAQ
What is share of local voice? The percentage of grid points where the business is in the top 3, which is the part of the map that gets most clicks (the local "3-pack").
What spacing should I use? Dense cities: 0.5 to 1 km. Suburbs: 1 to 3 km. Service-area businesses: 3 to 8 km.
Is it legal? The Actor reads public Google Maps listing data, without login, and collects business information only.
How do I track a competitor? Run the same grid with the competitor's name or Maps URL, or enable Include all businesses per point to see every business at every point in one run.
Related Actors from ocius-data
Built to the same standard (status per input in RUN_SUMMARY, actionable errors, pay only for valid data), for a complete SEO workflow:
- Bulk Keyword Search Volume & CPC - Keyword Planner: search volume, CPC and competition for the keywords you track on the grid.
- Google Autocomplete API: Keyword Ideas & Questions: find the local keywords customers actually type ("dentist near me open now").
- Bulk Domain Authority & Backlinks Checker API: authority and backlinks of your website and of the competitors found on the grid.
Changelog
- November 2026 Fixed: a business name is no longer matched to a different listing that only shares category words (for example "Dental Studio"). When Google's listing name differs from the name you entered, the run now logs a warning with the listing it used.
- 0.1.9 (4 November 2026) Rank change since the previous run at every point and in the summary row (named key-value store, free); per-point
competitorAboveandrankExplanation; quick-win points (rank 4 to 6); colour HTML heatmap (recordHEATMAP) linked from the summary row and the status message; free status rows for points that could not be checked;dataQualityandwarningsper row;recordType, a first Overview view, labelled and formatted columns, and output links for every view, CSV and the heatmap. The final charge check now takes under 1 second instead of about 7 (it reads the platform counter only when the SDK counter does not match). - 0.1.5 (2 November 2026) Fixed a false "charge reconciliation mismatch" warning in RUN_SUMMARY: the final check now waits for the platform charge counter to catch up. Charges themselves were always correct.
- 0.1 (November 2026) First version: 3x3 to 9x9 grids in km or miles, business lookup by name, place ID or Maps URL, centre by coordinates or address, top 3 competitors per point, optional full list of businesses, summary row with average rank, share of local voice, top competitors and text heatmap.
Tutorials and examples
Ready-to-import templates: Google Sheets, Make, Zapier and a webhook receiver.
- Tutorial: Google Maps rank grid tracker with an API: a local SEO heatmap in JavaScript
- Example code: JavaScript: rank grid heatmap
- All examples: apify-data-apis-examples on GitHub
Rate this Actor
If this Actor saved you time, please consider leaving a rating or a short review on its Apify Store page. It helps other users find it and shows us what to improve. If something does not work as expected, please open an issue first so we can fix it.
Support
Open an issue on the Actor page. Issues are answered within one business day.