Picking an FX data provider is one of those decisions you don't want to couple your code to. ECB data is free but only ~30 currencies. fawazahmed0/currency-api is free and covers crypto, but it's CDN-based. AllRatesToday gives you real-time Reuters data but needs a key. Each has different endpoints, shapes, and auth.
live-currency-rates is a tiny wrapper that hides all of that behind a fluent API. Write your code once; swap providers with one line when requirements change.
The API you actually write
import { Convert } from 'live-currency-rates';
const result = await Convert(100).from('USD').to('EUR');
console.log(result.amount); // 92.45
That's it. No setup needed to start — defaults to the free Frankfurter provider (ECB data, no key, no signup).
Install
npm install live-currency-rates
Zero dependencies. TypeScript types included.
Three providers, one interface
| Provider | Key? | Currencies | Source | Notes |
|---|---|---|---|---|
frankfurter |
no | ~30 | European Central Bank | Default. Daily updates. |
fawaz |
no | 200+ | fawazahmed0/currency-api | Includes crypto. CDN-hosted. |
allrates |
yes | 160+ | AllRatesToday (Reuters) | Real-time mid-market rates. |
Pick one with setup():
import { setup, Convert } from 'live-currency-rates';
// Free, no key — 200+ currencies including crypto
setup({ provider: 'fawaz' });
// AllRatesToday — real-time Reuters rates, free key at allratestoday.com/register
setup({ apiKey: 'art_live_...' });
Your existing Convert(...) calls don't change. That's the point.
Core API
Convert(amount).from(...).to(...)
const result = await Convert(250).from('GBP').to('JPY');
console.log(`250 GBP = ${result.amount} JPY`);
console.log(`Rate: ${result.rate}`);
Returns { amount, rate, from, to, originalAmount }.
Rate('XXX').to('YYY')
import { Rate } from 'live-currency-rates';
const { rate } = await Rate('USD').to('EUR');
console.log(`1 USD = ${rate} EUR`);
Rates('XXX', ['YYY', 'ZZZ'])
One round-trip, multiple pairs:
import { Rates } from 'live-currency-rates';
const rates = await Rates('USD', ['EUR', 'GBP', 'JPY']);
// { EUR: 0.92, GBP: 0.78, JPY: 149.5 }
Omit the target list to get every available rate for that base.
Why a wrapper?
Three reasons it earns its keep:
-
Start free, upgrade later. Ship the MVP with Frankfurter. When you hit a currency Frankfurter doesn't cover, flip to
fawazorallrateswithout touching call sites. - Test without hitting production. Point tests at Frankfurter; point prod at AllRatesToday. Same code.
- Provider lock-in is costly. Every provider has different endpoint shapes. A fluent wrapper means a future provider migration is one file change, not a rewrite.
When you outgrow the wrapper
The wrapper optimizes for "I don't care which provider yet." If you've settled on a provider and need its full feature set, drop to the native client:
-
AllRatesToday only? Use
@allratestoday/sdk— full API: historicals, time-series, preset periods. -
Just want a one-liner + CLI? Use
fx-rates. -
Need cashify-compatible sync conversion? Use
moneyify.
Next steps
- npm:
live-currency-rates - Free API key (AllRatesToday provider): allratestoday.com/register
Which provider did you land on, and why? Comments open.
Top comments (0)