Search "car insurance" from a server in Virginia and you get Geico and Progressive. Run the same query for a German audience and you should see HUK-Coburg and Allianz. If your rank tracker, market research script, or AI agent runs from a US data center, it sees American results by default, no matter who your users are.
The good news: you usually don't need a proxy in Frankfurt to see what Germans see. Google exposes URL parameters that control localization directly, and they're better documented in SEO folklore than anywhere official. Here's how they actually work.
Changing the domain stopped working in 2017
The old trick was to query google.de or google.co.jp instead of google.com. That hasn't worked since October 2017, when Google announced that results are served based on detected location regardless of which country domain you use. Typing google.de from a US IP gets you US results with a German logo.
Google finished the job in early 2025 by redirecting all country-code domains to google.com entirely. So if a tutorial tells you to swap ccTLDs, it's at least eight years out of date.
What replaced the domain trick is a set of query parameters.
The parameters that control localization
| Parameter | What it controls | Example |
|---|---|---|
gl |
Country the results are geolocated for | gl=de for Germany |
hl |
Interface language (also biases result language) | hl=de for German |
lr |
Restrict results to a language | lr=lang_fr |
cr |
Restrict results to pages from a country | cr=countryJP |
uule |
City or region level location | encoded canonical name |
pws |
Personalization (pws=0 disables it) |
pws=0 |
num |
Number of results | num=20 |
The two you'll use constantly are gl and hl, and they answer different questions.
gl answers "where is the searcher standing?" It takes a two-letter country code and shifts the entire result set: which domains rank, which shopping results appear, what the local intent looks like.
hl answers "what language does the searcher read?" It changes the interface and nudges Google toward results in that language.
They're independent for a reason. A French speaker in Montreal is gl=ca&hl=fr. An English-speaking expat in Tokyo is gl=jp&hl=en. Getting this pairing right matters more than people expect; gl=jp&hl=ja and gl=jp&hl=en can return noticeably different pages for the same query.
A concrete example
Here's the same query localized for the US and for Germany:
# US searcher, English interface
curl "https://www.google.com/search?q=car+insurance&gl=us&hl=en&pws=0"
# German searcher, German interface
curl "https://www.google.com/search?q=kfz+versicherung&gl=de&hl=de&pws=0"
Note the query itself changed too. Localizing the parameters while keeping an English keyword is a common mistake in international rank tracking. If your German users search "kfz versicherung", tracking "car insurance" with gl=de tells you nothing useful.
In Python, structured as a comparison:
import requests
def google_search(query, gl, hl):
return requests.get(
"https://www.google.com/search",
params={"q": query, "gl": gl, "hl": hl, "pws": 0, "num": 10},
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"Accept-Language": f"{hl};q=0.9",
},
)
us = google_search("best crm software", gl="us", hl="en")
uk = google_search("best crm software", gl="gb", hl="en")
Set Accept-Language to match hl. Google reads the header as a localization signal, and a request claiming hl=ja while the browser header says en-US looks inconsistent, both for accuracy and for bot detection.
One warning before you build on this: raw requests to google.com get CAPTCHA-challenged quickly at any real volume. The parameters above are the right way to express localization, but delivering the requests reliably is a separate problem. More on that below.
City-level targeting with uule
Country codes are too coarse for local SEO. "Dentist near me" in Manchester and London are different result sets, and gl=gb can't distinguish them.
That's what uule does. It encodes a canonical location name from Google's geotargets database (the same list Google Ads uses) into a token Google trusts as the searcher's location:
import urllib.parse
def build_uule(canonical_name):
key = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz0123456789-_")
return "w+CAIQICI" + key[len(canonical_name)] + \
urllib.parse.quote(canonical_name)
uule = build_uule("Manchester,England,United Kingdom")
# append &uule=... to the search URL alongside gl=gb
The magic character after the prefix encodes the length of the location string; the lookup table above handles names up to 63 characters. The canonical name must match Google's geotargets CSV exactly, comma-separated with no spaces after commas. "Manchester, UK" silently fails; "Manchester,England,United Kingdom" works.
In my experience uule is the single most underused parameter in local rank tracking. People pay for proxies in 40 cities when one parameter does the job.
What parameters can't fix
Three gotchas that bite everyone who builds this pipeline:
EU consent pages. Requests that look like they come from Europe often get bounced to consent.google.com before any results load. Your parser sees a cookie banner instead of a SERP. You can sometimes suppress this by sending a CONSENT cookie, but it's a moving target.
The local pack still trusts the IP. Organic results follow gl and uule faithfully. Map packs and some "near me" features weigh the requesting IP more heavily. If map pack positions are what you're tracking, parameters alone may not be enough, and that's the one case where location-based proxies still earn their cost.
Anti-bot pressure. This is the real production issue. Google aggressively challenges automated traffic, and the HTML changes often enough that a parser you wrote in March is broken by June. The localization logic is a morning's work. Keeping the pipeline alive is a job.
When to stop fighting Google directly
If you need localized SERPs at any scale, the sane architecture is: you own the localization decisions (query, country, language, city), and a search API owns the delivery and parsing. The link.sc Search API returns structured results as JSON or clean markdown from a single call, which means no CAPTCHA handling and no HTML parser to babysit, and the output drops straight into an LLM prompt or a database. The getting started guide covers the setup in about five minutes.
For the broader mechanics of extracting SERP features like featured snippets, see the ultimate guide to SERP scraping, and if question mining is your goal, extracting People Also Ask data pairs naturally with per-country queries, since PAA questions differ sharply between markets. If you're feeding results to an agent rather than a dashboard, real-time web search for LLMs covers that side.
The short version: express location with gl, hl, and uule instead of buying IP addresses, match the query language to the market, and let something else absorb the anti-bot arms race.
Need localized search results without babysitting proxies and parsers? Create a free link.sc account and get structured SERP data from one API call.