ScavioScavio
ToolsPricing
Sign InsGet Startedg
Blog
googlelocal-seoserp-api

Google Local Pack Scraping: Why the location Parameter Returns the Wrong City

Pass ll coordinates to Scavio's /api/v2/google/maps/search, not a location string to the SERP endpoint. Over six cities that scored 6 of 6 against 0 of 18.

August 24, 2026
8 min read
Try Scavio FreePricing

50 free credits · no credit card

To pull the local pack for a specific city, send coordinates to a Maps endpoint rather than a location string to a SERP endpoint. Scavio's /api/v2/google/maps/search with ll=@lat,lng,12z returned businesses registered in the requested city in 6 of 6 cities tested. The same query through /api/v2/google with location="Austin,Texas,United States" matched the requested city 0 times in 18 attempts, and the businesses it returned instead were in Florida, Oklahoma, Oregon and Ohio.

That is the whole finding. The rest of this post is the measurement, the control that makes it trustworthy, and the cost of doing it properly.

What was measured

Three queries with unambiguous local intent - hvac repair, emergency plumber, personal injury lawyer - each requested from six US cities: Austin, Boston, Denver, Miami, Phoenix and Seattle. Every request set the canonical location string, for example Austin,Texas,United States, which the endpoint converts to a UULE automatically.

Forty-four live calls in total: 21 through the SERP endpoint, 4 more as a noise control, 3 with the city written into the query text, 6 through the Maps endpoint, and 10 to resolve the returned businesses to real street addresses. Every call cost 1 credit, so the whole study was 44 cents.

The last group matters. A SERP local pack gives you a business name, a rating, a review count and opening hours. It does not give you an address. So a pack full of the wrong city looks exactly like a pack full of the right city until you go and look each business up, which is why this failure survives in production pipelines.

The pack never followed the location string

Two panels comparing where local results came from. With the SERP endpoint location parameter, five of six cities returned the same business registered in Longwood, Florida and the sixth returned Hilliard, Ohio, so none matched the requested city. With the Maps endpoint ll coordinate parameter, all six returned a business registered in the requested city.

For hvac repair, five of the six cities came back with the identical three businesses:

Business returnedWhere it actually is
Air Tech of Central FloridaLongwood, FL
Okla-Home Heating & CoolingBroken Arrow, OK
Air Stars Heating, AC, Plumbing & ElectricalKeizer, OR

Three businesses in three states, served as the local pack for Austin, Miami, Seattle, Denver and Phoenix. The sixth request, Boston, got a different pack that was internally consistent and still wrong: Eco Plumbers in Hilliard OH, Pickerington Heating & Cooling in Pickerington OH, and Dor-Mar in Reynoldsburg OH. All three are suburbs of Columbus, roughly 750 miles from Boston.

The other two queries behaved the same way. emergency plumber returned Handy Plumbing Man, registered in San Carlos, California, to five of six cities; Seattle got three Charleston, South Carolina plumbers. personal injury lawyer returned Carabin Shaw of San Antonio to five of six; Denver got Jeffrey Glassman Injury Lawyers, of Boston.

Eighteen city-specific requests, zero packs in the requested city.

The control that makes this trustworthy

Cross-city differences prove nothing on their own, because a SERP is not a stable object. The number that gives the comparison meaning is how much two identical requests differ.

So: four requests for hvac repair from Austin, differing only by explicitly passing a parameter that was already the default (start: 0, device: "desktop", hl: "en", gl: "us"). Semantically the same request four times.

ComparisonMean shared organic URLs
Same city, four identical requests2.2 of ~10
emergency plumber, across six cities2.9 of ~10
hvac repair, across six cities5.1 of ~10
personal injury lawyer, across six cities6.3 of ~10

Read that table twice. Requests to six different cities agreed with each other more than four identical requests to the same city did. The four identical Austin calls also produced three different local packs.

Whatever the location parameter is doing to the organic list, it is smaller than the churn the endpoint produces standing still. That is the trap: run this test with two cities and no repeat control and you will see the results change, conclude the parameter works, and ship it.

The UULE is fine. The exit is not.

The obvious suspect is the encoding, and it is innocent. Every response echoes the uule it sent, and base64-decoding the payload returns the requested city exactly:

w+CAIQICIaQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM -> Austin,Texas,United States w+CAIQICIiQm9zdG9uLE1hc3NhY2h1c2V0dHMsVW5pdGVkIFN0YXRlcw -> Boston,Massachusetts,United States

Six for six, correct. The parameter reaches Google intact and Google declines to act on it in a way that reaches the pack. The pattern in the data points at the requesting IP: packs cluster into a small number of variants that rotate independently of what was asked for, and those variants are geographically coherent in themselves - three Columbus suburbs together, three Charleston plumbers together. That is what an exit node's own neighbourhood looks like, not what a random sample looks like.

For honesty's sake: that mechanism is inference from the pattern, not something the response states. What is measured is the outcome, which is that the location string does not determine the pack.

What does work

Coordinates on the Maps endpoint. Six cities, ll=@lat,lng,12z, and six correct answers with street addresses in the requested metro:

Python
import requests

r = requests.post(
    "https://api.scavio.dev/api/v2/google/maps/search",
    headers={"Authorization": "Bearer YOUR_KEY"},
    json={"query": "hvac repair", "ll": "@30.2672,-97.7431,12z"},
).json()

for p in r["local_results"][:3]:
    print(p["position"], p["title"], "|", p["address"])
1 Elite Air Conditioning and Plumbing | 7101 Burleson Rd, Austin, TX 78744 2 Radiant Plumbing, Air Conditioning, & Electrical | 901 Reinli St, Austin, TX 78751 3 McCullough Heating, Air Conditioning & Plumbing | 2620 Buell Ave, Austin, TX 78757

Twenty results per call rather than three, each with an address, rating, reviews, phone, website and gps_coordinates. The endpoint's own documentation is blunt about which knob matters: ll is what controls where results come from, not gl.

Writing the city into the query. A partial fix worth knowing about. hvac repair austin tx with no location parameter returned a pack whose three businesses were all in the Austin Maps top twenty. Miami managed two of four and Seattle one of three. It works because the words are part of the query Google answers, rather than a hint about who is asking. It is fine for a one-off lookup and unusable for rank tracking, because you have changed the keyword you are measuring.

The cost of a real geo grid

Grid tools exist because one rank number for a metro is meaningless - the same search from the shop and from four miles away are different searches. A grid is just the same query repeated at a lattice of coordinates.

At 1 credit per Maps call and $0.01 per credit:

  • A 7x7 grid is 49 points, so 49 cents per keyword per scan
  • Ten keywords scanned weekly is about 2,120 calls a month, or roughly $21 a month
  • Fifty keywords across five client locations, scanned weekly, is about $530 a month

You supply the coordinate lattice and the map rendering. What you are buying is the twenty ranked businesses at each point, with addresses, which is the part that has to be correct.

What we cannot do

The location parameter on /api/v2/google is documented as taking a canonical location name and building the UULE, and it does exactly that. What it does not do, today, on the evidence above, is move the local pack. That is a defect on our side rather than a design decision, it is now on the fix list, and until it ships the honest advice is the one in this post: use ll on the Maps endpoint for anything geographic, and treat the SERP pack as national.

Two other limits worth stating. Organic results from a SERP call are volatile enough that single-shot comparisons are not evidence of anything - if you are measuring change, repeat the call and compare distributions, not lists. And a Maps response is one page of twenty; there is no parameter in this study that returns more, so a business ranked thirtieth in a dense metro is simply absent rather than reported low.

Questions people actually ask

Why does my SERP API return the wrong city in the local pack? Because the pack is resolved from where the request physically came from, not from the location string you sent. Eighteen city-specific requests here matched the requested city zero times, with the UULE encoded correctly on every one of them.

What is the Google local pack? The block of three or four businesses with ratings and hours that sits above the organic results on a local-intent query. In a scraped response it is local_results.places, and it carries a title, rating, review count and hours - but no address, which is precisely why a wrong-city pack goes unnoticed.

Does the uule parameter still work? The encoding works. The effect did not appear. Decoding the payload returned the right city on all six requests, and five of those six still received the same three out-of-state businesses.

How do I get local results for a specific city? Coordinates on a Maps endpoint. /api/v2/google/maps/search with ll=@lat,lng,12z returned in-metro businesses in all six cities, twenty per call, with addresses.

Is it legal to scrape Google Maps data? Collecting publicly visible listings is not usually where the risk sits; doing it from a logged-in account, or republishing the result as your own directory, is. Using a managed API changes who holds the session, not what the data is or what you may do with it downstream.

What are the alternatives to Local Falcon for geo grid tracking? A grid tool is a visualisation layer over repeated coordinate-anchored Maps queries, so the alternative is running the lattice yourself: 49 calls for a 7x7 grid, 49 cents per keyword per scan, and you own the rendering.

How many results does a local pack return versus a Maps query? Three or four against twenty. For rank tracking that gap decides whether a client sitting eighth in the metro is invisible or measurable.

Why do two identical SERP requests return different results? Different exits and heavy personalisation on local-intent queries. Four identical requests shared a mean of 2.2 of about 10 organic URLs and produced three different packs.

What this leaves you owning

If you build local rank tracking on a SERP endpoint, you own a silent failure mode: a pack with no address field that looks correct in every log and every dashboard, and that you can only falsify by looking up each business by hand. You also own the coordinate lattice, the scan schedule, and the retry logic for a surface that disagrees with itself 2.2 times out of 10.

Scavio absorbs the request layer. Proxy rotation, the Maps parsing, and the twenty-row response with addresses and gps_coordinates on every row happen on our side, and when Google reshapes that page it is our on-call rather than your Saturday morning. The lattice and the heatmap stay yours; the part that has to be geographically correct does not.

Pricing is 1 credit per request at $0.01 per credit, no monthly commitment. The 44 calls behind this post cost 44 cents. A 7x7 grid on one keyword is 49 cents; ten keywords scanned weekly is about $21 a month.

Start with 50 free credits, no card - enough to run a 7x7 grid on one keyword and check the addresses yourself.

Endpoint reference is in the Google API docs. If you are working the same surface from the other direction, AI Mode barely cites the businesses Maps ranks used this endpoint across 8 markets, and Google Maps data without scraping covers the non-grid case.


Measured on 23 August 2026 against live endpoints. Google personalises local-intent queries heavily and rotates results between requests, so a rerun will produce nearby but not identical figures. The 0-of-18 and 6-of-6 counts were verified by resolving each returned business to a street address rather than by reading its name.

Continue reading

tiktokcomments

Why Does a TikTok Comment Scrape Return Half the Comments?

9 min read
google-ai-modelocal-seo

Does Google AI Mode Cite Local Businesses? 8 Markets, 57 Citations

9 min read
ScavioScavio

One scraper API for every social, search and ecommerce platform. Built for AI agents.

Product

  • Features
  • Pricing
  • Dashboard
  • Affiliates

Developers

  • Documentation
  • API Reference
  • Quickstart
  • MCP Integration
  • Python SDK

Alternatives

  • Tavily Alternative
  • SerpAPI Alternative
  • Firecrawl Alternative
  • Exa Alternative
  • Serper Alternative
  • Tavily vs Scavio
  • SerpAPI vs Scavio
  • All alternatives
  • Compare Scavio vs alternatives

Search APIs

  • Google Search API
  • Amazon Product API
  • YouTube API
  • Reddit API
  • Walmart Product API
  • TikTok API
  • Instagram API

Tools

  • All Tools

© 2026 Scavio. All rights reserved.

Featured on TAAFT
Terms of ServicePrivacy Policy