Reading IP Location From an API Response vs Where the Modem Is
Published
A line in Chicago returns an address whose geolocation lookup says Chicago. Usually. Sometimes it says Milwaukee, or a hub city in the region, while the modem has not moved an inch. Developers who assert city equality in a test see it flap and file a bug. This page explains where the city in an IP geolocation response comes from, why it diverges from the physical device by carrier, and what a script should check so the assertion is both meaningful and stable.
Two different facts
The modem's location is a physical fact: a device in a rack in one of eight US metros, with a SIM registered on a cell tower in that metro. The IP's location is a database opinion: a vendor's best guess at where the traffic from that address appears to originate, built from carrier registrations, latency measurements and user reports. The two agree when the carrier's gateway for the address is near the tower. They disagree when it is not.
Neither is wrong. A geolocation API answers the question where does traffic from this address usually come from. It does not and cannot answer where the specific handset or modem behind a shared NAT address is right now.
How carrier gateways move the dot
Mobile traffic leaves the radio network through a packet gateway and gets its public address there. Carriers place gateways regionally. T-Mobile's layout puts the public address close to the metro, so lookups show the city itself most consistently. Verizon routes through a smaller number of regional hubs, so an address used in one city can be listed under a hub a few hundred miles away within the same region. AT&T is mostly metro-accurate with known exceptions.
The known exception that catches everyone: Boston. Verizon lines in Boston geolocate as Boston. AT&T lines in Boston geolocate as New York, because AT&T's New England traffic exits through its New York gateway. Same rack, two carriers, two cities in the response.
How databases lag and disagree
Vendors update at different cadences and from different evidence. After a carrier re-plans its address blocks, one database may move a /24 to the new city within days while another keeps the old entry for months. The same address queried against two services can return two cities. Both responses are honest reports of stale or fresh data.
Granularity also differs. Many vendors return a city for mobile ranges with low confidence and a region or state with high confidence. The confidence field, when present, is more useful than the city string.
What a script should assert
Assert what is reliable: country equals US, region equals the state the line is in, connection type is mobile or cellular, and the ASN is the carrier you bought (AS20057 AT&T, AS21928 T-Mobile, AS22394 or AS6167 Verizon). Treat the city as informational. If the job genuinely requires a metro-level match, buy T-Mobile for that line, and even then log rather than fail on a city mismatch.
The Mobile Proxies US API helps here. city in GET /proxies/my is the location as sold, such as 5G Houston. sim_location says where the address shows right now, by the SIM behind it. GET /proxies/UUID/ip-history carries new_ip_geo for each change, one entry per database (ipinfo, maxmind, dbip), with city, region and country, so you can see the disagreement directly. A new block can read null for up to a day.
import os, requests
BASE = "https://cp.mobileproxiesus.com/backend/api_v1"
H = {"x-api-key": os.environ["MPUS_API_KEY"]}
line = next(l for l in requests.get(f"{BASE}/proxies/my", headers=H, timeout=15).json()["proxyList"]
if l["uuid"] == UUID)
ip = requests.get(f"{BASE}/proxy/status", params={"license": UUID}, timeout=15).json()["ip"]
geo = requests.get(f"https://geo.example/json/{ip}", timeout=10).json() # placeholder; your vendor
assert geo["country"] == "US"
assert geo["region"] == STATE_FOR_LINE[line["uuid"]]
assert geo.get("connection_type", "").lower() in ("mobile", "cellular")
assert geo["asn"] in CARRIER_ASNS[line["carrier"]]
hist = requests.get(f"{BASE}/proxies/{UUID}/ip-history", headers=H, timeout=15).json()["histories"]
latest = max((h for h in hist if h["status"] == "success"), key=lambda h: h["created_at"])
for db, g in latest["new_ip_geo"].items():
if g:
log.info(f"{db}: {g['city']}, {g['region']} (sold as {line['city']})")
What destinations see
Websites use the same databases, so whatever your vendor says is roughly what the destination infers. If a site shows a Miami line as Florida and the city as Orlando, it will still serve Florida content and treat the visitor as a Florida mobile user. State-level and country-level behaviour is what most geo features key on; city-level is rare outside local news, weather and store finders.
For a city-sensitive test, confirm the site's own view: load its location indicator through the line and record it alongside the vendor city. Three columns in the log, modem metro, vendor city, site city, settle most disputes.
When a mismatch is actionable
Wrong country: never acceptable; contact [email protected] with the licence uuid and the lookup. Wrong state: on Verizon, possible within the region; rotate and check again, and if the job needs the state exactly, move the line to a metro where that carrier reads correctly or switch carrier. Wrong city, right state: expected behaviour on Verizon and on AT&T in Boston; not a fault.
A free move between metros keeps the remaining time, so trying another metro costs nothing but a minute. The host and ports can change on a move, so re-read GET /proxies/my afterwards; the vendor lookup can be re-run in the same script.
Frequently asked
My Houston line geolocates to Dallas. Is it broken?
Probably not. On Verizon especially, a regional hub can appear as the city. State is Texas either way. Rotate and re-check, or use T-Mobile for a metro-accurate city.
Why does an AT&T line in Boston show New York?
AT&T's New England traffic exits through its New York gateway and databases list the address there. Verizon in Boston reads as Boston.
Which field should a test assert on?
Country, state, connection type and ASN. Log the city; do not fail on it unless the line is T-Mobile and the job truly needs a metro match.
Do destinations see the same city my lookup shows?
Roughly. They use the same kinds of databases. Check the site's own location indicator through the line when city matters.
