# Identify the companies visiting your website (FetchAPI + ipapi.is)

Turn each visitor's IP address into the company behind it: name, domain, type (business, isp, hosting, education,
government), network, location, and VPN / proxy / datacenter flags. One call per visitor through FetchAPI:

```
GET  https://fetchapi.co/api/gw/ipapi/lookup?q=<visitor ip>          header: x-api-key: gw_...
POST https://fetchapi.co/api/gw/ipapi/lookup  {"ips": ["1.2.3.4", ...]}  (up to 100 per call)
```

The answer is `{"status":"success","data":{...ipapi.is record...},"meta":{"cost_usd":0,...}}`. Field reference with a real
sample: https://fetchapi.co/docs/ipapi.md. The provider is enabled per key (the upstream plan allows 1,000 lookups a
day), so a key that is not enabled gets `forbidden`.

## What counts as an identified company

ipapi.is records who owns the IP range. That is the visitor's employer only on a company network:

| `company.type` | `is_datacenter` / `is_vpn` / `is_proxy` | Meaning |
|---|---|---|
| `business` | all false | **A company visited.** `company.name` and `company.domain` are the lead. |
| `education`, `government` | false | A university or agency visited. |
| `isp` | false | A home or mobile connection: no company (name the ISP, not the person's employer). |
| `hosting` | `is_datacenter: true` | A bot, crawler, cloud server or VPN exit. Not a person. Drop it. |

Expect most consumer traffic to be `isp`, and B2B traffic from offices to be `business`. To go from a company to people
or from an email to a person, see the enrichment waterfall below.

## Wire it into your site (server side; never put the key in the browser)

Next.js on Vercel (`middleware.ts`), non-blocking: the page is served immediately and the lookup runs after.

```ts
import { NextResponse, type NextRequest, type NextFetchEvent } from "next/server";

export function middleware(req: NextRequest, ev: NextFetchEvent) {
  const ip = (req.headers.get("x-forwarded-for") || "").split(",")[0].trim();
  if (ip && req.method === "GET" && !req.nextUrl.pathname.startsWith("/_next")) {
    ev.waitUntil((async () => {
      const r = await fetch(`https://fetchapi.co/api/gw/ipapi/lookup?q=${encodeURIComponent(ip)}`,
        { headers: { "x-api-key": process.env.FETCHAPI_KEY! } });
      const { data: d } = await r.json();
      if (d?.company?.type !== "business" || d.is_datacenter || d.is_vpn || d.is_proxy) return;
      // store it: one row per company per day, e.g. in your database
      console.log("visitor company", d.company.name, d.company.domain, req.nextUrl.pathname, d.location?.country);
    })().catch(() => {}));
  }
  return NextResponse.next();
}
export const config = { matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"] };
```

Any other server: read the client IP (`x-forwarded-for` first value behind a proxy or CDN, else the socket address),
call the same URL, keep `business` rows.

## Spend and limits

- Cache by IP for a day: the same visitor on ten pages is one lookup, not ten. The upstream plan allows 1,000 a day.
- Skip known bots by user agent before looking up, and skip your own office IPs.
- Batch: if you log IPs first, `POST lookup {"ips": [...]}` resolves 100 in one call.

## The waterfall after the company

1. **IP -> company** (this page): ipapi.is, about $0.03 per 1,000 on paid plans, free up to 1,000 a day.
2. **Company domain -> company profile**: size, industry, funding (CompanyEnrich, Hunter; RecentFunding for startups).
3. **Person level** (who exactly): needs a consented identity pixel (US only), e.g. RB2B-style providers, priced about
   $20-330 per 1,000 people identified. Not part of this endpoint.
4. **Email -> person** for sign-ups: Gravatar and GitHub (free), then Hunter, QuickEnrich, Tomba (pay on match).

## Privacy

An IP address is personal data in the EU and UK. Say in your privacy policy that you resolve visitor IPs to the
organisation that owns them, keep company-level results, and don't keep raw IPs longer than you need them.
