DEV Community

RoamProxy
RoamProxy

Posted on

One mobile IP, two cities: how to check where a proxy exit really is

If you target proxies by city, you will eventually look up an exit IP and get two different answers.

Here is one we saw this week. Same IP, same carrier (T-Mobile USA, AS21928), checked a few minutes apart:

  • ipinfo: Fort Worth, Texas
  • ip-api: Chicago, Illinois

That is not a typo in either database. Mobile carrier IPs are hard to place. Traffic from many phones leaves through a small number of carrier gateways, and the address pool behind those gateways gets reassigned across regions. Each database makes its own guess from its own signals, so they often land on different cities. Fixed broadband IPs (cable, fiber, DSL) usually agree much more closely.

ipinfo and ip-api results for the same T-Mobile IP, last octet masked

What to check instead of one lookup

  1. Ask two databases, not one. If both name the same city, you can trust it. If they disagree, you know the city is uncertain, which is still useful to know.
  2. Look at the ASN and the mobile flag. If the ASN is a mobile carrier, or the lookup says mobile: true, treat the city as approximate and plan for region-level accuracy.
  3. Check the exit, not the label. Whatever your proxy username asks for, verify the IP you actually got from the place you will use it.

A small script

import json, sys, urllib.request

def get(url):
    with urllib.request.urlopen(url, timeout=10) as r:
        return json.load(r)

def check(ip):
    a = get(f"http://ip-api.com/json/{ip}?fields=countryCode,regionName,city,isp,as,mobile,proxy,hosting")
    b = get(f"https://ipinfo.io/{ip}/json")
    same_city = (a.get("city") or "").lower() == (b.get("city") or "").lower()
    print(f"ip-api : {a.get('city')}, {a.get('regionName')} ({a.get('as')}) mobile={a.get('mobile')}")
    print(f"ipinfo : {b.get('city')}, {b.get('region')} ({b.get('org')})")
    print("city agrees" if same_city else "city DISAGREES: treat it as region-level only")

if __name__ == "__main__":
    # Pass an IP, or leave it empty to check the exit you are using right now
    ip = sys.argv[1] if len(sys.argv) > 1 else get("https://api.ipify.org?format=json")["ip"]
    check(ip)
Enter fullscreen mode Exit fullscreen mode

Run it through your proxy (for example with HTTPS_PROXY set) and it checks the exit you are actually using. Both services have free tiers with rate limits, which is fine for spot checks but not for every request.

Takeaway

City targeting is a request, not a guarantee, and the answer depends on whose database you ask. For mobile IPs, check two sources and trust the region more than the city.

Written by the team at Roam (roamproxy.com), where we run residential and static proxies and check exits this way ourselves.

Top comments (0)