← Docs and guides

IP lookup in a Cloudflare Worker

A small Worker that looks up the caller's IP with the ipatlas API, caches the answer at the edge and keeps your key in a secret.

Do you need this?

Workers already expose coarse location data for the visitor in request.cf. A lookup API is useful when you want the same data source and fields on every platform, or when you need to look up an address that is not the current visitor (from a form, a webhook or a log line). This example uses the visitor's address from CF-Connecting-IP; change ip to look up any other validated address.

src/index.js

export default {
  async fetch(request, env) {
    const ip = request.headers.get("CF-Connecting-IP");
    if (!ip) return json({ error: "no client address" }, 400);

    let r;
    try {
      r = await fetch(`https://api.ipatlas.dev/v1/${encodeURIComponent(ip)}`, {
        headers: env.IPATLAS_KEY ? { "X-API-Key": env.IPATLAS_KEY } : {},
        cf: { cacheTtl: 3600 },                      // cache successful answers at the edge for an hour
        signal: AbortSignal.timeout(2000),
      });
    } catch {
      return json({ error: "lookup unavailable" }, 503);
    }

    if (r.status === 429) {                          // over the per-second or the quota limit
      return json({ error: "lookup busy" }, 503, { "Retry-After": r.headers.get("Retry-After") ?? "60" });
    }
    if (!r.ok) return json({ error: "lookup failed" }, 502);

    const geo = await r.json();
    return json({ country: geo.country_code ?? null, city: geo.city ?? null, timezone: geo.timezone ?? null });
  },
};

const json = (body, status = 200, headers = {}) =>
  new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json", ...headers } });

wrangler.toml

name = "ip-lookup"
main = "src/index.js"
compatibility_date = "2025-01-01"

Create a free key on the home page, then store it as a secret and deploy:

npx wrangler secret put IPATLAS_KEY
npx wrangler deploy

Notes

Limits: without a key, 1,000 requests per day per IP address (10 req/s); with a free key, 50,000 requests per month (50 req/s). Over a limit the API returns 429. IP geolocation is approximate: country is usually right, city often is not.

Attribution

The data is DB-IP Lite, licensed CC BY 4.0. If you show or use it in a public product, link to DB-IP, for example in your footer:

<a href="https://db-ip.com">IP Geolocation by DB-IP</a>

See the API docs for fields, limits and error codes.