Caching
Read this one. It is the difference between instantgeo feeling instant and feeling slow.
Why it matters here specifically
We serve from a single region, and the response depends on who is asking — so it
is Cache-Control: private, meaning Cloudflare cannot cache it for you and every
uncached call is a full round trip. For a visitor on another continent that is
roughly 250–350ms.
Cached, it is zero.
We are working on the underlying number. In the meantime, caching is entirely in your hands and takes about five lines.
Cache per session
A visitor’s location does not change while they browse. Look it up once:
async function getGeo(key) { const cached = sessionStorage.getItem('geo'); if (cached) return JSON.parse(cached);
const geo = await fetch( `https://api.instantgeo.info/v1/geo?key=${key}` ).then((r) => r.json());
sessionStorage.setItem('geo', JSON.stringify(geo)); return geo;}A shopper viewing eight pages now makes one request instead of eight. That is an 8x reduction in both latency-visible calls and quota consumption.
If several parts of your page ask at once, keep the in-flight promise and hand the same one to every caller, so a burst of callers still makes one request:
let inFlight = null;
function visitor() { const cached = sessionStorage.getItem('geo'); if (cached) return Promise.resolve(JSON.parse(cached)); inFlight ??= fetch(URL) .then((r) => r.json()) .then((geo) => { sessionStorage.setItem('geo', JSON.stringify(geo)); return geo; }) .finally(() => { inFlight = null; }); return inFlight;}Preconnect
<link rel="preconnect" href="https://api.instantgeo.info" />In your <head>, this opens the TLS connection while the rest of the page loads,
so the first call does not pay for the handshake. A cross-continent handshake
costs two to three extra round trips — this line is free and removes them from
the critical path.
Do not block rendering on it
Never await geolocation before painting. Render a sensible default, then adjust:
// Good: page renders immediately, refines when geo arrives.document.body.dataset.currency = 'USD';getGeo(key).then((geo) => { if (geo.currency) document.body.dataset.currency = geo.currency;});// Bad: every visitor waits on a network call before seeing anything.const geo = await getGeo(key);render(geo);Respect Cache-Control
We send private, max-age=300. If you are calling from a server, honour it. Five
minutes is plenty — a caller’s IP rarely moves faster than that, and it cuts your
usage substantially.