
You set country-us, ran the collection, and every request came back 200. Nothing errored, nothing retried, no CAPTCHA. The dataset still describes a market nobody sells into.
That is the quiet failure of country-level targeting, and it is worse than a block. A block is loud — you see the 403, you fix it. Wrong-granularity data is silent: the page renders, the price parses, the row lands in the warehouse, and the dashboard on top of it looks perfectly healthy. You find out months later, when somebody who actually lives in the market says that has never been the price here.
The country is not the unit the web varies on
For a lot of pages it is. Product documentation, a public filing, a global catalog page — those look the same from Seattle and Miami, and country targeting is exactly right. But an entire class of pages resolves against something much finer than the country: the metro, the postal area, sometimes the network itself.
- Local search. The map pack, the near me results, and the ordering of local listings are computed from an approximate location, not a country. Two US exits two thousand miles apart return genuinely different SERPs for the same query — different businesses, different order, different pack size. This is why localized rank tracking is a sampling problem before it is a parsing problem.
- Store-level retail. Big-box retailers price and stock per store, and resolve your store from your location. A national average is a fiction the site never actually showed anyone, which is the whole difficulty in monitoring big-box retail prices.
- Regional ad delivery. Campaigns are bought by media market, region, or postal code. Verifying a campaign that ran in Chicago from a New York exit tells you nothing about whether it ran.
- Shipping, tax, and availability. Estimated delivery dates, sales tax, and unavailable in your area all key off something finer than the country.
- State and provincial rules. Some categories are gated below the national level, so one site legitimately serves different pages inside a single country.
- The ISP itself. Broadband and mobile offers are priced per carrier and per footprint, and CDNs choose an edge by network path — so a page can differ between two households on the same street with different providers.
The through-line: none of these fail loudly when the location is wrong. They serve a perfectly valid page for the location you actually came from.

When country-level is genuinely enough
Most collection does not need city targeting, and buying granularity you cannot use is a bad trade. Every constraint you add narrows the set of exits you can draw from, which costs you availability and usually latency, for no gain.
Stay at country level when the page does not vary sub-nationally: catalogs and product pages with national pricing, documentation, registries and filings, most non-local search queries, general web content. Reach for city or ISP only when you can name the mechanism that varies — the map pack, the store, the campaign, the carrier offer, the CDN edge. If you cannot name it, you do not need it.

How targeting works
Everything is a suffix on the proxy username, so it works with any HTTP client that supports proxy auth. No SDK required, no special endpoint.
# country only (Premium or Elite)
aethyn-d9e2c-country-us
# city (Elite)
aethyn-d9e2c-country-us-city-chicago
# ISP (Elite)
aethyn-d9e2c-country-us-isp-comcast
Suffix order is base · country · city · isp · session · lifetime. City and ISP targeting are Elite features; Premium routes by country. The full reference is in the targeting docs, and the SDK also accepts state and zip on Elite if you would rather build the string with a typed API than assemble it by hand.
The rule that makes any of this trustworthy: verify, don't assume
City and ISP suffixes resolve to the closest available match, and when nothing matches they fall back to the country. That default is the right one — a run that degrades beats a run that dies — but it has a consequence you have to design around: asking for a city is not the same as getting it.
So make the check part of the pipeline, not something you do once during setup:
p = client.session(country="us", city="chicago", session="run1", ttl=30, tier="elite")
geo = requests.get("https://ipinfo.io/json", proxies=p.proxies, timeout=15).json()
if geo.get("city", "").lower() != "chicago":
# fell back to country — rotate the session id and re-check, or keep the
# row but label it country-level. Never label it Chicago.
...
The discipline fits in one sentence: a datapoint is only as good as the vantage point you can prove it came from. Record what you got, not what you asked for. A row that honestly says resolved_city: fallback-country is worth more than a confident one that says chicago and isn't.

Pin the location to a session, not to a request
Once you are working at metro level you almost always want a multi-step flow — set the store, open the listing, read the price — to come from one address. That is what sticky sessions are for: reuse the same session id and every request rides the same exit for the lifetime window.
aethyn-d9e2c-country-us-city-chicago-session-chi01-lifetime-30
Lifetime is in minutes (1–1440, default 30). Size it to the flow rather than to the job. If store selection takes four minutes, a 30-minute window is plenty; if you are paging a catalog for an hour, either extend it or accept that the identity will roll and make the parser notice. A flow that silently changes IP halfway through a location-dependent journey produces exactly the plausible-but-wrong row this whole post is about. If you are new to the trade-off, rotating vs static sessions covers the general case.

Design the sample matrix before you scale it
Granularity multiplies the job, and the multiplier is real money — residential traffic bills per gigabyte, and our pricing is published so you can do that arithmetic before you run it, not after.
Three decisions worth making up front:
- Pick markets for a reason. Cities where you actually sell, where a competitor just opened, where a campaign is live. A grid of the 50 largest metros is usually 45 metros of noise and 45 metros of bandwidth.
- Sample each market more than once. Local results move. One reading per city per week tells you almost nothing about variance; three tell you whether a change is a change.
- Store the vantage point in the same row as the value.
price,currency,requested_city,resolved_city,resolved_isp,exit_ip,collected_at. Without those columns you cannot re-audit a suspicious number later — and you will have suspicious numbers.
The code
Python, using the SDK so you are not hand-assembling usernames:
from proxy_builder_sdk import AethynClient
import requests
client = AethynClient() # reads AETHYN_USERNAME / AETHYN_PASSWORD
for city in ("chicago", "houston", "phoenix"):
p = client.session(country="us", city=city, session=f"local-{city}",
ttl=15, tier="elite")
geo = requests.get("https://ipinfo.io/json",
proxies=p.proxies, timeout=15).json()
print(city, "->", geo.get("city"), geo.get("org"))
# only now collect — and write geo into the row next to the value
Node:
import { AethynClient } from "proxy-builder-sdk";
import got from "got";
const client = new AethynClient();
for (const city of ["chicago", "houston", "phoenix"]) {
const p = client.session({ country: "us", city, session: `local-${city}`, ttl: 15, tier: "elite" });
const geo = await got("https://ipinfo.io/json", { proxy: p.url }).json();
console.log(city, "->", geo.city, geo.org);
}
String(p) is safe to log — the password is redacted. The SDK reference has the Playwright and Selenium variants if your collection runs in a real browser, which for local search it usually should.
ISP targeting is the narrower tool
City answers where. ISP answers through whom. Reach for it when the network is the variable: verifying a carrier's own broadband or mobile pricing, checking how a page resolves across different CDN edges, or reproducing a bug that only appears for users on one network. For ordinary local-market collection, city is the lever and ISP is an extra constraint that mostly shrinks the pool you draw from. The same verification rule applies — read back the org field and record what you actually got, not what you requested.
The guardrails
None of this changes what is fair to collect. Public data, robots.txt respected, rate limits respected, terms read. A residential exit in the right city is a way to see what a real visitor in that city sees — it is not a licence to hit a site harder than a real visitor would, and it is not a route around a login or a wall somebody put up on purpose. Aethyn sources its IPs from consented, KYC-verified peers, and the point of that chain is that it stays defensible from origin to exit. Localization testing and local business data are the two use cases where this discipline pays off fastest.
Where to start
Run one city against one country-level control and compare the rows. If they match, you have your answer: stay on country targeting and spend the money on volume instead. If they don't, you have just measured how much of your existing dataset describes a place your customers do not live.
Targeting reference · Elite residential · Locations · SDK · Free trial, no card
Common questions about this article
What is city-level residential proxy targeting?
Do I need Elite for city and ISP targeting?
What happens if no exit is available in the city I asked for?
Is ISP targeting the same as city targeting?
Does city-level targeting cost more or run slower?
Guides, integrations & docs
Continue reading

Rotating vs Static Residential Proxies: How to Choose
Rotating residential proxies give you a new household IP per request. Sticky holds that IP for 1–1440 minutes (default 30) on the same rotating pool — not a static ISP product.

Scrape Any Site in 20 Lines with Residential Proxies (Node.js & Python)
A no-fluff quickstart for the Aethyn SDK: install, authenticate, target a country, hold a sticky session, and drive Playwright — with real, copy-paste code for Node and Python.

City SERP Divergence: A Re-Runnable Protocol (2026)
City SERP divergence is the measurable difference in local results for the same query when the exit metro changes. This page publishes the protocol, a 16-query basket, and the column schema — not invented overlap percentages.
Target the metro, not just the country
Elite adds city and ISP targeting on top of 195+ countries, with sticky sessions so a multi-step local flow keeps one address. Published per-GB pricing, free trial, no card.