Geo targeting with proxies: what actually decides the country you see
I once collected six days of price data through a correctly located address and got back a currency I never asked for. The addresses were right the whole time. The scraper was sending a language preference it inherited from the container image, and the target weighted that above the lookup.
Nothing in the logs said anything was wrong. Every request returned 200, every page parsed, every row landed in the table. The prices were just from a different country’s storefront.
That is the shape of almost every geo problem I get asked about. The address does what it was sold to do. Something else in the request quietly outvotes it.
The five inputs, in the order they usually win
When a page decides which country version to serve you, it has these to work with:
- The language preference your client sends on every request.
- Whatever it stored about you last time, in a cookie, a session, or a hostname it redirected you to.
- The country attached to the account you are logged into.
- A locale, currency or store parameter sitting in the URL you requested.
- The address the request arrived from.
Buying a proxy in a country buys you number five. Four of those five are decisions in your own code, and the fault in a broken geo setup is almost always in one of them.
I sell lines in one country and buy addresses in several others for my own checking, so I get this complaint from customers and I also generate it myself about once a quarter.
Why the language header usually wins
Content negotiation predates geolocation databases by years. A client says which languages it reads and in what order, the server picks the best match it has. Plenty of sites still treat that as the most trustworthy signal available, on the reasonable grounds that it came from the user instead of being guessed about them.
The catch is that nobody sets it deliberately. Browsers fill it from the operating system. HTTP libraries ship a default that a maintainer chose once. Headless browsers inherit the box they run on. Docker images inherit whatever the base layer had.
So a scraper on a server in one country, routed through an address in a second, announcing a language from a third, hands the site three answers and lets it choose. In my experience it picks the header.
There is a second trap in the same field. The value is a weighted list, not a single token. People set the entry they want and leave the old default sitting behind it at a lower weight, which a site parsing the whole list can still see and act on.
Print the headers your client actually puts on the wire before you spend anything on addresses. Not the ones in your config. The ones in a packet capture or an echo endpoint.
Sticky state, and the redirect that traps you
A lot of sites answer the country question once and then stop asking. The answer lives in a cookie, or on the session, or in the fact that request one bounced you to a country-specific hostname that now sets its own state.
That is why an identical request succeeds from a clean profile and fails from the one you have been running all week. The clean profile gets classified. The old one gets served whatever it was told in March.
Give every geo its own profile or its own jar, and never let them touch. And watch the first redirect specifically, because once you are pointed at a country-specific hostname, no address is going to drag you back off it.
Logged in means the account decides
An account carries its own country: a billing address, a region picked at signup, a store preference in settings.
That value beats the header and it beats the address, because it is something the site knows rather than infers. People run into this hardest on marketplaces and subscription services, buy an address in a country, log into an account created elsewhere, and get the account’s country back. The site is behaving exactly as designed.
If your job needs a logged-in session showing another country, the account has to move. On most platforms that is a support ticket rather than a setting, and on a few it is not possible at all.
The lookup underneath all of it
Here is the part that surprises people: the site is not reading your address. An address carries no location. There is no country field in it.
What happens is a database lookup. The address goes into a commercial geolocation dataset and comes back with a country, a region, sometimes a city, and a confidence value nobody reads. Those datasets are assembled from registration records that network operators file, routing announcements, latency measurements, and whatever else the vendor can buy or infer.
Country-level accuracy is good, up in the high ninety percents on ordinary connections. City-level is a different animal, and the vendors publish their own city figures, which sit well below what the marketing around city targeting implies.
They also refresh on independent schedules. A vendor updates its data on one cadence, a site updates its copy of that data on another, and a correction filed by an operator has to cross both before it reaches the page you are testing. The same address can read two ways depending on who is asking and when they last pulled.
Mobile addresses and the national gateway
Mobile is the worst case, and it is worth knowing why before you blame the seller.
A carrier does not give every phone a public address. Hundreds or thousands of subscribers sit behind one, through carrier grade NAT, and that shared address gets registered wherever the carrier declares its gateway. Frequently that gateway is national rather than local.
So a line physically sitting on a shelf in one city can be looked up as a city hundreds of kilometres away, and both statements are true at once. I have had one batch of lines read correctly by one database and wrongly by another on the same afternoon. Same SIMs, same carrier, same shelf.
No provider controls that. I cannot call a database vendor and have them move my hardware. The operator files what it files, the vendors ingest on their own schedule, and everyone downstream inherits it. When a seller quotes you a city, they are quoting what a database said the last time they looked.
The address type barely changes any of this. A residential exit and a mobile exit go into the same datasets with the same failure modes, so choose your type for other reasons.
Check the page, never a checker
An IP checker queries a database, and there is no guarantee it is the database your target queries. A green tick from one vendor while your target disagrees sends you off debugging something that was never broken.
Read the target instead. Pick a field that only changes when the site believes you are somewhere specific:
- the currency symbol or code on a price
- one fixed string of body copy, and what language it came back in
- the shipping or delivery estimate
- the value preselected in a country or store switcher
- the tax line, where there is one
Then assert on it inside the scraper, next to the parse. If the currency is not the one I asked for, my run stops there. The alternative is six days of data in the wrong denomination, which is where this article started.
Country is a claim, city is a rumour
I do not sell city-level targeting. When someone asks for a specific city I tell them what the lookups currently say about the lines I have, and I put none of it in writing, because I cannot promise a dataset will still say that next month.
City-level geo targeting as a product category is mostly marketing, sold on a number the seller does not control and cannot repair when it drifts. Buy at country level. If the work genuinely needs a city, buy a handful, look them up, keep the ones that read right, and expect some of them to wander.
What I got wrong
I spent two days and bought four extra lines in a country chasing a customer’s geo complaint. The fix was one header on his machine. I had already invoiced for the lines, refunded it, and ate a day plus four lines I did not need.
I also used to repeat city claims off supplier sheets without testing them. A customer asked me to confirm a city on a line, I checked it in three places, and got two different answers. I stopped quoting cities that week.
What I can’t tell you
I do not know which dataset any particular site uses. Some run their own. Some license a vendor feed. Some combine several, or use a first-party signal I cannot see from the outside. I infer from how pages come back, and I am wrong often enough to say so.
I also cannot promise that a line reading as a given city today reads as that city in six weeks. Nobody selling you an address can promise that either, whatever the product page says.
The header values I set, and the currency assertion I run inside every geo job, are here.
Get new guides and videos first — join the Telegram channel.