Langsung ke konten
Integration

Bagaimana cara menambahkan geolokasi IP ke SaaS Anda dalam 20 menit

| 7 min read

Empat fitur SaaS yang memerlukan geolokasi IP: default mata uang, spanduk GDPR, deteksi penipuan, dan dasbor analitik. Kode berfungsi untuk masing-masing, tidak diperlukan Google Maps.

World map with location pins showing IP geolocation data
Photo by NASA on Unsplash

SaaS Anda menunjukkan USD kepada pengguna di Berlin. Spanduk cookie Anda muncul untuk pengunjung di Texas. Sistem penipuan Anda tidak dapat menandai ketika IP Nigeria menggunakan alamat penagihan Jerman. Empat fitur memerlukan geolokasi IP, dan Anda dapat menambahkan keempatnya dalam 20 menit dengan satu API.

Panggilan API

Setiap fitur dalam postingan ini dimulai dengan titik akhir yang sama. Inilah ikal mentahnya:

curl -X POST https://api.botoi.com/v1/ip/lookup \\
  -H "Content-Type: application/json" \\
  -d '{"ip": "8.8.8.8"}'

Tanggapan:

{
  "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"
  }
}

Satu POST memberi Anda kota, wilayah, kode negara, nama lengkap negara, koordinat, zona waktu, ISP, organisasi, dan nomor AS. Data tersebut cukup untuk mendukung keempat fitur di bawah ini.

Fitur 1: Pilih mata uang secara otomatis saat checkout

Menampilkan mata uang yang salah saat checkout akan mematikan tingkat konversi. Seorang pengunjung dari Jerman melihat "$49,99" dan harus secara mental mengonversi ke euro sebelum memutuskan. Lebih buruk lagi, mungkin saja demikian asumsikan Anda tidak melayani wilayah mereka.

Perbaiki masalah ini dengan middleware yang memetakan negara IP pengunjung ke mata uang default:

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 });
});

Peta negara-ke-mata uang mencakup 15 pasar SaaS teratas. Perluas untuk audiens Anda. Penggantian ke USD menangani kegagalan API dengan baik; tidak ada pengunjung yang pernah melihat kasir rusak karena waktu panggilan geolokasi habis.

Fitur 2: Spanduk cookie GDPR hanya untuk pengunjung UE

Menampilkan spanduk persetujuan cookie kepada setiap pengunjung tidak diperlukan dan mengganggu. GDPR berlaku untuk pengunjung di Uni Eropa. Semua orang bisa melewatkannya.

Middleware ini memeriksa negara IP pengunjung terhadap daftar negara anggota UE dan menetapkan cookie yang frontendnya berbunyi:

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();
});

Di frontend, baca cookie dan aktifkan banner:

// 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";
}

Perilaku default jika gagal adalah menampilkan spanduk. Hal ini salah dalam hal kepatuhan; jika pencarian geografis gagal, Anda masih memenuhi persyaratan GDPR. Kuenya tahan 24 jam, jadi Anda hanya memanggil API satu kali per pengunjung per hari.

Fitur 3: Deteksi penipuan dengan ketidakcocokan geografis

Ketika seseorang memeriksa dengan alamat penagihan di Jerman tetapi IP mereka melakukan geolokasi ke Nigeria, itu adalah sinyal yang perlu diselidiki. Ini tidak berarti transaksinya demikian penipuan; orang bepergian, menggunakan VPN, dan membeli hadiah untuk teman di luar negeri. Tapi itu data tunjukkan kebutuhan tim peninjau penipuan Anda.

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 });
});

Fungsi ini mengembalikan objek terstruktur dengan tanda ketidakcocokan dan dapat dibaca manusia catatan risiko yang dapat ditinjau oleh tim dukungan Anda. Tandai pesanan untuk peninjauan manual memblokirnya secara langsung. Gabungkan ini dengan sinyal lain (usia domain email, pembayaran kecepatan, sidik jari perangkat) untuk gambaran yang lebih lengkap.

Fitur 4: Dasbor analitik dengan distribusi pengguna

Mengetahui lokasi pengguna membantu Anda memutuskan bahasa mana yang akan didukung dan wilayah mana untuk menargetkan dengan pemasaran, dan di mana menempatkan server edge. Skrip ini memproses batch IP pengunjung dan menghasilkan distribusi negara yang diurutkan:

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%" },
//   ...
// ]

Jalankan ini sebagai pekerjaan malam terhadap log akses Anda. Outputnya memberi tahu Anda yang mana negara-negara yang mengarahkan lalu lintas terbanyak. Jika 14% pengguna Anda berada di Jerman tetapi hanya aplikasi Anda mendukung bahasa Inggris, itu adalah peluang pelokalan yang dapat Anda ukur.

Strategi cache

Pemetaan IP-ke-lokasi tidak sering berubah. Tidak ada alasan untuk memanggil API lagi untuk IP yang sama dalam satu sesi. Cache ini menggunakan Peta sederhana dengan TTL 1 jam:

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;
}

Untuk server Node.js instans tunggal, Peta dalam memori berfungsi dengan baik. Jika Anda menjalankan banyak contoh di belakang penyeimbang beban, tukar Peta dengan Redis. Logika TTL yang sama juga berlaku; menyimpan data geografis sebagai string JSON dengan masa berlaku 3600 detik.

Mengekstrak IP klien

Bagian tersulit dari geolokasi IP bukanlah panggilan API; itu mendapatkan IP yang benar pertama. Jika aplikasi Anda berada di belakang proxy terbalik, penyeimbang beban, atau CDN, req.connection.remoteAddress mengembalikan IP proxy, bukan pengunjung.

Berikut cara mendapatkan IP klien sebenarnya di setiap lingkungan:

// 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();

Selalu dipisahkan pada koma pertama x-forwarded-for. Header ini dapat berisi rantai IP ketika lalu lintas melewati beberapa proxy. Entri pertama adalah IP klien asli.

Jika Anda menggunakan Cloudflare, gunakan cf-connecting-ip. Cloudflare menyetel tajuk ini pada setiap permintaan dan lebih sulit untuk dipalsukan daripada x-forwarded-for.

FAQ

Bagaimana cara menambahkan geolokasi IP ke aplikasi SaaS saya?
Kirim IP pengunjung Anda ke API geolokasi IP (seperti POST /v1/ip/lookup) dan gunakan data negara, kota, dan zona waktu yang dikembalikan untuk mempersonalisasi pengalaman mereka. Kasus penggunaan yang umum mencakup pemilihan mata uang secara otomatis saat checkout, menampilkan spanduk GDPR kepada pengunjung UE, menandai penipuan geo-mismatch, dan membuat dasbor analitik. Anda dapat menambahkan keempat fitur dengan satu API.
Apa API lokasi IP terbaik untuk produk SaaS?
Cari API yang mengembalikan data negara, kota, wilayah, koordinat, zona waktu, dan ISP dalam satu panggilan. /v1/ip/lookup Botoi mengembalikan semua bidang ini tanpa perlu mendaftar untuk akses anonim (5 persyaratan/mnt). Untuk penggunaan produksi, kunci API gratis menyediakan 1.000 permintaan per hari. Paket berbayar mulai dari $9/bulan.
Bisakah saya melakukan geolokasi pengguna berdasarkan IP tanpa Google Maps?
Ya. API geolokasi IP mengembalikan data lintang, bujur, kota, dan negara tanpa memerlukan Google Maps atau layanan pemetaan apa pun. Anda hanya memerlukan perpustakaan pemetaan jika ingin menampilkan lokasi pada peta visual. Untuk fitur seperti default mata uang, kepatuhan GDPR, dan deteksi penipuan, Anda hanya memerlukan data geolokasi mentah dari API.
Seberapa akurat geolokasi IP untuk mendeteksi lokasi pengguna?
Geolokasi IP akurat pada tingkat negara sekitar 99% dan pada tingkat kota sekitar 80-90%. Akurasi menurun pada operator seluler dan pengguna VPN. Untuk fitur SaaS seperti pemilihan mata uang dan kepatuhan GDPR, akurasi tingkat negara sudah memadai. Untuk deteksi penipuan, gabungkan geolokasi IP dengan data alamat penagihan daripada mengandalkan presisi tingkat kota.
Haruskah saya menyimpan hasil geolokasi IP di SaaS saya?
Ya. Pemetaan IP-ke-lokasi jarang berubah, sehingga hasil cache selama 1 jam per IP mengurangi panggilan API secara signifikan. Gunakan Peta dalam memori untuk penerapan instans tunggal atau Redis untuk penyiapan multi-instans. Sebagian besar aplikasi SaaS melihat tingkat cache hit sebesar 60-80% karena pengunjung yang kembali mengunjungi IP yang sama dalam satu sesi.

Mulai membangun dengan botoi

150+ endpoint API untuk pencarian, pemrosesan teks, pembuatan gambar, dan utilitas developer. Paket gratis, tanpa kartu kredit.