@ipgeotrace/express
v0.1.0
Published
Express middleware for IPGeoTrace. Resolves the caller's location once per request and exposes it on req.geo.
Maintainers
Readme
@ipgeotrace/express
Express middleware for IPGeoTrace. Resolves the caller's location once
per request and hands it to you on req.geo. Built on
@ipgeotrace/client — the secret key stays server-side.
Sign up and grab your API key at ipgeotrace.com.
Install
npm add @ipgeotrace/express expressUsage
import express from 'express';
import { ipgeotrace, getGeo } from '@ipgeotrace/express';
const app = express();
app.set('trust proxy', true); // so req.ip reads X-Forwarded-For behind a proxy / load balancer
app.use(ipgeotrace({ apiKey: process.env.IPGEOTRACE_API_KEY! }));
app.get('/checkout', (req, res) => {
const geo = getGeo(req);
const currency = geo.status === 'resolved' ? geo.value?.country?.currency ?? 'USD' : 'USD';
res.json({ currency });
});req.geo (and getGeo(req)) is a GeoLookup whose status tells you exactly what happened:
resolved—valuecarries the data.skipped— the caller's IP was missing, private, loopback, or link-local, so no API call was made.failed—errorcarries the reason (rate_limited,quota_exceeded, …).not_attempted— the middleware opted out for this request (shouldResolvereturned false).
getGeo() is always safe to call and returns not_attempted when the middleware never ran.
Skipping requests
Health checks and internal endpoints should not spend lookups. Opt them out with shouldResolve:
app.use(ipgeotrace({
apiKey: process.env.IPGEOTRACE_API_KEY!,
shouldResolve: (req) => !req.path.startsWith('/health') && !req.path.startsWith('/internal'),
}));Private, loopback, and link-local addresses (including IPv4-mapped IPv6) are detected locally and skipped without an API call or quota usage.
Choosing the caller's IP
By default the middleware uses req.ip, which respects Express's trust proxy setting. For full
control, supply your own selector:
app.use(ipgeotrace({
apiKey: process.env.IPGEOTRACE_API_KEY!,
ipSelector: (req) => req.header('cf-connecting-ip') ?? req.ip,
}));Configuration
Pass client options through clientOptions, or share a pre-built client across your app:
import { IpGeoTraceClient } from '@ipgeotrace/client';
// inline client options
app.use(ipgeotrace({
apiKey: process.env.IPGEOTRACE_API_KEY!,
clientOptions: { cache: true, cacheTtlMs: 6 * 60 * 60_000, timeoutMs: 3_000 },
}));
// or bring your own client (also usable directly in services)
const client = new IpGeoTraceClient({ apiKey: process.env.IPGEOTRACE_API_KEY!, cache: true });
app.use(ipgeotrace({ client }));See the @ipgeotrace/client README for caching, retries, timeouts, and batch lookups.
