Skip to content

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.