Documentation
FreeIPAPI
IP geolocation over HTTPS: send an IP (or omit it to use the caller’s IP), get JSON with country, city, coordinates, ASN, and more.
Quick start
- Get an API key from the dashboard
(keys start with
fip_). - Call the API with
Authorization: Bearer YOUR_API_KEY. - Parse JSON from
GET https://api.freeipapi.app/api/v1/lookup— see code examples below.
Authentication
Every request must send your key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
Keys use the fip_ prefix. Create or rotate them in the dashboard.
IP lookup
Base URL: https://api.freeipapi.app
Omit ip to look up the
requesting client’s public IP (useful for “where is this user?” flows).
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ip |
string | No | IPv4 or IPv6. If omitted, uses the caller’s IP. |
Headers
| Header | Value | Notes |
|---|---|---|
Authorization |
Bearer <api_key> |
Required |
Accept |
application/json |
Optional; default is JSON |
Successful response
200 OK with a JSON body. Some plans may include an attribution field.
{
"ip_address": "8.8.8.8",
"ip_version": 4,
"is_valid": true,
"latitude": 37.4056,
"longitude": -122.0775,
"country": "United States",
"country_code": "US",
"region": "California",
"city": "Mountain View",
"postal_code": "94043",
"continent": "North America",
"continent_code": "NA",
"capital": "Washington D.C.",
"phone_codes": [1],
"timezones": ["America/Los_Angeles"],
"languages": ["en"],
"currencies": ["USD"],
"asn": 15169,
"asn_org": "Google LLC",
"is_proxy": false
}
Error responses
Errors use the HTTP status below; the body includes error, message, and
code (mirrors HTTP status).
| HTTP | Error Code | Description |
|---|---|---|
| 400 | INVALID_IP |
The IP address format is invalid |
| 401 | MISSING_AUTH |
Authorization header not provided |
| 401 | INVALID_KEY |
API key not found or malformed |
| 402 | SUBSCRIPTION_REQUIRED |
No active subscription |
| 404 | IP_NOT_FOUND |
IP not found in database |
| 410 | KEY_REVOKED |
API key has been revoked |
| 429 | RATE_LIMITED |
Rate limit exceeded, slow down requests |
| 429 | QUOTA_EXCEEDED |
Monthly request limit reached |
| 503 | SERVICE_ERROR |
Temporary service issue, retry later |
{
"error": "QUOTA_EXCEEDED",
"message": "Monthly request limit reached. Please upgrade your plan.",
"code": 429
}
Rate limits & quotas
Limits apply per account (all keys on the account share one pool).
| Plan | Rate Limit | Monthly Quota |
|---|---|---|
| Hobby | 50 requests / 10 seconds | 50,000 requests |
| Startup | 100 requests / 10 seconds | 2,000,000 requests |
| Business | 1,000 requests / 10 seconds | 10,000,000 requests |
Rate Limit Headers
The API returns rate limit information in response headers:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests allowed in the window |
X-RateLimit-Remaining |
Remaining requests in current window |
X-RateLimit-Reset |
Unix timestamp when the window resets |
Response fields
JSON keys use snake_case. Types below reflect typical successful lookups.
| Field | Type | Description |
|---|---|---|
ip_address |
string | Queried IP |
ip_version |
integer | 4 or 6 |
is_valid |
boolean | Whether the IP was resolved |
latitude |
number | Latitude |
longitude |
number | Longitude |
country |
string | Country name |
country_code |
string | ISO 3166-1 alpha-2 |
region |
string | Region / state / province |
city |
string | City |
postal_code |
string | Postal or ZIP code |
continent |
string | Continent name |
continent_code |
string | Two-letter continent code |
capital |
string | Country capital |
phone_codes |
array | Calling codes |
timezones |
array | IANA timezone ids |
languages |
array | ISO 639-1 codes |
currencies |
array | ISO 4217 codes |
asn |
integer | Autonomous System Number |
asn_org |
string | ASN organization |
is_proxy |
boolean | Known proxy / VPN heuristic |
Code examples
Replace YOUR_API_KEY and adjust the ip query as needed.
curl -s "https://api.freeipapi.app/api/v1/lookup?ip=8.8.8.8" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json"
const response = await fetch('https://api.freeipapi.app/api/v1/lookup?ip=8.8.8.8', {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Accept': 'application/json'
}
});
const data = await response.json();
console.log(data);
import requests
response = requests.get(
'https://api.freeipapi.app/api/v1/lookup?ip=8.8.8.8',
headers={'Authorization': 'Bearer YOUR_API_KEY'}
)
print(response.json())
<?php
$ch = curl_init('https://api.freeipapi.app/api/v1/lookup?ip=8.8.8.8');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer YOUR_API_KEY']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, _ := http.NewRequest("GET",
"https://api.freeipapi.app/api/v1/lookup?ip=8.8.8.8", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
require 'net/http'
require 'json'
uri = URI('https://api.freeipapi.app/api/v1/lookup?ip=8.8.8.8')
req = Net::HTTP::Get.new(uri)
req['Authorization'] = 'Bearer YOUR_API_KEY'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts JSON.pretty_generate(JSON.parse(res.body))
import java.net.URI;
import java.net.http.*;
public class Main {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.freeipapi.app/api/v1/lookup?ip=8.8.8.8"))
.header("Authorization", "Bearer YOUR_API_KEY")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
using System.Net.Http;
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_KEY");
var response = await client.GetStringAsync("https://api.freeipapi.app/api/v1/lookup?ip=8.8.8.8");
Console.WriteLine(response);
Troubleshooting
401 Unauthorized
- Confirm the key is active and starts with
fip_ - Header must be exactly
Authorization: Bearer YOUR_API_KEY(no quotes, no typos)
429 QUOTA_EXCEEDED
- Monthly quota for your account is exhausted — upgrade or wait for reset
- Review usage in the dashboard
429 RATE_LIMITED
- Too many requests in the sliding window — slow down or backoff
- Use
X-RateLimit-Resetto know when to retry
404 IP_NOT_FOUND
- Private/reserved IPs or gaps in the DB — try another address
503 SERVICE_ERROR
- Transient failure — retry with backoff