The easiest way to add IP geolocation to JavaScript applications. Detect visitor country, city, timezone, and coordinates — with framework-native integrations for Next.js and React.
Built for developers who need geolocation features without wiring up raw API calls: EU compliance gating, locale-based routing, timezone-accurate scheduling, regional content delivery, and privacy-respecting analytics.
- Framework-native — not just an API wrapper. Server-side proxy, React context, conditional rendering components
- Smart timezone — IP-based on first request, browser-confirmed on hydration, cookie-cached thereafter. 100% accurate after first visit
- Privacy compliance ready —
isEU()helper for GDPR, country and region fields for CCPA and other regulations - Zero-config RUM — Core Web Vitals, Navigation Timing, and error tracking enabled by default
- Type-safe — full TypeScript types for every response field
| Use Case | How |
|---|---|
| Show cookie consent to EU users | <GeoGate eu={true}> |
| Redirect by country/locale | withGeoRedirect({ 'DE': '/de', 'FR': '/fr' }) |
| Display local timezone | geo.location?.timezone |
| Personalize by city/region | geo.location?.city, geo.location?.region?.name |
| Block or allow by country | <GeoGate country={['US', 'CA']}> |
| Detect VPN/proxy users | Coming in v2 (see roadmap) |
| Package | Description |
|---|---|
@netloc8/core |
API client, IP detection, platform headers, cookies, RUM telemetry |
@netloc8/react |
React context, Provider, useGeo() hook, <GeoGate> component |
@netloc8/nextjs |
Next.js proxy, server functions, re-exports React bindings |
- Next.js — install
@netloc8/nextjs(includes React + core) - React SPA — install
@netloc8/react(includes core) - Node / Edge / Vanilla JS — install
@netloc8/core
See each package's README for detailed usage instructions.
Documentation · API Reference · Dashboard
All packages return a nested Geo object matching the API's GeolocationResult:
const geo = await fetchGeo('8.8.8.8', { apiKey: 'sk_...' });
geo.query?.value; // "8.8.8.8"
geo.query?.ipVersion; // 4
geo.location?.country?.code; // "US"
geo.location?.country?.name; // "United States"
geo.location?.country?.flag; // "🇺🇸"
geo.location?.country?.unions; // ["EU"] or []
geo.location?.region?.code; // "CA"
geo.location?.region?.name; // "California"
geo.location?.city; // "Mountain View"
geo.location?.postalCode; // "94043"
geo.location?.coordinates?.latitude; // 37.386
geo.location?.coordinates?.longitude; // -122.084
geo.location?.timezone; // "America/Los_Angeles"
geo.location?.utcOffset; // "-07:00"
geo.location?.geoConfidence; // 1.0
geo.network?.asn; // "AS15169"
geo.network?.organization; // "Google LLC"
geo.network?.domain; // "google.com"
geo.meta?.precision; // "city"| Variable | Required | Description |
|---|---|---|
NETLOC8_API_KEY |
Yes (server) | Secret API key (sk_...) for proxy and server functions |
NETLOC8_API_URL |
No | API base URL (defaults to https://api.netloc8.com) |
NETLOC8_TEST_IP |
No | Override IP in development |
For client-side SPAs, pass a publishable key (pk_...) via the apiKey prop instead.
Real User Monitoring is enabled by default. The SDK passively collects Core
Web Vitals (LCP, FID, INP, CLS, TTFB), Navigation Timing, and unhandled errors,
then sends a single beacon via navigator.sendBeacon() when the page is hidden.
- Zero latency — collection is passive, beacon fires on
visibilitychange - No PII — only page path, timing values, connection type, and device type
- Opt out — set
rum={false}on the Provider
- Proxy intercepts each request — detects client IP, checks cookie cache, reads platform headers (Vercel/Cloudflare/CloudFront), and calls the NetLoc8 API if needed
- Reconciliation deep-merges all sources (cookie → platform → API) into a single
Geoobject - Server Components read geo data from
x-netloc8-*request headers set by the proxy - Client Components receive geo data via React context; on mount, the Provider reads the browser's
Intl.DateTimeFormattimezone for 100% accuracy and persists it in a cookie
- Page renders immediately — no server-side geo call blocking the response
- Provider calls the API in the background using a publishable key (
pk_...) - Geo data populates asynchronously — faster wall-clock time than SSR proxy mode
- Browser timezone is reconciled on the same tick
Why is direct mode faster? In SSR proxy mode, the request path is browser → server → NetLoc8 API → server renders → browser. In direct mode, the browser calls the NetLoc8 edge API directly — eliminating the server as a middleman. The page also renders immediately without waiting for geo data.
Trade-off: On a user's first visit, geo-dependent content (like
<GeoGate>or city names) will appear after the API call completes, causing a brief content shift. On repeat visits, the__netloc8cookie provides geo data synchronously — no shift.
- Browser validation headers —
X-NL8-TZ,X-NL8-Lang,X-NL8-Conn, andX-NL8-RTTare sent automatically on every API request to improve geo accuracy - Cookie caching — after the first lookup, geo data is cached in a cookie. Subsequent requests skip the API entirely
# Install dependencies
bun install
# Build all packages
bun run build
# Run tests
bun test packages/