IP Intelligence¶
2 endpoints for resolving public IP addresses to geographic locations and detecting anonymisation infrastructure.
| Endpoint | Purpose |
|---|---|
GET /v1/geo/ip-lookup |
Resolve IP to city, region, country, coordinates, ASN |
GET /v1/geo/ip-threat |
Detect VPN, proxy, Tor, and datacenter IPs |
REST API Examples¶
Geolocate an IP address¶
curl "https://geo.toolkitapi.io/v1/geo/ip-lookup?ip=8.8.8.8" \
-H "X-API-Key: YOUR_KEY"
const params = new URLSearchParams({ ip: "8.8.8.8" });
const resp = await fetch(`https://geo.toolkitapi.io/v1/geo/ip-lookup?${params}`, {
headers: { "X-API-Key": "YOUR_KEY" },
});
const data = await resp.json();
console.log(`${data.city}, ${data.country} (${data.latitude}, ${data.longitude})`);
Response
{
"ip": "8.8.8.8",
"city": "Mountain View",
"region": "California",
"country": "United States",
"country_code": "US",
"latitude": 37.386,
"longitude": -122.0838,
"asn": 15169,
"asn_name": "GOOGLE",
"org": "Google LLC",
"query_time_ms": 34.2
}
Detect VPNs, proxies, and threats¶
curl "https://geo.toolkitapi.io/v1/geo/ip-threat?ip=198.51.100.42" \
-H "X-API-Key: YOUR_KEY"
const params = new URLSearchParams({ ip: "198.51.100.42" });
const resp = await fetch(`https://geo.toolkitapi.io/v1/geo/ip-threat?${params}`, {
headers: { "X-API-Key": "YOUR_KEY" },
});
const data = await resp.json();
console.log(`Threat: ${data.is_threat}, VPN: ${data.is_vpn}, Proxy: ${data.is_proxy}`);
Python SDK Examples¶
Geolocate an IP address¶
ip_lookup accepts any public IPv4 or IPv6 address and returns city-level location data plus ASN information.
from toolkitapi import Geo
with Geo(api_key="tk_...") as geo:
result = geo.ip_lookup("8.8.8.8")
print(result["city"]) # "Mountain View"
print(result["region"]) # "California"
print(result["country"]) # "United States"
print(result["country_code"]) # "US"
print(result["latitude"]) # 37.386
print(result["longitude"]) # -122.0838
print(result["asn"]) # "AS15169"
print(result["org"]) # "Google LLC"
Geolocate a user's IP in a web request¶
from toolkitapi import Geo
def enrich_request(remote_ip: str) -> dict:
"""Return geo data for an incoming request IP."""
with Geo(api_key="tk_...") as geo:
try:
return geo.ip_lookup(remote_ip)
except Exception:
return {}
# Flask / FastAPI example
# location = enrich_request(request.remote_addr)
Check if an IP is a VPN, proxy, or Tor node¶
ip_threat returns anonymisation indicators — useful for fraud detection, access control, or analytics filtering.
from toolkitapi import Geo
suspicious_ips = [
"185.220.101.5", # Known Tor exit node
"104.16.100.1", # Cloudflare CDN
"8.8.8.8", # Google DNS
]
with Geo(api_key="tk_...") as geo:
for ip in suspicious_ips:
threat = geo.ip_threat(ip)
print(f"{ip}:")
print(f" VPN: {threat['is_vpn']}")
print(f" Proxy: {threat['is_proxy']}")
print(f" Tor: {threat['is_tor']}")
print(f" Datacenter: {threat['is_datacenter']}")
print(f" Threat score: {threat.get('threat_score', 'n/a')}")
Combine geolocation and threat data¶
from toolkitapi import Geo
def analyze_ip(ip: str) -> dict:
"""Return full IP intelligence: location + threat indicators."""
with Geo(api_key="tk_...") as geo:
location = geo.ip_lookup(ip)
threat = geo.ip_threat(ip)
return {
"ip": ip,
"city": location.get("city"),
"country": location.get("country_code"),
"org": location.get("org"),
"is_vpn": threat.get("is_vpn"),
"is_tor": threat.get("is_tor"),
"is_datacenter": threat.get("is_datacenter"),
}
result = analyze_ip("1.2.3.4")
if result["is_vpn"] or result["is_tor"]:
print("Anonymised traffic — proceed with caution")
Batch-process a list of IPs¶
from toolkitapi import Geo
access_log_ips = [
"8.8.8.8",
"1.1.1.1",
"185.220.101.5",
"91.108.4.1",
]
results = []
with Geo(api_key="tk_...") as geo:
for ip in access_log_ips:
try:
loc = geo.ip_lookup(ip)
threat = geo.ip_threat(ip)
results.append({
"ip": ip,
"country": loc.get("country_code"),
"city": loc.get("city"),
"flagged": threat.get("is_vpn") or threat.get("is_tor"),
})
except Exception as exc:
results.append({"ip": ip, "error": str(exc)})
for r in results:
flag = " [FLAGGED]" if r.get("flagged") else ""
print(f"{r['ip']} → {r.get('city')}, {r.get('country')}{flag}")
Response Fields¶
ip-lookup response:
| Field | Type | Description |
|---|---|---|
ip |
string | Normalised IP address |
city |
string | City name |
region |
string | State or province |
country |
string | Full country name |
country_code |
string | ISO 3166-1 alpha-2 code |
latitude |
float | Latitude |
longitude |
float | Longitude |
asn |
string | Autonomous System Number (e.g. AS15169) |
org |
string | Organisation name |
ip-threat response:
| Field | Type | Description |
|---|---|---|
ip |
string | Checked IP |
is_vpn |
bool | Known VPN exit node |
is_proxy |
bool | Open or commercial proxy |
is_tor |
bool | Tor exit node |
is_datacenter |
bool | Datacenter / hosting provider ASN |
Tip
Private (192.168.x.x, 10.x.x.x), loopback (127.x.x.x), and reserved address ranges return a 400 error. Only publicly routable IPs can be geolocated. In development, use a real public IP like 8.8.8.8 for testing.