Quick Start
Every lookup is a single HTTP GET request. No SDK install, no OAuth handshake, no request signing — just a token and, optionally, an IP. The example below is real: it's the exact shape of data you'll get back for 8.8.8.8.
{
"ip": "8.8.8.8",
"hostname": "dns.google",
"country_code2": "US",
"country_code3": "USA",
"country_name": "United States",
"country_capital": "Washington",
"state_prov": "California",
"city": "Mountain View",
"zipcode": "94043",
"latitude": "37.4056",
"longitude": "-122.0775",
"is_eu": false,
"country_emoji": "🇺🇸",
"calling_code": "+1",
"country_tld": ".us",
"languages": "en",
"currency": {
"code": "USD",
"name": "Dollar",
"symbol": "$"
},
"time_zone": {
"name": "America/New_York",
"offset": -4,
"offset_with_dst": -3,
"current_time": "2026-08-21 03:12:46.964685-0400",
"current_time_unix": 1787296366.9647,
"current_tz_abbreviation": "EDT",
"current_tz_full_name": "America/New_York",
"is_dst": true
},
"asn": {
"asn": "AS15169",
"name": "Google LLC",
"domain": "google.com",
"route": "8.8.8.0/24",
"type": "hosting"
},
"company": {
"name": "AS15169 Google LLC",
"domain": "google.com",
"type": "isp"
},
"security": {
"is_tor": false,
"is_vpn": false,
"is_icloud_relay": false,
"is_proxy": false,
"is_datacenter": true,
"is_anonymous": false,
"is_known_attacker": false,
"is_known_abuser": false,
"is_threat": false,
"is_bogon": false,
"blocklists": [],
"scores": {
"vpn_score": 100,
"proxy_score": 1,
"threat_score": 100,
"trust_score": 33
}
}
}
Security and ASN Company Data fields availability depends on the subscription plan, starting from Pro Monthly plan.
See pricing for more details.
Try It Live
This calls the real IPFly API from your browser and renders the actual response — not a mock. Nothing is stored or logged by this page.
Enter your token above and click "Send request" to see a live response here.
Authentication
All requests require your API token as a query parameter. You can query your own IP by omitting the ip parameter.
Detect your own IP automatically:
Look up a specific IP address:
Get your API token by signing up for a free account.
Never call the IPFly API directly from client-side JavaScript, a mobile app bundle, or any code a user can inspect. Your token will be visible in network requests and can be extracted and abused by anyone viewing your page source. Always proxy requests through your own backend.
Making Requests
All requests are simple HTTP GET calls. No special headers required.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
token | string | Yes | Your API authentication token |
ip | string | No | IP address to lookup (IPv4 or IPv6). Omit to detect caller's IP. |
A note on IPv6
IPv6 addresses are fully supported and returned in the same response shape as IPv4 — pass them exactly as written (e.g. 2001:4860:4860::8888), no encoding needed. If a large share of your traffic is still IPv4-mapped through NAT64 or a CDN, expect the resolved location to reflect the edge or gateway, not the end user.
Sandbox & Test IPs
A handful of well-known, stable IPs are useful for integration tests and demos because their location and network ownership rarely change.
| IP | Good for testing | Typical result |
|---|---|---|
8.8.8.8 | Standard US result, hosting-type ASN | 🇺🇸Mountain View, CA — Google LLC |
1.1.1.1 | Anycast edge network, non-US | 🇦🇺Sydney/Anycast — Cloudflare |
9.9.9.9 | Privacy-focused resolver, EU-adjacent | 🇨🇭Quad9 Foundation |
2001:4860:4860::8888 | IPv6 code path | Same fields as IPv4, Google IPv6 DNS |
127.0.0.1 / 10.0.0.0/8 | Negative test — private/reserved ranges | Returns an error; these are never publicly routable |
A common first bug: testing from localhost during development. Your server's outbound IP (not 127.0.0.1) is what gets geolocated — if you're behind a home router or corporate NAT, expect an approximate result centered on your ISP, not your exact address. This is expected behavior for every IP geolocation provider, not an IPFly-specific limitation.
Standalone Fields
Root-level fields returned for every lookup.
| Field | Type | Description | Status |
|---|---|---|---|
ip | string | The queried IP address. | Required |
hostname | string | Reverse DNS hostname of the IP. | Required |
country_code2 | string | ISO 3166-1 alpha-2 country code. | Required |
country_code3 | string | ISO 3166-1 alpha-3 country code. | Required |
country_name | string | Common name of the country. | Required |
country_capital | string | Capital city of the country. | Required |
country_emoji | string | Country flag emoji. | Required |
calling_code | string | International dialing code. | Required |
country_tld | string | Country code top-level domain (e.g. .ua). | Required |
languages | string | Official languages of the country. | Required |
is_eu | boolean | Whether the country is an EU member. | Required |
Location Object
Detailed geographic data for the IP address.
| Field | Type | Description | Status |
|---|---|---|---|
state_prov | string | State / province / region name. | Optional |
state_code | string | State/province code. | Optional |
district | string | District or sub-region. | Optional |
city | string | City name. | Optional |
zipcode | string | ZIP / postal code. | Optional |
latitude | string | Latitude coordinate. | Required |
longitude | string | Longitude coordinate. | Required |
ASN Object
Autonomous System Number information.
| Field | Type | Description |
|---|---|---|
asn.asn | string | AS number (e.g. AS15169). |
asn.name | string | Organization name. |
asn.domain | string | Organization's domain. |
asn.route | string | IP route/prefix (CIDR notation). |
asn.type | string | Network type: isp, hosting, business, education. |
Timezone Object
Current time and timezone data for the IP's location.
| Field | Type | Description |
|---|---|---|
time_zone.name | string | IANA timezone name (e.g. Europe/Paris). |
time_zone.offset | number | UTC offset in hours (without DST). |
time_zone.offset_with_dst | number | UTC offset including DST. |
time_zone.current_time | string | Current local time string. |
time_zone.current_time_unix | number | Current time as Unix timestamp. |
time_zone.current_tz_abbreviation | string | Timezone abbreviation (e.g. EEST). |
time_zone.is_dst | boolean | Whether DST is currently active. |
Security Object
Threat intelligence and anonymization detection flags.
| Field | Type | Description |
|---|---|---|
security.is_tor | boolean | Whether the IP is a Tor exit node. |
security.is_vpn | boolean | Whether the IP is a used for VPN. |
security.is_icloud_relay | boolean | Whether the IP is a iCloud Apple proxy. |
security.is_proxy | boolean | Whether the IP is a known proxy. |
security.is_datacenter | boolean | Whether the IP belongs to a datacenter allocation. |
security.is_anonymous | boolean | Whether the IP is a used for anonymization. |
security.is_known_attacker | boolean | Whether the IP is used for DoS attacks, flood etc. |
security.is_known_abuser | boolean | Whether the IP is a used for abusing like hijack, malware etc. |
security.is_threat | boolean | Whether the IP belongs to a high and risk threat. |
security.is_bogon | boolean | Whether the IP belongs to a bogon CIDR ranges. |
security.blocklists | boolean | Whether the IP belongs to a specific organic ban-lists. |
security.scores | boolean | IP Reputation scores for VPN, Proxy, Threat and Trust Score. |
Currency Object
Local currency information for the IP's country.
| Field | Type | Description |
|---|---|---|
currency.code | string | ISO 4217 currency code (e.g. EUR). |
currency.name | string | Currency name (e.g. Euro). |
currency.symbol | string | Currency symbol (e.g. €). |
Errors & Status Codes
The API uses standard HTTP status codes: 2xx for success, 4xx for problems with the request, 5xx for problems on our end. Every error also returns a JSON body so you can branch on error.code without parsing status text.
| Status | Meaning | Typical cause |
|---|---|---|
| 200 | OK | Lookup succeeded. |
| 400 | Bad Request | Malformed or unparseable IP address. |
| 401 | Unauthorized | Missing or invalid token. |
| 403 | Forbidden | Token valid but suspended, or plan doesn't include this field set. |
| 404 | Not Found | No record for a private, reserved, or bogon IP. |
| 500 / 503 | Server Error | Transient issue on our side. Safe to retry with backoff. |
Example error response
{
"error": "Invalid API token! Please recheck your token or sign up at https://ipfly.world/billing"
}
Tip: check error.code rather than the human-readable message in your code — the message text is meant for logs and dashboards, and its wording may evolve over time, while the code is stable.
Best Practices
A few patterns that separate integrations that hold up in production from ones that break under real traffic.
Cache by IP
A given IP's location rarely changes hour to hour. Cache responses for 12–24 hours keyed on the IP to cut request volume dramatically — most apps see 80%+ cache hit rates once traffic has a returning-user base.
Keep the token server-side
Proxy lookups through your own backend. A token embedded in a browser bundle or mobile app will eventually be scraped and used to burn your quota.
Treat security flags as signals, not verdicts
is_vpn, is_proxy, and is_tor are strong risk signals, not proof of intent. Combine them with your own account and behavior signals before blocking a user outright — false positives on shared corporate NATs and mobile carrier gateways are common across every provider.
Fail open, not closed
If a lookup errors or times out, don't block the user's core action (checkout, login, page load) on it. Default to a safe fallback — e.g. no personalization, or a conservative currency — and log the failure for later review.
Batch thoughtfully
Processing a large IP list (log analysis, offline enrichment)? Parallelize with a bounded worker pool (5–10 concurrent requests) instead of firing everything at once — it's both friendlier to the API and easier to reason about failures.
Mind data-retention rules
An IP address paired with derived location data can count as personal data under GDPR and similar regimes. If you store lookups long-term, apply the same retention and deletion policies you use for other user PII.
Code Examples
The same lookup in six languages. Every snippet uses only the standard library or a single common HTTP package — no IPFly-specific SDK required.
curl "https://ipfly.world/api?token=YOUR_TOKEN" curl "https://ipfly.world/api?token=YOUR_TOKEN&ip=8.8.8.8" # Pretty-print with jq curl -s "https://ipfly.world/api?token=YOUR_TOKEN&ip=8.8.8.8" | jq .
const res = await fetch('https://ipfly.world/api?token=YOUR_TOKEN&ip=8.8.8.8');
if (!res.ok) throw new Error(`IPFly error: ${res.status}`);
const data = await res.json();
console.log(data.country_name); // "United States"
console.log(data.city); // "Mountain View"
console.log(data.security.is_vpn); // false
console.log(data.currency.symbol); // "$"// Native fetch, no dependencies needed on Node 18+
async function lookupIP(ip) {
const url = new URL('https://ipfly.world/api');
url.searchParams.set('token', process.env.IPFLY_TOKEN);
if (ip) url.searchParams.set('ip', ip);
const res = await fetch(url);
if (!res.ok) throw new Error(`IPFly ${res.status}`);
return res.json();
}
const geo = await lookupIP('8.8.8.8');
console.log(geo.country_name, geo.asn.name);<?php
$url = 'https://ipfly.world/api?token=' . urlencode($_ENV['IPFLY_TOKEN']) . '&ip=8.8.8.8';
$ctx = stream_context_create(['http' => ['timeout' => 5]]);
$json = @file_get_contents($url, false, $ctx);
if ($json === false) {
// network-level failure — fail open
exit;
}
$data = json_decode($json, true);
if (isset($data['error'])) {
error_log('IPFly error: ' . $data['error']['code']);
exit;
}
echo $data['country_name']; // "United States"
echo $data['security']['is_vpn']; // falseimport os
import requests
def lookup_ip(ip: str | None = None, timeout: float = 5.0) -> dict:
params = {"token": os.environ["IPFLY_TOKEN"]}
if ip:
params["ip"] = ip
r = requests.get("https://ipfly.world/api", params=params, timeout=timeout)
r.raise_for_status()
return r.json()
data = lookup_ip("8.8.8.8")
print(data["city"], data["asn"]["name"]) # Mountain View Google LLCimport java.net.URI;
import java.net.http.*;
import java.time.Duration;
var client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.build();
var request = HttpRequest.newBuilder()
.uri(URI.create("https://ipfly.world/api?token=" + System.getenv("IPFLY_TOKEN") + "&ip=8.8.8.8"))
.timeout(Duration.ofSeconds(5))
.build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("IPFly error: " + response.statusCode());
}
System.out.println(response.body());require 'net/http'
require 'json'
uri = URI("https://ipfly.world/api")
uri.query = URI.encode_www_form(token: ENV['IPFLY_TOKEN'], ip: '8.8.8.8')
response = Net::HTTP.get_response(uri)
data = JSON.parse(response.body)
raise "IPFly error: #{data['error']['code']}" if data['error']
puts data['country_name']
puts data['security']['is_vpn']package main
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"time"
)
func main() {
q := url.Values{}
q.Set("token", os.Getenv("IPFLY_TOKEN"))
q.Set("ip", "8.8.8.8")
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Get("https://ipfly.world/api?" + q.Encode())
if err != nil {
panic(err)
}
defer resp.Body.Close()
var data map[string]interface{}
json.NewDecoder(resp.Body).Decode(&data)
fmt.Println(data["country_name"])
}