On this page
A visitor from Berlin opens your pricing page and sees prices in euros, copy in German, and times in their own zone — with nothing to click. Two server-side calls make that happen before first paint. Here's the whole flow.
What you'll build
A localization layer that turns an inbound IP address into three decisions: which currency to price in, which language to render, and which timezone to show. It runs at the edge on the very first request, so there's no flash of the wrong locale.
1 · Resolve the visitor's IP
Read the client IP from your proxy or edge header (X-Forwarded-For, CF-Connecting-IP), then call the IP Geolocation endpoint. A single request returns country, currency, languages and coordinates from the nearest point of presence in about 35 ms.
const ip = req.headers["cf-connecting-ip"] ?? req.headers["x-forwarded-for"];
const res = await fetch(`https://api.locabium.com/v1/geoip?ip=${ip}`, {
headers: { Authorization: `Bearer ${process.env.LOCABIUM_KEY}` },
});
const geo = await res.json();The response is flat and ready to branch on:
{
"ip": "84.17.62.9",
"country": "DE",
"country_name": "Germany",
"city": "Berlin",
"currency": "EUR",
"languages": ["de", "en"],
"timezone": "Europe/Berlin",
"latitude": 52.52,
"longitude": 13.40
}2 · Choose currency and locale
Map the country and currency onto your own storefront settings. Always keep a fallback so an unknown or missing country degrades to your default rather than breaking.
currency→ format money withIntl.NumberFormat(locale, { style: 'currency', currency }).languages[0]→ preselect the UI language, then let the user override.timezone→ render dates and delivery estimates in the visitor's own zone.
3 · Convert prices with live rates
Keep your catalog priced in one base currency and convert at render time. The Currency Exchange endpoint returns mid-market rates cached hourly, so you're never hard-coding an FX table that quietly goes stale.
curl "https://api.locabium.com/v1/currency?from=USD&to=EUR&amount=49" \
-H "Authorization: Bearer $LOCABIUM_KEY"
# → { "from": "USD", "to": "EUR", "rate": 0.92, "amount": 49, "result": 45.08 }An IP address is personal data under GDPR. Cache the lookup for the session, and don't store the raw IP any longer than you actually need it.
Edge cases: VPNs, proxies and consent
- VPN or proxy traffic resolves to the exit node — treat geolocation as a strong hint, not identity or a hard gate.
- No IP available (SSR without the header)? Fall back to the
Accept-Languageheader plus a visible country picker. - Always show a locale switcher. Detection is a convenience; never trap the user in the guess.
Ready to build this?
View API docs