Most free IP geolocation APIs stop at city. If you build products for Chinese users — signup fraud checks, content localization, logistics routing, or just honest logging — city-level is often too coarse. Beijing alone is enormous, and a label that only says "Shanghai" does not tell you which district the address sits in.
IP99 returns district-level location for Chinese IPs, plus the six-digit GB/T 2260 admin_code, in the same free no-key call you already use for risk signals. One request, geo and risk together.
One curl, risk + geo together
curl https://ip99.com/v1/ip/36.112.24.1
A live response (re-fetched 2026-10-17, Asia/Shanghai) looks like this in spirit:
{
"ip": "36.112.24.1",
"evidence_state": "none",
"geo": {
"country": "CN",
"region": "Beijing",
"city": "Beijing",
"district": "Haidian",
"admin_code": "110108",
"subdivision": "CN-BJ",
"tz": "Asia/Shanghai"
},
"network": { "asn": 4847, "usage_type": "GTW" },
"risk": { "score": 0, "level": "none", "signals": [] }
}
Field notes that matter in production:
-
district: present for many Chinese addresses; absent outside China, and sometimes missing for coarse city-level ranges. -
admin_code: six-digit GB/T 2260 code (110108= Haidian District, Beijing). Useful when your CRM, compliance, or logistics tables already key off that national standard. -
subdivision: ISO 3166-2 when available (CN-BJ). -
Worldwide city still works for non-CN ranges (try
8.8.8.8→ Mountain View, California — nodistrict/admin_code).
To look up the caller's own egress, omit the IP:
curl https://ip99.com/v1/ip
A second live example: district + active risk
District alone is not a verdict. Pair it with the risk block in the same JSON. Here is another live call from the same day:
curl https://ip99.com/v1/ip/27.22.66.200
Shape (trimmed):
{
"ip": "27.22.66.200",
"evidence_state": "active",
"geo": {
"country": "CN",
"region": "Hubei",
"city": "Xiangyang",
"district": "Nanzhang",
"admin_code": "420624",
"subdivision": "CN-HB",
"tz": "Asia/Shanghai"
},
"network": { "asn": 4134, "usage_type": "DYN" },
"risk": {
"score": 61,
"level": "medium",
"signals": ["dialup_pool", "hijacked_proxy", "proxy"]
}
}
Same free endpoint: you get Hubei / Xiangyang / Nanzhang plus admin_code 420624, and you also see that this range currently carries dial-up-pool and proxy evidence. A score of 0 is not "safe" — it means no current verifiable evidence (evidence_state can be active, stale, or none). Do not build a hard allowlist on geo alone.
Not every Chinese address returns a district. Some resolve only to city with a city-level admin code. Example (live 2026-10-17): 114.114.114.114 → Nanjing, Jiangsu, admin_code 320100, no district field. Treat missing keys as "not in the database," not as zero.
Why district beats city for China-facing apps
City labels collapse districts that behave differently for fraud and ops:
- A shared hosting or gateway range in one district is not the same as a residential dial-up pool in another.
- Content, support, or courier routing often needs district, not just "Beijing".
- If you store only
city, you throw away a free signal that maps cleanly to national admin tables viaadmin_code.
Typical uses that benefit from the join:
- Signup and login enrichment: store
admin_codenext to the session so later reviews can filter by district without re-parsing free-text city names. - Soft localization: pick language, currency, or support queue by province/district — not by claiming "this person is standing at these coordinates."
- Incident review: when a chargeback or abuse ticket lands, district + ASN +
usage_typeis a better starting point than a bare city string.
Honest limits (so you do not over-trust geo)
IP geolocation describes a network range, not a person's phone GPS. Confidence falls as you go finer: country is usually strong; region is often good; city is statistical; district (China-only on IP99) is still an estimate for the range.
Common reasons a city or district looks "wrong":
- The traffic exited through a VPN or proxy (you see the exit, not the user).
- Mobile CGNAT shares one public address across a wide area.
- Enterprise, IDC, or CDN ranges sit where the provider parks gear, not where end users live.
- Registration data for a prefix can lag how the prefix is actually used.
A practical triage order: check proxy / VPN signals first, compare timezone, look at usage_type (for example MOB or GTW are already coarse by nature), then treat the geo as an estimate. Use city or district to choose language, currency, or jurisdiction — not to assert that a specific person is at a specific street.
IP99 does not advertise Tor detection. Do not expect a Tor signal in this response.
What the free API does not return
- ISP display names (the website lookup shows them; the API sticks to ASN +
usage_type). - A permanent "bad IP" label. Evidence ages out on purpose so yesterday's dial-up exit does not permanently brand tomorrow's home user.
- Guarantees that every Chinese range has a district. Some stop at city-level
admin_code.
Quotas without a key: 500 lookups/day per public egress IP. Free signed-in account: 5,000/day. Full field dictionary, errors, and OpenAPI: ip99.com/api (machine-readable at https://ip99.com/openapi.json).
Soft next steps
- English product home: ip99.com
- Geo ranges by country: ip99.com/en/geo/
- Agents: MCP tool
ip_risk_lookupathttps://ip99.com/mcp
One line to keep:
curl https://ip99.com/v1/ip/36.112.24.1
If you need China down to the district — and a GB/T code you can join on — you do not need a second vendor just for geo.
Top comments (0)