Geo resolution
Resolve visitor country, region, and city at ingest, with headers, MaxMind, or your own resolver.
The native engine resolves geo per ingested event, server-side. Resolution never blocks ingestion: on any failure the geo fields stay empty and the event is stored anyway.
Default: platform headers
Out of the box, geo comes from headers your hosting platform already injects. platformHeaderResolver reads:
x-vercel-ip-country,x-vercel-ip-country-region,x-vercel-ip-city(Vercel)cf-ipcountry(Cloudflare, as the country fallback)
On Vercel or behind Cloudflare this means country-level analytics with zero configuration and zero databases.
MaxMind (optional)
For self-hosted deployments without geo headers, point the engine at a MaxMind GeoLite2 database:
native({ geoDbPath: '/data/GeoLite2-City.mmdb' })This composes headers-first with MaxMind: IP lookup runs only when headers did not already supply a country. It requires two things you provide:
pnpm add maxmind # optional peer dependency, loaded lazilyand a downloaded .mmdb file (GeoLite2 is free with a MaxMind account). If the library is missing, the file is unreadable, or a lookup fails, resolution degrades to empty fields with a single logged warning.
Custom pipelines
The @10x-media/analytics/geo subpath exports the building blocks:
import {
platformHeaderResolver,
maxmindResolver,
composeGeoResolvers,
noopResolver,
type GeoResolver,
type Geo,
} from '@10x-media/analytics/geo'A GeoResolver is (headers: Headers) => Geo | Promise<Geo> where Geo is { country?, region?, city? }. Compose resolvers left to right; the first one that produces a country wins:
native({
geoResolver: composeGeoResolvers(
platformHeaderResolver,
maxmindResolver({ dbPath: '/data/GeoLite2-City.mmdb' }),
async (headers) => lookupInMyService(headers.get('x-real-ip')),
),
})Use noopResolver to disable geo entirely (geoResolver: noopResolver).
Where geo shows up
Geo lands on each raw event and in the site-wide country rollup, which powers the Countries dashboard widget and the country dimension. Events without a resolved country are simply omitted from country breakdowns; totals are unaffected.