# Show HN: IP Lookup API

> Source: <https://companyofcraft.com/ip-lookup>
> Published: 2026-10-18 17:22:05+00:00

# IP lookup

See what a website can tell from an IP address: where it is, whose network it is on, and whether it looks like a VPN, a bot or an AI crawler.

## Questions

## How do I check if a request comes from a real Googlebot or GPTBot?

Anyone can put Googlebot or GPTBot in a user agent. Google, Bing, Apple, OpenAI, Anthropic and Perplexity publish the IP ranges their crawlers use. A request is real when its IP is in those ranges. Call the API with the `ip` and `ua` of the request to check it.

## Can it tell if someone uses a VPN?

Partly. Tor exit nodes are on a public list, so those are certain. VPNs and proxies mostly run on hosting networks like AWS, DigitalOcean, Hetzner or M247, so an IP from one of those is likely a VPN, a proxy or a server. A VPN on a home network looks like any home connection.

## Why is my location a different city?

An IP address belongs to a network, not a house. The location is where your internet provider says that network is, which can be the nearest big city. Mobile networks and VPNs can show a city far away.

## Why is the city missing when I look up another IP?

The city comes from the network your request arrives through, so it is only known for your own IP. For other IPs the country comes from the regional internet registry.

## Are the IPs I look up saved?

No. Nothing is stored.

## Detect bots on your site

Send the visitor's IP and a few request headers from your server to `POST /api/ip-lookup`. The answer has a `verdict`: `human`, `proxy`, `bot`, `ai_crawler`, `search_bot` or `spoofed_crawler`, plus `isBot`, `isAiCrawler` and `isProxy`. Send only the headers below, not cookies.

```
curl -X POST https://companyofcraft.com/api/ip-lookup \
  -d '{"ip":"66.249.66.1","headers":{"user-agent":"Googlebot/2.1"}}'
```

On Netlify, an Edge Function can check every request:

``` js
const HEADERS = ["user-agent", "accept", "accept-language", "sec-ch-ua", "sec-fetch-mode"];

export default async (request, context) => {
  const headers = Object.fromEntries(
    HEADERS.filter((name) => request.headers.has(name)).map((name) => [name, request.headers.get(name)]),
  );
  const response = await fetch("https://companyofcraft.com/api/ip-lookup", {
    method: "POST",
    body: JSON.stringify({ ip: context.ip, headers }),
  });
  const { verdict } = await response.json();
  if (verdict === "spoofed_crawler") {
    return new Response("Forbidden", { status: 403 });
  }
  return context.next();
};
```

To check your own request, call `GET /api/ip-lookup`. Add `?ip=` and `&ua=` to look up another IP. Each server or browser can make 600 calls a minute.

## How it works

The network and its country come from the [Team Cymru IP to ASN service](https://www.team-cymru.com/ip-asn-mapping). Tor exit nodes come from the [Tor Project list](https://check.torproject.org/torbulkexitlist). Bots are matched by user agent and checked against the IP ranges each company publishes. The map uses [Natural Earth](https://www.naturalearthdata.com) data.

Company of Craft also builds [stateofpixel](https://stateofpixel.com), which catches UI regressions before they merge.
