When your Senegalese store starts exporting — to Ivory Coast, Nigeria, Kenya, Europe — every added currency hides traps: FX rates, margin eaten by volatility, customs taxes, unavailable payment methods, multi-language support tickets.
TL;DR
- Recommend max 5 currencies for SMEs: XOF + NGN + KES + EUR + USD covers 80% of African cases.
- Pricing strategy: reference price in USD/EUR, auto-convert with 2.5% safety margin.
- FX update: daily via Open Exchange Rates API (free up to 1000 req/month).
Why multi-currency is needed
Real client case — premium fashion store in Dakar:
- 62% revenue in XOF (SN, CI, BJ)
- 18% revenue in NGN (Lagos, Abuja)
- 9% revenue in EUR (FR/BE/DE diaspora)
- 7% revenue in KES (Nairobi, Mombasa)
- 4% revenue in USD (international, US/CA payers)
Forcing all in XOF would forfeit ~38% revenue.
Multi-currency architecture
`
[Visitor arrives]
↓
[IP detection → country → default currency]
↓
[Currency picker (top)]
↓
[Live product price recompute (cache 6h)]
↓
[Checkout]
↓
[PaymentRouter by (currency, country)]
↓
[Pay in displayed currency]
↓
[Settlement accounting in EUR or XOF]
`
Pricing strategy: USD/EUR as reference
Store prices in USD (or EUR) in DB, compute display price live:
`ts
const RATES_CACHE_KEY = 'fx:rates:v1';
const RATES_TTL = 6 * 3600;
async function getRates(): Promise
const cached = await redis.get(RATES_CACHE_KEY);
if (cached) return JSON.parse(cached);
const res = await fetch(
https://openexchangerates.org/api/latest.json?app_id=${process.env.OXR_KEY}&base=USD
);
const { rates } = await res.json();
await redis.setex(RATES_CACHE_KEY, RATES_TTL, JSON.stringify(rates));
return rates;
}
export async function priceFor(productPriceUsd: number, currency: string): Promise
const rates = await getRates();
const rate = rates[currency.toUpperCase()];
if (!rate) throw new Error(Currency unsupported: ${currency});
const safetyMargin = 1.025;
const raw = productPriceUsd * rate * safetyMargin;
switch (currency.toUpperCase()) {
case 'XOF': return Math.ceil(raw / 100) * 100;
case 'NGN': return Math.ceil(raw / 50) * 50;
case 'KES': return Math.ceil(raw / 10) * 10;
case 'EUR':
Need a professional website?
Kolonell builds websites that attract clients, optimized for the Sénégalese market. Free quote in 2 minutes.
case 'USD': return Math.ceil(raw * 100) / 100;
default: return Math.ceil(raw);
}
}
`
Currency picker UX
Visible but discreet. IP-prefilled:
`tsx
const FLAGS = {
'XOF': { flag: '🇸🇳', label: 'CFA (West Africa)' },
'XAF': { flag: '🇨🇲', label: 'CFA (Central Africa)' },
'NGN': { flag: '🇳🇬', label: '₦ Naira' },
'KES': { flag: '🇰🇪', label: 'KSh Shilling' },
'GHS': { flag: '🇬🇭', label: '₵ Cedi' },
'EUR': { flag: '🇪🇺', label: '€ Euro' },
'USD': { flag: '🇺🇸', label: '$ Dollar' },
};
export function CurrencySelector() {
const { currency, setCurrency } = useCurrency();
return (
{Object.entries(FLAGS).map(([code, { flag, label }]) => (
))}
);
}
`
Payment per currency
Checkout routing by currency:
| Currency | Gateways | Notes |
|---|---|---|
| XOF | Wave, Orange Money, PayDunya, CinetPay | UEMOA |
| XAF | Orange Money, MTN MoMo, Express Union | CEMAC |
| NGN | Paystack, Flutterwave, Squad | Nigeria |
| KES | M-Pesa, Stripe | Kenya |
| GHS | MTN MoMo, Vodafone Cash, Hubtel | Ghana |
| EUR | Stripe, PayPal | Europe |
| USD | Stripe, PayPal | International |
Tax & logistics pitfalls
1. VAT: depends on seller AND buyer country (EU B2C = buyer's country VAT via OSS for EU sellers; outside EU it varies). Senegal: 18% VAT mandatory on domestic sales.
2. Import customs: a Lagos customer buying an XOF product from Dakar pays import duties on arrival. Display these fees or include in export price (DDP).
3. Multi-currency cash: invoicing in NGN but paying suppliers in XOF accrues FX risk. Solutions: multi-currency account (Wise Business, Mercury Africa) or instant conversion.
4. Cross-border returns: a Lagos → Dakar return costs more than product margin for small carts. Returns policy by country.
Real case — Dakar fashion store (12 months)
Before multi-currency (XOF only):
- Revenue: 28M XOF/month
- 19% international carts abandoned at checkout
After multi-currency (XOF, NGN, EUR, USD):
- Revenue: 41M XOF/month (+46%)
- 6% international carts abandoned
- Multi-currency integration cost: 2.8M XOF, ROI 2.2 months
FAQ
Q: Display tax included or excluded?
A: Depends on target country. EU B2C: tax-inclusive mandatory. Africa B2C: local custom = tax-inclusive. B2B export: tax-exclusive + "VAT not applicable / DDP" mention.
Q: Can the customer change currency mid-cart?
A: Technically yes, but avoid — recomputing shipping + conversions is buggy. Lock at checkout start.
Q: How to avoid FX margin losses?
A: 2.5–3.5% buffer per volatility. For very volatile (NGN), 5%.
Conclusion
Multi-currency isn't a luxury — it's the gateway to scale past 30M XOF/month in Africa. The technical stack ships in 2–3 weeks, but the real challenge is multi-country logistics and tax. Plan, test on 1 corridor (e.g., SN → CI), then duplicate.
Mohamed Bah
Fondateur, Kolonell
Passionate about digital and entrepreneurship in Africa, Mohamed has been helping Sénégalese businesses with their digital transformation since 2020. Founder of Kolonell, he believes every SME deserves a professional and accessible online présence.

