API Documentation
Free IP geolocation API. 10,000 req/day. Zero logs. Powered by Cloudflare.
Overview
whatsmy.fyi provides a single REST endpoint that returns IP address, geolocation, and connection metadata for the requesting IP. All data comes directly from the Cloudflare edge network β no third-party databases, no caching, no IP query logging.
- Free tier β 10,000 requests/day per key (Enterprise for unlimited)
- No IP query logging β we never store the IPs you look up
- Powered by Cloudflare Workers β global sub-50ms latency
- Three scopes:
ip,geo,full
Infrastructure & Reliability
whatsmy.fyi runs on Cloudflare Workers β the same global edge network that serves millions of production applications. There are no intermediate servers, no external database queries on the hot path, and no third-party IP lookup services.
Edge locations
300+ globally
Response time
p50 < 20ms worldwide
Infrastructure SLA
99.99% (Cloudflare)
IP data source
Native CF request context
Key validation
KV cache β no D1 on hot path
Health monitoring
Pinged every 5 minutes
Keyless endpoint
Just need your bare IP β no signup, no key? Use GET /ip. It returns plain text by default, or JSON with ?format=json β the same response shape as api.ipify.org, so it works as a drop-in replacement.
# Plain text
curl https://whatsmy.fyi/ip
# β 203.0.113.42
# JSON (ipify-compatible)
curl "https://whatsmy.fyi/ip?format=json"
# β {"ip":"203.0.113.42"}CORS is enabled, both IPv4 and IPv6 are supported, and nothing is logged. For geolocation, ASN, and timezone data, use the authenticated /api/v1/ip endpoint below. See how we stack up against other IP APIs on the comparison page β
Base URL
https://whatsmy.fyi/api/v1
Authentication
All requests require an API key. Pass it as a Bearer token in the Authorization header (preferred) or as a key query parameter.
# Header (preferred) curl https://whatsmy.fyi/api/v1/ip \ -H "Authorization: Bearer wmf_your_api_key" # Query parameter (fallback) curl "https://whatsmy.fyi/api/v1/ip?key=wmf_your_api_key"
Don't have a key? Create a free account β
Scopes
Each API key has a scope that controls which fields are returned. You choose the scope when creating a key and can change it anytime from the dashboard.
status, ip, ipv6
status, ip, ipv6, city, region, region_code, country, country_name,
continent, latitude, longitude, timezone, timezone_offset, postal_code,
asn, org, as, is_eu, currency
Everything in Geo, plus: http_protocol, tls_version, tls_cipher, rtt, colo, proxy, hosting
You can also narrow the scope per request with the ?scope= query parameter β useful when one key serves multiple use cases. A request can never widen beyond the key's scope: a geo key with ?scope=full still returns geo fields.
# Key has "full" scope, but this request only needs the IP: curl "https://whatsmy.fyi/api/v1/ip?scope=ip" \ -H "Authorization: Bearer wmf_your_api_key"
Endpoint
/api/v1/ipReturns IP metadata for the caller. The response shape depends on the key's scope.
Request
GET /api/v1/ip HTTP/1.1 Host: whatsmy.fyi Authorization: Bearer wmf_your_api_key
Response by scope
{
"status": "success",
"ip": "203.0.113.42",
"ipv6": null,
"city": "Amsterdam",
"region": "North Holland",
"region_code": "NH",
"country": "NL",
"country_name": "Netherlands",
"continent": "EU",
"latitude": 52.374,
"longitude": 4.8897,
"timezone": "Europe/Amsterdam",
"timezone_offset": 7200,
"postal_code": "1011",
"asn": 1101,
"org": "SURF B.V.",
"as": "AS1101 SURF B.V.",
"is_eu": true,
"currency": "EUR"
}Response fields
The Scope column shows which key scope includes each field. ALL = all scopes, GEO+ = geo and full, FULL = full only.
| Field | Type | Scope | Description |
|---|---|---|---|
status | string | ALL | Always "success" on a valid response |
ip | string | ALL | IPv4 address of the request (null if IPv6) |
ipv6 | string | ALL | IPv6 address of the request (null if IPv4) |
city | string | GEO+ | City name |
region | string | GEO+ | Region / state name |
region_code | string | GEO+ | ISO 3166-2 subdivision code (e.g. "NH", "34") |
country | string | GEO+ | ISO 3166-1 alpha-2 country code (e.g. "NL") |
country_name | string | GEO+ | Full country name in English (e.g. "Netherlands") |
continent | string | GEO+ | Two-letter continent code (e.g. "EU") |
latitude | number | GEO+ | Latitude (decimal degrees) |
longitude | number | GEO+ | Longitude (decimal degrees) |
timezone | string | GEO+ | IANA timezone identifier (e.g. "Europe/Amsterdam") |
timezone_offset | number | GEO+ | UTC offset in seconds (e.g. 7200 = UTC+2) |
postal_code | string | GEO+ | Postal / ZIP code |
asn | number | GEO+ | Autonomous System Number |
org | string | GEO+ | AS organisation name (ISP) |
as | string | GEO+ | Formatted AS string (e.g. "AS1101 SURF B.V.") |
is_eu | boolean | GEO+ | Whether the IP is located in the EU |
currency | string | GEO+ | ISO 4217 currency code for the country (e.g. "EUR") |
http_protocol | string | FULL | HTTP protocol version (e.g. "HTTP/3", "HTTP/2") |
tls_version | string | FULL | TLS version (e.g. "TLSv1.3") |
tls_cipher | string | FULL | TLS cipher suite |
rtt | number | FULL | Round-trip time from client to Cloudflare edge (ms) |
colo | string | FULL | Cloudflare datacenter IATA code that handled the request |
proxy | boolean | FULL | Whether the ASN is a known VPN or proxy provider |
hosting | boolean | FULL | Whether the ASN is a known hosting or cloud provider |
Error reference
| Status | Error | Meaning |
|---|---|---|
| 401 | missing_api_key | No API key was provided in the request |
| 401 | invalid_api_key | The key does not exist or was deleted |
| 403 | inactive_api_key | The key exists but has been deactivated |
| 429 | rate_limit_exceeded | Daily quota (10,000 req/day) reached, or burst limit (300 req/min) exceeded β burst pauses the key until you resume it |
| 500 | internal_error | Unexpected server error β please try again |
Code examples
curl https://whatsmy.fyi/api/v1/ip \ -H "Authorization: Bearer wmf_your_api_key"
Rate limits
Two limits apply to every API key:
- Daily quota β 10,000 requests per day on the free tier. The counter resets at midnight UTC.
- Burst limit β 300 requests per minute per key. This protects against runaway loops and applies to all keys, including enterprise.
Rate limit status is returned on every response via headers:
X-RateLimit-Limit: 10000 X-RateLimit-Remaining: 9987 X-RateLimit-Reset: 1749081600 # Unix timestamp of next reset
When the daily quota is exceeded, the API returns a 429 response and requests resume automatically at midnight UTC:
{
"error": "rate_limit_exceeded",
"message": "You have reached the free tier limit of 10,000 requests/day. Resets at midnight UTC.",
"docs": "https://whatsmy.fyi/docs#rate-limits",
"enterprise": "https://whatsmy.fyi/enterprise"
}When the burst limit is exceeded, the key is automatically paused β exceeding 300 req/min almost always indicates a bug (an infinite loop, a missing cache). The 429 response includes Retry-After: 60, and you can review and resume the key from your dashboard with one click. Tip: cache responses on your side β a visitor's IP data rarely changes within a session.
Need more? Enterprise plan β
API Stability & Versioning
The /api/v1/ip endpoint follows a strict stability contract. Production integrations can rely on it long-term.
- πBreaking changes are never made to /api/v1/ β existing integrations keep working.
- βNew response fields may be added at any time (additive only β safe to ignore).
- π£Deprecations are announced at least 6 months in advance via the changelog.
- π’/api/v2/ will be introduced for any breaking change β /v1/ stays live in parallel.
- πAll changes are documented at whatsmy.fyi/changelog.
For enterprise SLA requirements β Contact us
Official Node.js SDK
Install the official @whatsmyfyi/sdk package for TypeScript-first access with automatic retries and full type definitions.
npm install @whatsmyfyi/sdk
import { WhatsMyFyi } from '@whatsmyfyi/sdk'
const client = new WhatsMyFyi({ apiKey: 'wmf_your_api_key' })
// Full response
const data = await client.ip.lookup()
console.log(data.city) // "Amsterdam"
console.log(data.country) // "NL"
// Quick helpers
const ip = await client.ip.address() // "203.0.113.42"
const loc = await client.ip.location() // { city, country, countryCode, lat, lng }
const org = await client.ip.org() // { asn, name }- Keyless mode β
new WhatsMyFyi()without a key still servesip.address() - Zero dependencies β uses native
fetch - Works in Node.js, Deno, Bun, and the browser
- Auto-retry on 5xx with exponential backoff (max 3 attempts)
- Typed
WhatsMyFyiErrorwithcode,message,status
OpenAPI Specification
The full OpenAPI 3.1 spec is available for import into Postman, Insomnia, or any compatible tool. In Postman, go to File β Import β Link and paste the URL below.
https://whatsmy.fyi/openapi.jsonBadge
Add a badge to your README or website to show that you use the whatsmy.fyi API.
HTML
<a href="https://whatsmy.fyi"> <img src="https://whatsmy.fyi/api/badge" alt="Powered by whatsmy.fyi" height="40" /> </a>
Markdown (GitHub README)
[](https://whatsmy.fyi)
For light backgrounds, append ?theme=light:
[](https://whatsmy.fyi)
Try it live
Make a real API request right here β no account or API key needed. You'll see your own IP data returned directly from the Cloudflare edge.
Live demo β no API key needed
This returns your real IP data from the Cloudflare edge.
Hit "Send Request" to see your real IP data.
Get started
Create a free account to get your API key in under a minute.
Create a free account β