IP Lookup
/api/ip-lookup?ip={address}
No Auth RequiredThe /api/me endpoint tells you about yourself. This one tells you about anyone else. Pass any public IPv4 or IPv6 address and get back the same rich geolocation data: country, city, ISP, proxy detection, the works.
Need to check where a suspicious login came from? Want to verify a user’s claimed location? Curious about that weird IP in your server logs? This is your endpoint.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ip | string | Yes | IPv4 or IPv6 address to look up. Examples: 8.8.8.8, 2001:4860:4860::8888 |
Response Fields
| Field | Type | Description |
|---|---|---|
ip | string | The IP address you looked up (echoed back) |
country | string | Full country name |
countryCode | string | ISO 3166-1 alpha-2 code |
region | string | State or province name |
regionCode | string | Region abbreviation |
city | string | City name |
zip | string | Postal or ZIP code |
lat | number | Latitude |
lon | number | Longitude |
timezone | string | IANA timezone identifier |
isp | string | Internet Service Provider |
org | string | Organization name |
as | string | Autonomous System number and name |
asName | string | AS name only |
rdns | string | Reverse DNS hostname |
mobile | boolean | Mobile/cellular connection detected |
proxy | boolean | VPN or proxy detected |
hosting | boolean | Hosting/datacenter IP detected |
Example Request
curl
curl "https://whatismyip.technology/api/ip-lookup?ip=8.8.8.8"
Python
import requests
ip_to_check = "8.8.8.8"
response = requests.get(
"https://whatismyip.technology/api/ip-lookup",
params={"ip": ip_to_check}
)
data = response.json()
print(f"IP: {data['ip']}")
print(f"Location: {data['city']}, {data['country']}")
print(f"ISP: {data['isp']}")
print(f"Hosting: {data['hosting']}")
JavaScript
const ip = "8.8.8.8";
const response = await fetch(
`https://whatismyip.technology/api/ip-lookup?ip=${ip}`
);
const data = await response.json();
console.log(`IP: ${data.ip}`);
console.log(`Location: ${data.city}, ${data.country}`);
console.log(`ISP: ${data.isp}`);
console.log(`Hosting: ${data.hosting}`);
Example Response
{
"ip": "8.8.8.8",
"country": "United States",
"countryCode": "US",
"region": "California",
"regionCode": "CA",
"city": "Mountain View",
"zip": "94043",
"lat": 37.4056,
"lon": -122.0775,
"timezone": "America/Los_Angeles",
"isp": "Google LLC",
"org": "Google Public DNS",
"as": "AS15169 Google LLC",
"asName": "GOOGLE",
"rdns": "dns.google",
"mobile": false,
"proxy": false,
"hosting": true
}
Errors
| Status | Condition | Response Body |
|---|---|---|
400 | Missing ip parameter | {"error": "ip parameter is required"} |
400 | Invalid IP format | {"error": "Invalid IP address"} |
500 | Upstream lookup service failed | {"error": "Lookup failed"} |
The 500 error is rare but possible. The upstream geo provider might be down, overloaded, or returning garbage. If you get a 500, wait a few seconds and try again. If it keeps happening, the upstream is having a bad day. Not much you can do.
Runtime and Caching
Runs on the Edge runtime. The response is cached for 5 minutes. If you look up the same IP twice within 5 minutes, you’ll get the cached version. This is fine. IP geolocation data doesn’t change every second. It barely changes every month.
The 5-minute cache also protects the upstream provider from getting hammered. If your app does a lot of lookups, you might want to add your own cache layer on top. A simple in-memory cache or Redis setup will save you a ton of redundant requests.
Timeout
The upstream lookup has an 8-second timeout. If the geo provider doesn’t respond in 8 seconds, you’ll get a 500 error. In practice, responses come back in under 200ms. The timeout is a safety net, not something you should worry about.
Notes and Edge Cases
Private IPs don’t work. If you pass 192.168.1.1, 10.0.0.5, or 127.0.0.1, you’ll get a valid response but the geo data will be empty or nonsensical. These addresses aren’t routable on the public internet, so there’s nothing to look up.
Bogon addresses (like 0.0.0.0 or reserved ranges) will technically pass validation but return useless results. Don’t bother.
The difference between this and /api/me: The /api/me endpoint looks up the requester’s own IP. This endpoint looks up whatever IP you give it. If you call /api/ip-lookup?ip=YOUR_OWN_IP, you’ll get the same result as /api/me. But if you’re building a tool that checks other people’s IPs, this is the one you want.
Bulk lookups. There’s no batch endpoint. If you need to look up 1,000 IPs, you’ll need to make 1,000 requests. Be nice about it. Space them out. The 5-minute cache helps if you have duplicates.
IPv6 works. Pass the full address or the shortened form. Both 2001:4860:4860:0000:0000:0000:0000:8888 and 2001:4860:4860::8888 are accepted.
URL encoding. IPv6 addresses with colons don’t need special encoding in query parameters. Browsers and HTTP libraries handle this automatically. But if you’re constructing URLs by hand, keep it in mind.