How to Add Multi-Currency Pricing to Your Online Store
If your online store only shows prices in one currency, you are leaving money on the table. International shoppers who cannot see prices in their own currency are far more likely to abandon their cart and buy from a competitor who makes it easy.
This guide walks you through everything you need to add multi-currency pricing to your e-commerce store -- from detecting the customer's location to converting prices in real time using exchange rate APIs.
Why Multi-Currency Pricing Matters
The numbers tell a compelling story:
- 92% of shoppers prefer to see prices in their local currency before making a purchase.
- 33% of international visitors abandon their cart when prices are displayed only in a foreign currency.
- Stores with multi-currency support see 12-15% higher conversion rates on average compared to single-currency stores.
Think about it from the customer's perspective. A shopper in Germany sees a product listed at $49.99 USD. They have to mentally convert that to euros, wonder what the actual charge will be on their credit card, and worry about hidden conversion fees. That friction is enough to send them to a competitor who shows the price as 45.89 EUR upfront.
Key insight: Multi-currency pricing is not just a nice-to-have for international stores. It is one of the highest-ROI changes you can make to reduce cart abandonment and increase global conversions.
How Multi-Currency Pricing Works
At a high level, the architecture is straightforward:
- Detect the customer's location or preferred currency.
- Fetch current exchange rates from a reliable API.
- Convert your base prices into the target currency.
- Display the converted price with proper formatting.
- Handle checkout in either your base currency or the customer's local currency.
You keep your product catalog in a single base currency (e.g., USD), and all other prices are calculated dynamically. This means you never have to manually update prices for each currency -- the exchange rates do the work for you.
Step 1: Detect the Customer's Location and Currency
There are three common approaches, and the best stores use a combination of all three:
GeoIP Detection
Use the customer's IP address to determine their country, then map that country to its primary currency. Services like MaxMind GeoLite2 or Cloudflare's CF-IPCountry header make this simple. This gives you a solid default without the customer lifting a finger.
Browser Locale
The navigator.language property in JavaScript returns the user's browser locale (e.g., de-DE for German in Germany). You can extract the country code and map it to a currency. This is less reliable than GeoIP but works as a fallback.
Manual Currency Selector
Always give customers the option to override automatic detection. A dropdown in your header showing a flag and currency code lets users choose exactly what they want. Store their preference in a cookie or localStorage so it persists across sessions.
// Map country code to currency
const countryCurrencyMap = {
US: 'USD', GB: 'GBP', DE: 'EUR', FR: 'EUR',
JP: 'JPY', CA: 'CAD', AU: 'AUD', IN: 'INR',
BR: 'BRL', MX: 'MXN', CN: 'CNY', KR: 'KRW'
};
function getCurrencyFromCountry(countryCode) {
return countryCurrencyMap[countryCode] || 'USD';
} Step 2: Fetch Exchange Rates from an API
You need a reliable source for exchange rates. Hardcoding rates is a recipe for disaster -- currencies fluctuate constantly, and stale rates lead to either overcharging customers or losing margin.
AllRatesToday is an excellent choice for e-commerce use cases. It provides mid-market rates for 160+ currencies, updates every 60 seconds, and offers a free tier that does not require a credit card. The API is simple, fast, and built for exactly this kind of integration.
// Fetch exchange rates from AllRatesToday
const API_KEY = 'your_api_key_here';
async function getExchangeRates(baseCurrency = 'USD') {
const response = await fetch(
`https://api.allratestoday.com/v1/latest?base=${baseCurrency}`,
{
headers: { 'Authorization': `Bearer ${API_KEY}` }
}
);
const data = await response.json();
return data.rates; // { EUR: 0.9178, GBP: 0.7892, JPY: 149.53, ... }
} Important: Always cache exchange rates server-side. You do not need fresh rates on every page load. Fetching once every 5-10 minutes is sufficient for most e-commerce stores and keeps your API usage low.
Here is a simple caching layer:
// Simple in-memory cache for exchange rates
let cachedRates = null;
let cacheTimestamp = 0;
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
async function getRates(baseCurrency = 'USD') {
const now = Date.now();
if (cachedRates && (now - cacheTimestamp) < CACHE_TTL) {
return cachedRates;
}
cachedRates = await getExchangeRates(baseCurrency);
cacheTimestamp = now;
return cachedRates;
} Step 3: Convert and Display Prices
Once you have the rates, converting a price is simple multiplication. The real trick is formatting -- every currency has its own symbol, decimal separator, and digit grouping.
JavaScript's built-in Intl.NumberFormat handles all of this for you:
function convertAndFormat(priceInBase, targetCurrency, rates) {
const converted = priceInBase * rates[targetCurrency];
return new Intl.NumberFormat(undefined, {
style: 'currency',
currency: targetCurrency,
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(converted);
}
// Usage
const rates = await getRates('USD');
console.log(convertAndFormat(49.99, 'EUR', rates)); // "€45.89"
console.log(convertAndFormat(49.99, 'JPY', rates)); // "¥7,474"
console.log(convertAndFormat(49.99, 'GBP', rates)); // "£39.45" For Japanese yen and other zero-decimal currencies, adjust the fraction digits:
const zeroDecimalCurrencies = ['JPY', 'KRW', 'VND', 'CLP', 'ISK'];
function formatPrice(amount, currency) {
const fractionDigits = zeroDecimalCurrencies.includes(currency) ? 0 : 2;
return new Intl.NumberFormat(undefined, {
style: 'currency',
currency: currency,
minimumFractionDigits: fractionDigits,
maximumFractionDigits: fractionDigits
}).format(amount);
} Pro tip: Show a small disclaimer like "Prices shown in EUR are approximate. You will be charged in USD." This sets the right expectation and builds trust.
Step 4: Handle Checkout and Payment
This is where the decision gets important. You have two options:
Option A: Display in Local Currency, Charge in Base Currency
Show the converted price throughout the browsing experience, but at checkout, clearly state that the charge will be in your base currency (e.g., USD). The customer's bank handles the final conversion. This is simpler to implement but less transparent.
Option B: Charge in the Customer's Local Currency
Use your payment processor's multi-currency settlement feature. Stripe, PayPal, and Adyen all support charging in 100+ currencies. You lock in the exchange rate at checkout time and settle in the customer's currency. This gives the best customer experience but requires more setup.
| Factor | Option A (Display Only) | Option B (Charge Local) |
|---|---|---|
| Implementation effort | Low | Medium-High |
| Customer experience | Good | Excellent |
| Currency risk | On customer | On merchant |
| Payment processor support | Any processor | Stripe, PayPal, Adyen |
| Recommended for | Getting started quickly | Scaling international sales |
Recommendation: Start with Option A to get multi-currency display live quickly. Migrate to Option B as your international sales grow and justify the additional complexity.
Common Pitfalls to Avoid
Rounding Errors
Always round after the final conversion, not during intermediate calculations. A one-cent rounding error multiplied across thousands of transactions adds up. Use Math.round(amount * 100) / 100 for two-decimal currencies.
Stale Exchange Rates
If your cache expires and the API is temporarily unreachable, serve the stale rates rather than showing an error or falling back to unconverted prices. Set up monitoring to alert you if rates have not refreshed in the last 30 minutes.
Tax Implications
Multi-currency display does not change your tax obligations, but it can create confusion. Always calculate taxes in your base currency first, then convert the total. Make sure invoices show amounts in the currency the customer was actually charged in.
Price Anchoring Issues
If rates fluctuate significantly, a product that was 49.99 EUR yesterday might be 51.23 EUR today. Consider adding a small buffer (1-3% markup on the mid-market rate) to absorb minor fluctuations so prices feel more stable to returning visitors.
Platform-Specific Tips
Shopify
Shopify Markets handles multi-currency natively. Enable it in Settings > Markets, and Shopify will auto-detect customer location and convert prices. For more control over rates or to use mid-market rates, integrate with AllRatesToday through a custom app or the Shopify Functions API.
WooCommerce
Use the WPML WooCommerce Multilingual plugin or Currency Switcher for WooCommerce. Both support custom exchange rate providers. You can write a small plugin that fetches rates from AllRatesToday's API and feeds them into the currency switcher automatically.
Custom Stores (Node.js, React, Next.js)
You have full control. Fetch rates from AllRatesToday on the server side, cache them in Redis or in-memory, and pass the converted prices to your frontend. Use Intl.NumberFormat for display, and store the exchange rate used at checkout time for your accounting records.
// Next.js API route example
// pages/api/prices.js
import { getRates } from '../../lib/rates';
export default async function handler(req, res) {
const { currency = 'USD' } = req.query;
const rates = await getRates('USD');
const rate = rates[currency] || 1;
// Convert all product prices
const products = getProducts().map(product => ({
...product,
displayPrice: formatPrice(product.basePrice * rate, currency),
rawPrice: Math.round(product.basePrice * rate * 100) / 100
}));
res.json({ products, currency, rate });
} Frequently Asked Questions
Does showing prices in local currency increase conversions?
Yes. Studies show that 92% of shoppers prefer to see prices in their local currency, and multi-currency stores see 12-15% higher conversion rates on average compared to single-currency stores.
How do I get exchange rates for my e-commerce store?
Use an exchange rate API like AllRatesToday to fetch real-time mid-market rates. Rates update every 60 seconds for 160+ currencies. Cache them server-side and convert prices on the fly based on the customer's location.
Should I use mid-market or retail exchange rates for pricing?
Use mid-market rates as your baseline, then add a small markup (1-3%) to cover currency fluctuation risk. This is more transparent than using inflated retail rates, and customers trust stores that show rates close to what they see on Google.
Power Your Store with Real-Time Rates
160+ currencies, 60-second updates, free tier with no credit card. Built for e-commerce.
Get Your Free API Key