Comment ajouter la géolocalisation IP à votre SaaS en 20 minutes
Quatre fonctionnalités SaaS nécessitant une géolocalisation IP : valeurs par défaut des devises, bannières RGPD, détection des fraudes et tableaux de bord d'analyse. Code fonctionnel pour chacun, aucun Google Maps requis.
Votre SaaS montre des USD à un utilisateur à Berlin. Votre bannière de cookies apparaît pour les visiteurs au Texas. Votre système anti-fraude ne peut pas signaler lorsqu'une adresse IP nigériane utilise une adresse de facturation allemande. Quatre fonctionnalités Vous avez besoin d'une géolocalisation IP et vous pouvez ajouter les quatre en 20 minutes avec une seule API.
L'appel API
Chaque fonctionnalité de cet article commence par le même point de terminaison. Voici la boucle brute :
curl -X POST https://api.botoi.com/v1/ip/lookup \\
-H "Content-Type: application/json" \\
-d '{"ip": "8.8.8.8"}'
Réponse:
{
"success": true,
"data": {
"ip": "8.8.8.8",
"city": "Mountain View",
"region": "California",
"country": "US",
"countryName": "United States",
"latitude": 37.386,
"longitude": -122.0838,
"timezone": "America/Los_Angeles",
"isp": "Google LLC",
"org": "Google Public DNS",
"as": "AS15169 Google LLC"
}
}
One POST vous donne la ville, la région, le code du pays, le nom complet du pays, les coordonnées, le fuseau horaire, Numéro de FAI, d’organisation et d’AS. C'est suffisamment de données pour alimenter les quatre fonctionnalités ci-dessous.
Fonctionnalité 1 : Sélection automatique de la devise à la caisse
Afficher la mauvaise devise lors du paiement tue les taux de conversion. Un visiteur d'Allemagne voit « 49,99 $ » et doit mentalement le convertir en euros avant de prendre une décision. Pire encore, ils pourraient supposez que vous ne desservez pas leur région.
Corrigez ce problème avec un middleware qui mappe le pays IP du visiteur à une devise par défaut :
const COUNTRY_CURRENCY = {
US: "USD", GB: "GBP", DE: "EUR", FR: "EUR", JP: "JPY",
IN: "INR", BR: "BRL", AU: "AUD", CA: "CAD", CN: "CNY",
KR: "KRW", MX: "MXN", SE: "SEK", CH: "CHF", SG: "SGD",
};
async function currencyMiddleware(req, res, next) {
const ip = req.headers["x-forwarded-for"]?.split(",")[0] || req.ip;
try {
const response = await fetch("https://api.botoi.com/v1/ip/lookup", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ ip }),
});
const { data } = await response.json();
req.defaultCurrency = COUNTRY_CURRENCY[data.country] || "USD";
} catch {
req.defaultCurrency = "USD";
}
next();
}
// Usage in Express
app.get("/checkout", currencyMiddleware, (req, res) => {
res.render("checkout", { currency: req.defaultCurrency });
});
La carte pays-devise couvre les 15 principaux marchés SaaS. Étendez-le à votre public. Le repli vers l'USD gère les échecs d'API avec élégance ; aucun visiteur ne voit jamais une caisse cassée car un appel de géolocalisation a expiré.
Fonctionnalité 2 : bannière de cookies RGPD réservée aux visiteurs de l'UE uniquement
Afficher une bannière de consentement aux cookies à chaque visiteur est inutile et ennuyeux. Le RGPD s'applique aux visiteurs dans l'Union européenne. Tout le monde peut l’ignorer.
Ce middleware vérifie le pays IP du visiteur par rapport à la liste des États membres de l'UE. et définit un cookie que le frontend lit :
const EU_COUNTRIES = new Set([
"AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR",
"DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL",
"PL", "PT", "RO", "SK", "SI", "ES", "SE",
]);
async function gdprMiddleware(req, res, next) {
const ip = req.headers["x-forwarded-for"]?.split(",")[0] || req.ip;
try {
const response = await fetch("https://api.botoi.com/v1/ip/lookup", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ ip }),
});
const { data } = await response.json();
req.isEU = EU_COUNTRIES.has(data.country);
} catch {
// Default to showing the banner when the lookup fails
req.isEU = true;
}
next();
}
// Set a cookie so the frontend knows whether to show the banner
app.use(gdprMiddleware, (req, res, next) => {
res.cookie("gdpr_applies", req.isEU ? "1" : "0", {
httpOnly: false,
maxAge: 86400 * 1000,
});
next();
});
Sur le frontend, lisez le cookie et activez la bannière :
// Frontend: read the cookie and conditionally show the banner
function shouldShowCookieBanner() {
const match = document.cookie.match(/gdpr_applies=(\d)/);
return match ? match[1] === "1" : true; // default to showing
}
if (shouldShowCookieBanner()) {
document.getElementById("cookie-banner").style.display = "block";
}
Le comportement par défaut en cas d'échec est d'afficher la bannière. Cela va dans le sens de la conformité ; si la recherche géographique échoue, vous répondez toujours aux exigences du RGPD. Le cookie dure 24 heures, vous n'appelez donc l'API qu'une fois par visiteur et par jour.
Fonctionnalité 3 : Détection de fraude avec incompatibilité géographique
Lorsqu'une personne effectue un paiement avec une adresse de facturation en Allemagne mais que son adresse IP est géolocalisée à Le Nigeria, c'est un signal qui mérite d'être étudié. Cela ne veut pas dire que la transaction est frauduleux; les gens voyagent, utilisent des VPN et achètent des cadeaux pour des amis à l’étranger. Mais c'est une donnée indiquez les besoins de votre équipe d’examen des fraudes.
async function checkGeoMismatch(ip, billingCountry) {
const response = await fetch("https://api.botoi.com/v1/ip/lookup", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ ip }),
});
const { data } = await response.json();
const mismatch = data.country !== billingCountry;
return {
mismatch,
ipCountry: data.country,
ipCity: data.city,
billingCountry,
riskNote: mismatch
? \`IP located in \${data.countryName} but billing address is \${billingCountry}\`
: null,
};
}
// Usage during checkout
app.post("/checkout", async (req, res) => {
const ip = req.headers["x-forwarded-for"]?.split(",")[0] || req.ip;
const { billingCountry } = req.body;
const geo = await checkGeoMismatch(ip, billingCountry);
if (geo.mismatch) {
// Flag for manual review instead of blocking
await flagOrder(req.body.orderId, geo.riskNote);
}
// Continue processing the order
await processOrder(req.body);
res.json({ success: true });
});
The function returns a structured object with the mismatch flag and a human-readable note de risque que votre équipe d’assistance peut examiner. Marquer la commande pour une révision manuelle au lieu de le bloquant carrément. Combinez cela avec d'autres signaux (âge du domaine de messagerie, paiement vitesse, empreinte digitale de l'appareil) pour une image plus complète.
Fonctionnalité 4 : Tableau de bord d'analyse avec répartition des utilisateurs
Savoir où se trouvent vos utilisateurs vous aide à décider quelles langues prendre en charge et quelles régions cibler avec le marketing et où placer les serveurs Edge. Ce script traite un lot des adresses IP des visiteurs et produit une répartition par pays triée :
async function buildCountryDistribution(ips) {
const counts = {};
// Process in batches to respect rate limits
for (const ip of ips) {
try {
const response = await fetch("https://api.botoi.com/v1/ip/lookup", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ ip }),
});
const { data } = await response.json();
const country = data.countryName || "Unknown";
counts[country] = (counts[country] || 0) + 1;
} catch {
counts["Unknown"] = (counts["Unknown"] || 0) + 1;
}
}
// Sort by count descending
return Object.entries(counts)
.sort(([, a], [, b]) => b - a)
.map(([country, count]) => ({
country,
count,
percentage: ((count / ips.length) * 100).toFixed(1) + "%",
}));
}
// Example output:
// [
// { country: "United States", count: 4521, percentage: "34.2%" },
// { country: "Germany", count: 1893, percentage: "14.3%" },
// { country: "United Kingdom", count: 1247, percentage: "9.4%" },
// ...
// ]
Exécutez-le en tant que tâche nocturne sur vos journaux d'accès. La sortie vous indique exactement lequel les pays génèrent le plus de trafic. Si 14 % de vos utilisateurs se trouvent en Allemagne mais que votre application uniquement prend en charge l'anglais, c'est une opportunité de localisation que vous pouvez quantifier.
Stratégie de mise en cache
Les mappages IP vers emplacement ne changent pas souvent. Il n'y a aucune raison d'appeler à nouveau l'API pour la même IP au sein d’une session. Ce cache utilise une simple Map avec un TTL d'une heure :
class GeoCache {
constructor(ttlMs = 60 * 60 * 1000) {
this.cache = new Map();
this.ttlMs = ttlMs;
}
get(ip) {
const entry = this.cache.get(ip);
if (!entry) return null;
if (Date.now() - entry.timestamp > this.ttlMs) {
this.cache.delete(ip);
return null;
}
return entry.data;
}
set(ip, data) {
this.cache.set(ip, { data, timestamp: Date.now() });
}
}
const geoCache = new GeoCache();
async function lookupWithCache(ip) {
const cached = geoCache.get(ip);
if (cached) return cached;
const response = await fetch("https://api.botoi.com/v1/ip/lookup", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": process.env.BOTOI_API_KEY,
},
body: JSON.stringify({ ip }),
});
const { data } = await response.json();
geoCache.set(ip, data);
return data;
}
Pour les serveurs Node.js à instance unique, la carte en mémoire fonctionne correctement. Si vous exécutez plusieurs instances derrière un équilibreur de charge, remplacez la carte par Redis. La même logique TTL s'applique ; stockez les données géographiques sous forme de chaîne JSON avec une expiration de 3 600 secondes.
Extraire l'adresse IP du client
La partie la plus délicate de la géolocalisation IP n’est pas l’appel API ; ça obtient la bonne adresse IP
en premier lieu. Si votre application se trouve derrière un proxy inverse, un équilibreur de charge ou un CDN,
req.connection.remoteAddress renvoie l'adresse IP du proxy, pas celle du visiteur.
Voici comment obtenir la véritable adresse IP du client dans chaque environnement :
// Express
const ip = req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.ip;
// Next.js (App Router)
import { headers } from "next/headers";
const headerList = await headers();
const ip = headerList.get("x-forwarded-for")?.split(",")[0]?.trim();
// Cloudflare Workers
const ip = request.headers.get("cf-connecting-ip");
// Vercel (edge or serverless)
const ip = request.headers.get("x-real-ip")
|| request.headers.get("x-forwarded-for")?.split(",")[0]?.trim();
Toujours diviser sur la première virgule de x-forwarded-for. Cet en-tête peut contenir
une chaîne d’adresses IP lorsque le trafic passe par plusieurs proxys. La première entrée est la
IP client d'origine.
Si vous êtes sur Cloudflare, utilisez cf-connecting-ip. Cloudflare définit cet en-tête
à chaque demande et c'est plus difficile à usurper que x-forwarded-for.
FAQ
- Comment ajouter la géolocalisation IP à mon application SaaS ?
- Envoyez l'adresse IP de votre visiteur à une API de géolocalisation IP (comme POST /v1/ip/lookup) et utilisez les données renvoyées sur le pays, la ville et le fuseau horaire pour personnaliser son expérience. Les cas d'utilisation courants incluent la sélection automatique de la devise lors du paiement, l'affichage de bannières RGPD aux visiteurs de l'UE, le signalement de fraudes liées aux géo-incohérences et la création de tableaux de bord analytiques. Vous pouvez ajouter les quatre fonctionnalités avec une seule API.
- Quelle est la meilleure API de localisation IP pour les produits SaaS ?
- Recherchez une API qui renvoie les données du pays, de la ville, de la région, des coordonnées, du fuseau horaire et du FAI en un seul appel. /v1/ip/lookup de Botoi renvoie tous ces champs sans inscription requise pour un accès anonyme (5 req/min). Pour une utilisation en production, une clé API gratuite fournit 1 000 requêtes par jour. Les forfaits payants commencent à 9 $/mois.
- Puis-je géolocaliser les utilisateurs par IP sans Google Maps ?
- Oui. Les API de géolocalisation IP renvoient des données de latitude, de longitude, de ville et de pays sans nécessiter Google Maps ni aucun service de cartographie. Vous n'avez besoin d'une bibliothèque de cartographie que si vous souhaitez afficher l'emplacement sur une carte visuelle. Pour des fonctionnalités telles que les valeurs par défaut des devises, la conformité au RGPD et la détection des fraudes, les données brutes de géolocalisation de l'API sont tout ce dont vous avez besoin.
- Quelle est la précision de la géolocalisation IP pour détecter la position de l'utilisateur ?
- La géolocalisation IP est précise au niveau du pays environ 99 % du temps et au niveau de la ville environ 80 à 90 % du temps. La précision diminue pour les opérateurs de téléphonie mobile et les utilisateurs de VPN. Pour les fonctionnalités SaaS telles que la sélection des devises et la conformité au RGPD, la précision au niveau national est suffisante. Pour la détection des fraudes, combinez la géolocalisation IP avec les données d'adresse de facturation plutôt que de vous fier à la précision au niveau de la ville.
- Dois-je mettre en cache les résultats de géolocalisation IP dans mon SaaS ?
- Oui. Les mappages IP vers emplacement changent rarement, donc la mise en cache des résultats pendant 1 heure par IP réduit considérablement les appels d'API. Utilisez une carte en mémoire pour les déploiements à instance unique ou Redis pour les configurations multi-instances. La plupart des applications SaaS enregistrent des taux de réussite du cache de 60 à 80 %, car les visiteurs qui reviennent accèdent à la même adresse IP au cours d'une session.
Commencez a construire avec botoi
150+ endpoints API pour la recherche, le traitement de texte, la generation d'images et les utilitaires pour developpeurs. Offre gratuite, sans carte bancaire.