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 mid-market rates 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 | 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 mid-market 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.
Written by the team behind AllRatesToday — a free, keyless
exchange rate API with real-time mid-market rates for 160+ currencies and
official central-bank rates from 120+ sources. Browse the API docs or
grab a free key to start building.
Open source: official SDKs for JavaScript, Python, PHP and Rust,
plus an MCP server (@allratestoday/mcp-server) for AI agents.
Follow along: LinkedIn ·
X / Twitter · GitHub
