The UULE Parameter: How Google Location Targeting Actually Works
The uule parameter is a URL parameter Google Search accepts to set the searcher's location for a single query. Its value is a base64-encoded protocol buffer: the w+ form carries a canonical place name from Google's Ads geotargets list, while the a+ form carries raw latitude/longitude with a radius. It is how location-aware rank checks simulate searching from a specific place without being there.
Plenty of articles mention uule; very few explain what is actually inside it, and at least one example string that gets copied from guide to guide is subtly malformed. This is the technical reference: both variants decoded byte by byte, working Python you can paste (we ran it — outputs shown), and an honest note on what a uule can and cannot fix. If what you actually need is local-pack strategy, that lives in our geo-grid local rank tracking guide and the local rank tracking API page — this post is the encoding layer underneath them.
Where uule sits among Google's location signals
Google Search takes several location-related inputs, and they do different jobs. Mixing them up is the most common reason a “localized” check silently isn't.
| Parameter | What it does | Granularity |
|---|---|---|
gl | Country of the search market | Country |
hl | Interface language | Language |
uule | Sets the searcher's location for this query | City / coordinates |
| IP address | Default location signal when nothing else is set | Whatever the IP resolves to |
A uule doesn't replace gl and hl — location-testing guides pair all three (?q=pizza+delivery&uule=w+CAI…&gl=US&hl=en) so the market, language, and searcher location all agree. And because results still vary by time and personalization even with identical parameters, treat any single check as a sample, not the truth — that problem is why your rank tracker and Search Console never quite agree.
The w+ variant: a canonical name in a protobuf envelope
Strip the w+ prefix and base64-decode the rest and you get a small protocol buffer, as documented in valentin.app's teardown: field 1 is a role identifier (value 2), field 2 is a producer enum (value 32, which the teardown identifies as AdWords), and field 4 is the canonical place name as a length-prefixed string. That's the whole payload — five fixed header bytes, one length byte, then the name:
08 02 field 1, varint = 2 (role)
10 20 field 2, varint = 32 (producer: AdWords)
22 <len> field 4, length-delimited string
<name> the canonical name, UTF-8
Because the first five bytes never change, every w+ uule starts with the same seven base64 characters: CAIQICI. The next character encodes the top bits of the length byte — which is why older guides talk about a “secret key” lookup table indexed by name length. There's no secret: it's just the protobuf length prefix landing inside base64.
Where canonical names come from
The name inside a w+ uule is not free text. It must exactly match a canonical name from Google's geo targets list, published in the Google Ads API documentation as a downloadable CSV. Each row carries a Criteria ID, a name, a canonical name in City,Region,Country form, and a target type. New York,New York,United States is valid; NYC is not. When a location check mysteriously returns un-localized results, a misspelled or non-canonical name is the first thing to rule out.
Generate a w+ uule in Python (tested)
Here is a complete generator and decoder. We ran exactly this code before publishing; the output below is real, not typed from memory.
import base64
def make_uule(canonical_name: str) -> str:
"""Build a w+ uule from a Google Ads canonical location name."""
name = canonical_name.encode("utf-8")
if len(name) > 127:
raise ValueError("names longer than 127 bytes need multi-byte varint handling")
payload = b"\x08\x02\x10\x20\x22" + bytes([len(name)]) + name
return "w+" + base64.urlsafe_b64encode(payload).decode("ascii").rstrip("=")
def decode_uule(uule: str) -> str:
"""Recover the canonical name from a w+ uule."""
b64 = uule[2:] if uule.startswith("w+") else uule
b64 += "=" * (-len(b64) % 4)
raw = base64.urlsafe_b64decode(b64)
assert raw[:5] == b"\x08\x02\x10\x20\x22", "unexpected protobuf header"
n = raw[5]
return raw[6:6 + n].decode("utf-8")
uule = make_uule("New York,New York,United States")
print(uule)
print(decode_uule(uule))
Output from our run (Python 3, July 17, 2026):
w+CAIQICIfTmV3IFlvcmssTmV3IFlvcmssVW5pdGVkIFN0YXRlcw
New York,New York,United States
The round-trip is the point: generate, decode, and confirm you get the exact canonical name back. The single length byte covers names up to 127 UTF-8 bytes; beyond that, protobuf switches to a multi-byte varint, which the code above deliberately refuses rather than silently mis-encoding — no canonical city name we've seen comes close to that limit.
The malformed example that guides keep copying
While testing, we decoded a w+ example string that circulates through several location-testing guides: w+CAIQICIdQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM, presented as “Austin,Texas,United States”. Its header decodes to 08 02 10 20 22 1d — a declared length of 29 bytes — but the name that follows is only 26 bytes long. A strict protobuf parser reads three bytes past the string's end. The correctly encoded form, from the code above, is w+CAIQICIaQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM (length byte 1a = 26). Google's parser appears tolerant of the malformed version, but if your uule “works sometimes,” a wrong length byte from a copied lookup table is worth ruling out — generate, then verify by decoding, and you never inherit someone else's off-by-three.
Why your uule isn't working: the four usual suspects
When a localized check comes back looking suspiciously un-local, the failure is almost always one of four mechanical issues — and each has a distinct symptom:
| Symptom | Likely cause | Fix |
|---|---|---|
| Results ignore the location entirely | The name isn't a canonical name (“NYC”, a typo, wrong comma format) | Look the place up in the geotargets CSV and copy the canonical name exactly |
| Location works in the browser but not from code | The + after w was mangled in transit — in a query string a literal + decodes as a space, and some HTTP libraries encode it as %2B while others don't | Log the exact final URL your client sends and confirm what arrives after decoding is still w+CAIQICI… |
| Location applies but market/language look wrong | uule sent without gl/hl, so the market defaults from other signals | Always pair uule with explicit gl and hl |
| Works intermittently across tools | A malformed encoding (wrong length byte) copied from a guide | Generate with the code above, then verify with decode_uule() round-trip |
The decoder doubles as an audit tool for uule strings you find in the wild: paste any w+ value into decode_uule() and it either returns the exact canonical name or fails loudly on a bad header or length — which is precisely how we caught the malformed example above.
The a+ variant: coordinates, timestamp, radius
The second form starts with a+ and, per the same public teardown, contains readable key-value text after decoding: role, producer, and provenance fields, a timestamp in microseconds since the epoch, latitude and longitude as latlng e7 integers (degrees × 10,000,000), and a radius value. Location-testing guides reach for a+ when they need a precise point — a neighborhood or an exact address — rather than a city centroid. The exact semantics of every a+ field (the radius unit conversion, for one) are not publicly documented by Google; treat third-party descriptions of those details as reverse-engineered observations, not a spec.
What a uule cannot fix
A uule sets where Google thinks the searcher is standing — it does not make local results uniform across a city. Local-pack ordering is heavily proximity-driven, so one city-centroid check can disagree with what a searcher sees three miles away, which is why serious local work samples a grid of points rather than a single uule. That methodology — grid spacing, share-of-local-voice math, and what to do when your data source is country-level — is covered in the geo-grid guide and the broader local SEO rank tracking post; this article stops at the encoding.
uule and SERP APIs: what to check before you build
SERP APIs abstract location differently, and the abstraction determines what tracking you can honestly build. Some accept a raw uule or coordinates per request; others take a location name and build the uule for you; others localize at market level only. Serpent API is in the third group, by design: results are localized by a two-letter country code (112 supported countries) plus a language parameter — there is no uule, latitude/longitude, or street-level input. That's the right shape for country-by-country rank tracking and market-level SERP monitoring at low per-call cost, and the wrong shape for per-coordinate local grids — where a coordinate-accepting tool is the honest recommendation. The full parameter reference is in the API docs, and the SERP API overview shows what each endpoint returns.
Whichever tool you use, the checklist is the same: confirm what location input it accepts (uule, coordinates, name, or country), confirm what the parameter actually controls (searcher location vs. market vs. language), and verify with a decode — or a known-answer query — that the location you asked for is the one being applied.
Track rankings across 112 countries
Serpent API returns localized Google, Bing, Yahoo and DuckDuckGo results by country code — flat per-call pricing, up to 10 pages per call, credits that never expire. Start free — 10 searches, no card required.
Start Free — 10 Searches, No CardExplore: SERP API · Rank Tracking API · Local Rank Tracking
FAQ
What is the uule parameter in Google Search?
A URL parameter that sets the searcher's location for one query. Its value is a base64-encoded protocol buffer: w+ carries a canonical place name from Google's geotargets list; a+ carries latitude/longitude with a timestamp and radius.
Where do the canonical names come from?
Google's geo targets CSV, published in the Google Ads API documentation. The string must match a canonical name exactly — New York,New York,United States, not NYC.
What's the difference between w+ and a+?
w+ encodes a named place from the geotargets list; a+ encodes precise coordinates (documented by third-party teardowns as e7 integers) with a radius. w+ is more widely used and better documented.
Does a uule guarantee accurate local pack results?
No. It sets the location signal, but local packs are proximity-driven, so one city-centroid check can differ from what searchers see across town. Grid-based sampling is the standard answer.
Can I pass a uule to the Serpent API?
No — Serpent API localizes by two-letter country code (112 countries) plus language, with no uule or coordinate input. It's built for country-level tracking; for per-coordinate grids, use a coordinate-accepting tool.



