As of October 7, 2026, Shifter has the largest pool of live US IPs, more than Oxylabs and Bright Data, at a fraction of the cost.Shifter now has the largest pool of live US IPs

See benchmarks

Knowledge

Geo-Grid Rank Tracking: Measuring Local Rankings Block by Block

A local business has no single Google rank: it changes every few blocks. How to measure it with a geo-grid, read the metrics, and act on the map.

Daniel Okafor

October 7, 2026 · 11 min read

Ask a local business owner where they rank for “emergency plumber” and they will usually give one number, often the one they saw searching from their own office. That number is real, but it describes one spot on the map. Google ranks local results partly by distance from the searcher, so the same business can be first on its own street, eighth a mile away and missing entirely across town.

A geo-grid fixes that by measuring the ranking from many points at once. You lay a grid of coordinates over the area a business serves, run the same Maps search from each point, and record where the business appears. The result is a map of rankings rather than a single rank, and it shows exactly where a business wins and where it disappears.

This guide covers how to design the grid, the code to run it, how to read the three metrics teams report from it, and the mistakes that make grids misleading.

Why one rank is not enough

Google’s own guidance names three factors behind local results: relevance (how well the listing matches the search), distance (how far the result is from the searcher or the location in the search) and prominence (how well known the business is, from reviews, links and other signals). Relevance and prominence barely change from one block to the next. Distance changes with every step.

That makes local ranking a surface, not a number. A dentist with a strong profile might hold the top three across a whole district, while a newer competitor only ranks near its own door. A single check from the office hides both facts. So does a city-level check: asking for results “in Chicago” averages away exactly the variation a local business cares about.

If you are new to how location shapes search results more broadly, our guide to geo-targeted SERP APIs for local SEO covers the granularity ladder from country to coordinates. A geo-grid sits on the last rung.

Designing the grid

A grid has three settings, and each one changes what the map can tell you.

SettingWhat it controlsA sensible start
SizeNumber of points per side (7 means 7 x 7 = 49 points)7 for a neighbourhood business, 9 to 13 for a service area
SpacingDistance between neighbouring points0.5 to 1 km in dense cities, 2 to 5 km in suburbs and rural areas
ZoomThe map zoom the search is made at15 for street level, 13 for a wider area

Three rules keep a grid honest:

  • Use an odd size and centre it on the business. The middle point then sits on the address, so the map always shows the best case alongside everything around it.
  • Match the spacing to how people actually search. A coffee shop competes within walking distance; a roofing company competes across a county. A grid that is too tight shows only green, and one that is too wide shows only empty cells.
  • Keep every setting fixed between runs. Size, spacing, zoom, keyword, language and device must stay identical, or two maps cannot be compared.

The code

The module below builds the grid, prepares one Maps search per point, finds the business in each response and summarises the result. It uses only the standard library.

import math

EARTH_RADIUS_KM = 6371.0088
NOT_FOUND = 21  # one past the 20 places a Maps search returns


def grid_points(lat, lng, size=7, spacing_km=1.0):
    """A size x size grid centred on (lat, lng), points spacing_km apart."""
    if size % 2 == 0:
        raise ValueError("size must be odd so the business sits on the centre point")
    half = size // 2
    points = []
    for row in range(size):
        for col in range(size):
            north_km = (half - row) * spacing_km
            east_km = (col - half) * spacing_km
            p_lat = lat + math.degrees(north_km / EARTH_RADIUS_KM)
            p_lng = lng + math.degrees(east_km / (EARTH_RADIUS_KM * math.cos(math.radians(p_lat))))
            points.append({"row": row, "col": col, "lat": round(p_lat, 6), "lng": round(p_lng, 6)})
    return points


def maps_params(keyword, lat, lng, zoom=15, api_key="YOUR_API_KEY"):
    """Query parameters for one Google Maps search seen from (lat, lng)."""
    return {
        "engine": "google_maps",
        "api_key": api_key,
        "q": keyword,
        "type": "search",
        "ll": f"@{lat},{lng},{zoom}z",
        "hl": "en",
    }


def rank_of(response, place_id):
    """Position of the business in one response, or None when it is not listed."""
    for place in response.get("places_results", []):
        if place.get("place_id") == place_id:
            return place.get("position")
    return None


def summarise(ranks, top=3):
    """ranks: one rank (or None) per grid point."""
    found = [r for r in ranks if r is not None]
    return {
        "points": len(ranks),
        "found": len(found),
        "arp": round(sum(found) / len(found), 2) if found else None,
        "atrp": round(sum(r if r is not None else NOT_FOUND for r in ranks) / len(ranks), 2),
        "solv": round(sum(1 for r in found if r <= top) / len(ranks), 3),
    }


def render(points, ranks, size):
    """The grid as text, north at the top: rank per point, '--' when not found."""
    cells = {(p["row"], p["col"]): r for p, r in zip(points, ranks)}
    return "\n".join(
        " ".join(f"{cells[(row, col)]:>2}" if cells[(row, col)] is not None else "--" for col in range(size))
        for row in range(size)
    )

grid_points converts kilometres to degrees on a sphere, so the spacing stays even at any latitude rather than stretching as you move away from the equator. Point 0 is the north-west corner, and rows run north to south.

Running it for one business and keyword is a short loop. Each point becomes one Google Maps search through Shifter’s SERP API, with the coordinates passed in the ll parameter so the search is made from that point:

import json
import os
import time

import requests

from geogrid import grid_points, maps_params, rank_of, render, summarise

API = "https://serp.shifter.io/v1"
KEYWORD = "emergency plumber"
PLACE_ID = "ChIJ_YOUR_PLACE_ID"        # the business you are tracking
CENTER = (41.8781, -87.6298)            # its address
SIZE, SPACING_KM = 7, 1.0

points = grid_points(*CENTER, size=SIZE, spacing_km=SPACING_KM)
ranks = []
for p in points:
    params = maps_params(KEYWORD, p["lat"], p["lng"], api_key=os.environ["SERP_API_KEY"])
    response = requests.get(API, params=params, timeout=60).json()
    ranks.append(rank_of(response, PLACE_ID))
    time.sleep(0.2)

print(render(points, ranks, SIZE))
print(json.dumps(summarise(ranks)))

To match on the right listing, use the business’s place_id rather than its name: names repeat, and franchises share them. You can find the place_id in any Maps response that contains the business.

We tested the module against a synthetic responder that ranks a business by its distance from the centre point, with a slightly weaker eastern side. The output looks like this (the numbers are from the synthetic test, not a real business):

12 10  9  8 11 12 14
10  8  6  6  8 10 12
 9  6  4  3  6  8 11
 8  6  3  1  5  8 10
 9  6  4  3  6  8 11
10  8  6  6  8 10 12
12 10  9  8 11 12 14
{"points": 49, "found": 49, "arp": 8.31, "atrp": 8.31, "solv": 0.082}

The pattern is the one real grids show: strong at the address, fading with distance, and uneven by direction.

Reading the map: three metrics

Teams summarise a grid with three numbers, and each answers a different question.

MetricHow it is calculatedWhat it tells you
ARP, average rank positionMean rank over the points where the business appearsHow well it ranks where it ranks at all
ATRP, average total rank positionMean rank over all points, counting “not found” as 21Overall visibility across the whole area
SoLV, share of local voiceShare of points where the business is in the top 3How much of the map it owns in the map pack

They need to be read together. A business found at only five points, all in the top three, has an excellent ARP and a poor ATRP. The map shows why: it dominates a small area and is invisible everywhere else. That points to a distance problem, not a relevance one, and better on-page work will not fix it.

SoLV matters most for businesses that depend on the map pack, the three local results Google shows above the regular listings. Positions four to twenty exist on the full Maps list, but far fewer searchers scroll that far.

Using a grid to make decisions

A one-off grid is a diagnosis. Repeated grids are where the value is.

  • Compare against competitors on the same grid. Run the same points for the two or three businesses that beat you in the centre. Their maps often show that a competitor wins on prominence (a large, even area) while you win on proximity.
  • Measure change after you act. New reviews, a corrected category or a fixed address should show up as a larger green area a few weeks later. Without a fixed grid you cannot tell an improvement from noise.
  • Track the edges. The cells at the border of a business’s strong area move first, in both directions. Watching them gives earlier warning than the centre does.
  • Check service-area businesses carefully. Businesses that hide their address and serve customers on site often rank very differently from storefronts. A wider grid shows whether they appear where their customers are.

Weekly runs are enough for most businesses. Local rankings do move daily, but a weekly cadence on fixed settings shows trends without paying for every fluctuation. If you also track regular organic rankings, our guide to detecting SERP volatility covers how to tell a real movement from day-to-day noise.

Mistakes that make grids misleading

  • Searching with a city name in the keyword. “Plumber Chicago” tells Google where to look and overrides the point’s location. Use the plain service term the way a nearby searcher would.
  • Mixing devices or languages between runs. Mobile and desktop Maps results differ. Pick one and keep it.
  • Treating “not found” as a rank of 20. A business that is absent is worse than one in twentieth place. Count it separately, as ATRP does with 21, and report the number of points where it was found.
  • Running grids over water or empty land. Points in a lake or a forest add cells no customer will ever search from. Shift the centre or trim those cells before averaging.
  • Reading one run as the truth. Results vary slightly between identical searches. Act on patterns that hold across runs, not on a single cell changing colour.

For the wider picture on clean, consistent rank measurement (personalisation, device and time), see how to measure accurate keyword rankings.

Cost and scale

A grid’s cost is simply points times keywords times runs. A 7 x 7 grid is 49 searches per keyword. Ten keywords tracked weekly is 490 searches a week, or about 2,100 a month. A 13 x 13 grid for the same ten keywords is 1,690 searches a week.

That arithmetic is the main reason to choose the grid size deliberately. Start with a 7 x 7 grid on the keywords that bring in customers, and widen only the ones where the edges of the map are still changing.

FAQ

How many points should a geo-grid have?

For a business serving a neighbourhood, a 7 x 7 grid (49 points) is usually enough. Businesses that serve a whole city or county need wider spacing, and sometimes a 9 x 9 to 13 x 13 grid, to see where their visibility ends.

Is a geo-grid the same as checking rankings by ZIP code?

No. A ZIP code check runs one search for an area and returns one rank. A geo-grid runs a search from each coordinate, so it shows how the ranking changes inside an area, which is exactly what distance-based local results depend on.

Why does my business rank first at the office but not across town?

Distance is one of the main factors in Google’s local results. Near the address, distance works for you. Further away, competitors who are closer to the searcher, or better known, take the top positions.

How often should I run a geo-grid?

Weekly is enough for most businesses. Run an extra grid a few weeks after a significant change, such as new reviews or a corrected business category, to see whether the strong area has grown.

The bottom line

Local rankings are a map, not a number. A geo-grid measures that map with the same search from many points, and three metrics (ARP, ATRP and share of local voice) summarise it. Keep the grid centred on the business, sized to its real market and fixed between runs, and it becomes the most direct way to see where a local business is visible, where it is not, and whether that is changing.

Ready to get started?

Try Shifter's residential proxies, 205M+ IPs, 195+ countries, from $0.10/GB.

Get Started