Kamero

How to Show Local Currency and Pricing Based on Visitor IP

Showing prices in a visitor's local currency can significantly improve conversion rates. A user in Japan seeing "Â¥1,500" instead of "$9.99" immediately understands the cost without mental math. Here's how to implement it using IP geolocation.

Step 1: Detect the Visitor's Country

const { country } = await fetch(
  "https://geo.kamero.ai/api/geo"
).then(r => r.json());

// country = "JP" (ISO 3166-1 alpha-2)

Step 2: Map Country to Currency

const COUNTRY_CURRENCY: Record<string, string> = {
  US: "USD", CA: "CAD", GB: "GBP", EU: "EUR",
  DE: "EUR", FR: "EUR", IT: "EUR", ES: "EUR",
  JP: "JPY", CN: "CNY", IN: "INR", BR: "BRL",
  AU: "AUD", KR: "KRW", MX: "MXN", SE: "SEK",
  CH: "CHF", SG: "SGD", HK: "HKD", NZ: "NZD",
  // Add more as needed
};

// Eurozone countries
const EUROZONE = new Set([
  "AT","BE","CY","EE","FI","FR","DE","GR",
  "IE","IT","LV","LT","LU","MT","NL","PT",
  "SK","SI","ES"
]);

function getCurrency(countryCode: string): string {
  if (EUROZONE.has(countryCode)) return "EUR";
  return COUNTRY_CURRENCY[countryCode] || "USD";
}

Step 3: Format Prices with Intl.NumberFormat

JavaScript's built-in Intl.NumberFormat handles currency symbols, decimal separators, and grouping for you:

function formatPrice(
  amountUSD: number,
  currency: string,
  exchangeRate: number
): string {
  const localAmount = amountUSD * exchangeRate;

  return new Intl.NumberFormat(undefined, {
    style: "currency",
    currency,
    minimumFractionDigits: currency === "JPY" ? 0 : 2,
  }).format(localAmount);
}

// Examples:
formatPrice(9.99, "JPY", 150);  // "Â¥1,499"
formatPrice(9.99, "EUR", 0.92); // "€9.19"
formatPrice(9.99, "GBP", 0.79); // "£7.89"
formatPrice(9.99, "INR", 83);   // "₹829.17"

Putting It All Together

// Exchange rates (fetch from your preferred source)
const RATES: Record<string, number> = {
  USD: 1, EUR: 0.92, GBP: 0.79, JPY: 150,
  INR: 83, BRL: 4.97, CAD: 1.36, AUD: 1.53,
  CNY: 7.24, KRW: 1320, MXN: 17.1, SEK: 10.5,
};

async function getLocalizedPrice(amountUSD: number) {
  const { country } = await fetch(
    "https://geo.kamero.ai/api/geo"
  ).then(r => r.json());

  const currency = getCurrency(country);
  const rate = RATES[currency] || 1;

  return {
    formatted: formatPrice(amountUSD, currency, rate),
    currency,
    country,
    localAmount: amountUSD * rate,
  };
}

// Usage
const price = await getLocalizedPrice(29.99);
// { formatted: "Â¥4,499", currency: "JPY", country: "JP", localAmount: 4498.5 }

Purchasing Power Parity (PPP) Pricing

Beyond currency conversion, many SaaS companies offer PPP pricing — adjusting the actual price based on the local cost of living. A $29/month plan might be $9/month in India or $15/month in Brazil.

const PPP_DISCOUNTS: Record<string, number> = {
  IN: 0.30,  // 70% discount
  BR: 0.50,  // 50% discount
  MX: 0.50,
  PL: 0.60,
  TR: 0.40,
  PH: 0.35,
  NG: 0.30,
  // Countries not listed get full price
};

function getPPPPrice(baseUSD: number, country: string) {
  const multiplier = PPP_DISCOUNTS[country] || 1;
  const adjustedUSD = baseUSD * multiplier;
  const currency = getCurrency(country);
  const rate = RATES[currency] || 1;

  return {
    original: formatPrice(baseUSD, "USD", 1),
    adjusted: formatPrice(adjustedUSD, currency, rate),
    discount: multiplier < 1
      ? `${Math.round((1 - multiplier) * 100)}% PPP discount`
      : null,
  };
}

// For a visitor from India:
// { original: "$29.99", adjusted: "₹747", discount: "70% PPP discount" }

React Component Example

function PricingCard({ planName, basePrice }: {
  planName: string;
  basePrice: number;
}) {
  const [price, setPrice] = useState<string | null>(null);
  const [discount, setDiscount] = useState<string | null>(null);

  useEffect(() => {
    fetch("https://geo.kamero.ai/api/geo")
      .then(r => r.json())
      .then(({ country }) => {
        const ppp = getPPPPrice(basePrice, country);
        setPrice(ppp.adjusted);
        setDiscount(ppp.discount);
      })
      .catch(() => setPrice(`$${basePrice}`));
  }, [basePrice]);

  return (
    <div className="pricing-card">
      <h3>{planName}</h3>
      <p className="price">{price || `$${basePrice}`}</p>
      <p className="period">per month</p>
      {discount && <span className="badge">{discount}</span>}
    </div>
  );
}

Tips

Detect Visitor Country Instantly

Free API returns country code with every request. No key needed.

View Documentation →