Skip to content
Back to Monetization & Revenue

Currency Support

How to support multiple display currencies while settling in one base currency, without FX risk.

Why

Customers want to see prices in their local currency — a German customer sees €29 and knows what it costs, vs $29 which requires a mental FX conversion that reduces conversion. But accepting payment in 30 currencies creates FX risk: if you display €29 and the customer pays in EUR, you receive EUR which you must convert to USD (your base currency), and the conversion rate varies. The solution is display-only multi-currency: show prices in the customer's local currency (converted from your USD base price at a locked rate), but charge in USD — the customer's card does the conversion at their bank's rate, and you always receive USD. This gives the display benefit (customer sees a familiar number) without the FX risk (you always settle in USD). The most common mistake is charging in the display currency — you take FX risk, and if the EUR drops 10% against USD, your revenue drops 10% on those customers. Display in local currency, charge in base currency.

When

When you have international customers (> 20% of revenue from outside your base currency region). For most SaaS, this is within 6 months of launch.

How

1. Pick a base currency (USD for most SaaS) — this is the currency you settle in, report revenue in, and set prices in
2. Add display-currency conversion on the pricing page: detect the visitor's location (from billing address or, if not available, IP geolocation as a fallback), and show the converted price next to the base price
3. Use a daily-locked FX rate from your payment processor (Stripe's currency conversion API) — do not use live rates, which change during the checkout session and confuse the user
4. Charge in the base currency (USD) — the customer's card issuer does the conversion at their rate, and you receive USD; the customer may see a slightly different amount than the display price (their bank's rate vs your display rate), so add a note: 'charged in USD — your bank may convert at a different rate'
5. For customers who insist on paying in their local currency (some EU businesses require EUR invoicing for accounting), use Stripe's multi-currency settlement: charge in EUR and let Stripe auto-convert to USD at the daily rate
6. Do not offer currency choice on the pricing page — this creates decision friction; detect and display, but let the customer override in their billing settings if they care
7. Update display prices when the FX rate moves > 5% — if you display €29 and the rate moves so the USD price is now €32, update the display; stale display prices create confusion at checkout
8. Report revenue in your base currency only — multi-currency revenue reporting creates FX gains/losses that complicate accounting; let your payment processor handle the conversion and report the settled USD amount

Example

# Display-currency conversion (display only, charge in USD)
const BASE_PRICE_USD = 29;
const FX_RATES = { USD: 1.0, EUR: 0.92, GBP: 0.79, JPY: 150 };  // daily-locked

function displayPrice(countryCode: string) {
  const currency = COUNTRY_CURRENCY[countryCode];  // DE → EUR
  const rate = FX_RATES[currency];
  const localPrice = BASE_PRICE_USD * rate;
  return { amount: localPrice, currency, base: { amount: BASE_PRICE_USD, currency: "USD" } };
}
// German visitor sees: "€26.68 (charged in USD — $29)"
// They pay $29, their bank converts to EUR at the bank's rate

# Stripe charge (always in USD)
await stripe.paymentIntents.create({
  amount: 2900,         // $29.00 USD
  currency: "usd",      // always USD
  customer: customerId,
  description: "EZ4Code Pro — charged in USD",
});
// Customer's bank statement: "$29.00 USD" or "€27.20 EUR" (bank's conversion)

# For customers who require EUR invoicing (B2B)
await stripe.paymentIntents.create({
  amount: 2668,         // €26.68 EUR
  currency: "eur",
  customer: customerId,
});
// Stripe auto-converts to USD at the daily rate and settles in USD

Common Problems

  • ⚠Charging in the display currency — you take FX risk, and if the local currency drops 10% against your base, your revenue drops 10%. Display in local, charge in base.
  • ⚠Using live FX rates — the rate changes during the checkout session, so the displayed price and the charged amount differ, confusing the user. Use daily-locked rates.
  • ⚠Offering a currency selector on the pricing page — this creates decision friction and most users do not care. Auto-detect and display, with an override in billing settings.

Best Practices

  • ✓Display prices in the visitor's local currency (auto-detected) but charge in your base currency — this gives the display benefit without FX risk.
  • ✓Use daily-locked FX rates from your payment processor — live rates change during checkout and confuse the user; locked rates are stable for the session.
  • ✓Add a 'charged in USD' note next to the display price — this sets expectations and prevents support tickets when the customer's bank statement shows a slightly different amount.