20 分で IP 地理位置情報を SaaS に追加する方法
IP 地理位置情報を必要とする 4 つの SaaS 機能: 通貨のデフォルト、GDPR バナー、不正検出、分析ダッシュボード。 それぞれのコードが機能するため、Google マップは必要ありません。
あなたの SaaS はベルリンのユーザーに USD を表示します。 あなたの Cookie バナーがテキサス州の訪問者に表示されます。 ナイジェリアの IP がドイツの請求先住所を使用している場合、詐欺システムはフラグを立てることができません。 4つの特長 IP 地理位置情報が必要ですが、1 つの API を使用して 20 分で 4 つすべてを追加できます。
API呼び出し
この投稿のすべての機能は同じエンドポイントから始まります。 生のカールは次のとおりです。
curl -X POST https://api.botoi.com/v1/ip/lookup \\
-H "Content-Type: application/json" \\
-d '{"ip": "8.8.8.8"}'
応答:
{
"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"
}
}
1 つの POST で、都市、地域、国コード、完全な国名、座標、タイムゾーン、 ISP、組織、および AS 番号。 これは、以下の 4 つの機能すべてを強化するのに十分なデータです。
機能1: チェックアウト時に通貨を自動選択
チェックアウト時に間違った通貨を表示すると、換算率が下がります。 ドイツからのお客様 「$49.99」を見て、決定する前に頭の中でユーロに換算する必要があります。 さらに悪いことに、彼らは、 あなたが彼らの地域にサービスを提供していないと仮定してください。
訪問者の IP 国をデフォルトの通貨にマッピングするミドルウェアを使用して、この問題を修正します。
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 });
});
国と通貨のマップは、上位 15 の SaaS 市場をカバーしています。 視聴者のためにそれを拡張してください。 USD へのフォールバックは API エラーを適切に処理します。 訪問者は壊れたチェックアウトを目にすることはありません 地理位置情報の呼び出しがタイムアウトしたためです。
特徴 2: EU 訪問者専用の GDPR Cookie バナー
すべての訪問者に Cookie 同意バナーを表示するのは不要であり、煩わしいものです。 GDPR は欧州連合内の訪問者に適用されます。 他の人はスキップできます。
このミドルウェアは、訪問者の知的財産国を EU 加盟国のリストと照合します。 フロントエンドが読み取る Cookie を設定します。
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();
});
フロントエンドで Cookie を読み取り、バナーを切り替えます。
// 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";
}
失敗時のデフォルトの動作では、バナーが表示されます。 これはコンプライアンスの面で誤りです。 地域検索が失敗した場合でも、GDPR 要件は満たされています。 クッキーは24時間持続しますが、 したがって、API を呼び出すのは、訪問者ごとに 1 日に 1 回だけです。
特徴 3: 地理的不一致による不正行為の検出
誰かがドイツの請求先住所でチェックアウトしたが、その IP の地理的位置が次の場所にある場合 ナイジェリア、それは調査する価値のある兆候だ。 これはトランザクションが完了するという意味ではありません 詐欺的; 人々は旅行し、VPN を使用し、海外の友人へのプレゼントを購入します。 でもそれはデータです 不正行為調査チームが必要とする点を指摘します。
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 });
});
この関数は、不一致フラグと人間が読める形式の構造化オブジェクトを返します。 サポート チームが確認できるリスク ノート。 手動レビューの代わりに注文にフラグを立てます それを徹底的にブロックします。 これを他のシグナル (電子メール ドメインの年齢、支払い) と組み合わせます。 速度、デバイスの指紋など)より完全な状況を把握します。
機能 4: ユーザー分布を含む分析ダッシュボード
ユーザーがどこにいるかを把握すると、どの言語をサポートするか、どの地域をサポートするかを決定するのに役立ちます。 マーケティングでターゲットを絞るか、エッジ サーバーをどこに配置するか。 このスクリプトはバッチを処理します 訪問者 IP を抽出し、ソートされた国分布を生成します。
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%" },
// ...
// ]
これを夜間のジョブとしてアクセス ログに対して実行します。 出力により、どれがどれであるかが正確にわかります。 最も交通量が多い国。 ユーザーの 14% がドイツにいて、アプリのみがいる場合 英語をサポートしている場合、それは定量化できるローカライズの機会となります。
キャッシュ戦略
IP から場所へのマッピングは頻繁には変更されません。 API を再度呼び出す理由はありません セッション内の同じ IP に対して。 このキャッシュは、1 時間の TTL を持つ単純なマップを使用します。
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;
}
単一インスタンスの Node.js サーバーの場合、メモリ内マップは正常に機能します。 複数実行する場合 ロード バランサーの背後にあるインスタンスでは、マップを Redis に交換します。 同じ TTL ロジックが適用されます。 地理データを有効期限が 3600 秒の JSON 文字列として保存します。
クライアントIPの抽出
IP 地理位置情報の最も注意が必要な部分は API 呼び出しではありません。 正しいIPを取得しています
そもそも。 アプリがリバース プロキシ、ロード バランサー、または CDN の背後にある場合、
req.connection.remoteAddress 訪問者の IP ではなく、プロキシの IP を返します。
各環境で実際のクライアント IP を取得する方法は次のとおりです。
// 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();
常に最初のカンマで分割します x-forwarded-for。 このヘッダーには次の内容を含めることができます
トラフィックが複数のプロキシを通過するときの IP チェーン。 最初のエントリは、
元のクライアント IP。
Cloudflare を使用している場合は、次を使用します cf-connecting-ip。 Cloudflareはこのヘッダーを設定します
すべてのリクエストで、なりすましはより困難です x-forwarded-for。
FAQ
- SaaS アプリケーションに IP 地理位置情報を追加するにはどうすればよいですか?
- 訪問者の IP を IP 地理位置情報 API (POST /v1/ip/lookup など) に送信し、返された国、都市、タイムゾーンのデータを使用してエクスペリエンスをパーソナライズします。 一般的な使用例には、チェックアウト時の通貨の自動選択、EU 訪問者への GDPR バナーの表示、地理的不一致の不正行為の警告、分析ダッシュボードの構築などが含まれます。 1 つの API で 4 つの機能すべてを追加できます。
- SaaS 製品に最適な IP ロケーション API は何ですか?
- 1 回の呼び出しで国、都市、地域、座標、タイムゾーン、および ISP データを返す API を探してください。 Botoi の /v1/ip/lookup は、匿名アクセス (5 要求/分) のサインアップを必要とせずに、これらすべてのフィールドを返します。 運用環境で使用する場合、無料の API キーで 1 日あたり 1,000 件のリクエストが提供されます。 有料プランは月額 9 ドルから始まります。
- Google マップを使用せずに IP でユーザーの位置情報を特定できますか?
- はい。 IP 地理位置情報 API は、Google マップや地図サービスを必要とせずに、緯度、経度、都市、国のデータを返します。 マッピング ライブラリが必要になるのは、ビジュアル マップ上に位置を表示する場合のみです。 通貨のデフォルト設定、GDPR 準拠、不正行為検出などの機能に必要なのは、API からの生の地理位置情報データだけです。
- ユーザーの位置を検出するための IP 地理位置情報はどの程度正確ですか?
- IP 地理位置情報は、国レベルでは約 99%、都市レベルでは約 80 ~ 90% の精度です。 携帯電話会社と VPN ユーザーの精度は低下します。 通貨選択や GDPR 準拠などの SaaS 機能については、国レベルの精度で十分です。 不正行為を検出するには、都市レベルの精度に依存するのではなく、IP 地理位置情報と請求先住所データを組み合わせます。
- IP 地理位置情報の結果を SaaS にキャッシュする必要がありますか?
- はい。 IP から場所へのマッピングは頻繁には変更されないため、IP ごとに 1 時間結果をキャッシュすると API 呼び出しが大幅に減少します。 単一インスタンスのデプロイにはインメモリ マップを使用し、複数インスタンスのセットアップには Redis を使用します。 ほとんどの SaaS アプリケーションでは、再訪問者がセッション内で同じ IP にヒットするため、キャッシュ ヒット率が 60 ~ 80% になります。
botoiで開発を始めよう
150以上のAPIエンドポイント。検索、テキスト処理、画像生成、開発者ユーティリティに対応。無料プラン、クレジットカード不要。