DEV Community

ApogeoAPI
ApogeoAPI

Posted on • Originally published at apogeoapi.com

How to Localize Prices in React Using Exchange Rates

Showing prices in a user's local currency increases trust, reduces bounce rates, and improves conversions — especially for international audiences. Here's how to do it automatically in React.

The Goal

  1. Detect the user's currency from their IP address (no user input needed)
  2. Fetch the live exchange rate for that currency
  3. Format the price according to their locale

Step 1: Detect User Currency from IP

// hooks/useCurrency.ts
import { useEffect, useState } from 'react';
export function useCurrency() {
const [currency, setCurrency] = useState('USD');
useEffect(() => {
fetch('https://api.apogeoapi.com/v1/geolocate/auto', {
headers: { 'X-API-Key': process.env.NEXT_PUBLIC_APOGEO_KEY! },
})
.then(r => r.json())
.then(geo => setCurrency(geo.currency ?? 'USD'))
.catch(() => {}); // Fallback to USD on any error
}, []);
return currency;
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Fetch the Exchange Rate

// hooks/useExchangeRate.ts
import { useEffect, useState } from 'react';
export function useExchangeRate(currency: string) {
const [rate, setRate] = useState(null);
useEffect(() => {
if (currency === 'USD') { setRate(1); return; }
fetch(`https://api.apogeoapi.com/v1/exchange-rates/${currency}`, {
headers: { 'X-API-Key': process.env.NEXT_PUBLIC_APOGEO_KEY! },
})
.then(r => r.json())
.then(data => setRate(data.usdRate))
.catch(() => setRate(null)); // Fallback: show USD
}, [currency]);
return rate;
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Format the Price

function formatPrice(usdAmount: number, currency: string, usdRate: number): string {
const localAmount = usdAmount / usdRate;
return new Intl.NumberFormat(undefined, {
style: 'currency',
currency,
maximumFractionDigits: 2,
}).format(localAmount);
}
// Examples:
// formatPrice(19, 'EUR', 1.082) → '€17.56'
// formatPrice(19, 'ARS', 0.001) → 'ARS 19,000.00'
// formatPrice(19, 'BRL', 0.19)  → 'R$100.00'
Enter fullscreen mode Exit fullscreen mode

Step 4: The LocalizedPrice Component

// components/LocalizedPrice.tsx
'use client';
import { useCurrency } from '@/hooks/useCurrency';
import { useExchangeRate } from '@/hooks/useExchangeRate';
interface Props {
usdAmount: number;
className?: string;
}
export function LocalizedPrice({ usdAmount, className }: Props) {
const currency = useCurrency();
const rate = useExchangeRate(currency);
if (rate === null) {
return ${usdAmount};
}
const localAmount = usdAmount / rate;
const formatted = new Intl.NumberFormat(undefined, {
style: 'currency',
currency,
maximumFractionDigits: 2,
}).format(localAmount);
return {formatted};
}
Enter fullscreen mode Exit fullscreen mode

Edge Cases

  • Stale rates: The API returns stale: true if rates are older than 6 hours. Show a small "approximate" indicator in that case.
  • Unknown currency: Always have a USD fallback — the catch(() => {}) blocks above handle this.
  • Loading state: While fetching, show the USD price — it's better than a blank or flashing layout.
  • Server-side rendering: Detect currency server-side in middleware and pass it as a prop or cookie to avoid a layout shift.

Originally published at https://apogeoapi.com/blog/localize-prices-react. Try ApogeoAPI free at apogeoapi.com.

Top comments (0)