DEV Community

viraj geeth
viraj geeth

Posted on Originally published at allratestoday.com

I benchmarked 6 free exchange rate APIs every hour for a week. Here are the numbers.

Every "best exchange rate API" list I have read ranks providers by their pricing page. Nobody measures them. So I set up a GitHub Action that hits six free, keyless exchange rate endpoints every hour, records latency, HTTP status and the publication date in the body, and publishes the results as JSON and CSV.

Disclosure up front: I build AllRatesToday, which is one of the six. The harness is public, the raw data is public, and the numbers below are copied from it without editing. If you think the method is unfair to anyone, the workflow file is the place to argue.

Method

  • Vantage: GitHub Actions hosted runner, ubuntu-latest, US East.
  • Cadence: hourly, since 2026-09-19. The table below covers the first 7 days (31 runs at the time of writing).
  • Per run: 3 sequential GETs per provider with a cache-busting query string and a 15 s timeout. The median of the three is recorded.
  • Uptime: share of runs that returned HTTP 2xx with a parseable body.
  • Freshness: the publication date inside the response compared with the run date (UTC).

Source: benchmark.mjs and benchmark.yml. Output: latest.json and history.csv.

Results, first 7 days

Endpoint Type Median p90 Uptime Currencies Data age
fawazahmed0/currency-api (jsDelivr) market, static file 11 ms 23 ms 100% 340 1 day
AllRatesToday open central-bank endpoint official (ECB table) 31 ms 68 ms 100% 29 1 day
ExchangeRate-API open endpoint market 112 ms 131 ms 100% 166 0 days
FloatRates market 316 ms 379 ms 100% 146 1 day
Frankfurter official (ECB) 373 ms 580 ms 96.8% 29 1 day
ECB eurofxref-daily.xml official, primary source 401 ms 558 ms 100% 29 1 day

"Data age" is the gap between the publication date in the response and the run date. A 1-day age on an ECB-derived feed is normal: the ECB publishes around 16:00 CET and the date rolls the next day.

What the numbers actually say

Static beats dynamic. The fastest endpoint is not an API at all. fawazahmed0's project publishes JSON files to a CDN once a day. If daily market rates are enough and you can live without an SLA, a CDN file will always win on latency.

Edge-cached official tables are the next tier. The AllRatesToday open endpoint serves the ECB table from Cloudflare's edge, which is why it lands at 31 ms from a US runner. It carries the ECB's own publication date, so it is usable for invoices and month-end where the auditor asks which rate you used.

The classic "free API" options are 100 to 400 ms. ExchangeRate-API's open endpoint was the most consistent of the dynamic services: 100% uptime and a tight p90. FloatRates and Frankfurter are fine but slower, and Frankfurter dropped one run in the week. One failed run in 31 is not a verdict on Frankfurter, and the 30-day column on the live page will be fairer.

Going straight to the ECB is the slowest option. The primary source XML is 400 ms and still one day old. There is no freshness advantage to fetching it yourself. Cache it or use a mirror.

Which one should you use

  • Side project, daily rates, no budget: fawazahmed0's CDN files or ExchangeRate-API's open endpoint.
  • Anything an accountant will read: an official-rate endpoint that returns the publisher and date. AllRatesToday's open endpoint does that for the ECB with no key, and the keyed API covers 116 central banks plus HMRC, US Treasury and Swiss customs tables.
  • Real-time market rates in a checkout: none of the free endpoints above. Every one is daily. You need a paid tier from any provider that quotes sub-minute updates.

Try the two fastest yourself

# static CDN file, daily
curl -s https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies/eur.min.json | head -c 200

# official ECB table with publication date, no key
curl -s "https://allratestoday.com/api/open/central-bank/ecb?source=USD&target=EUR"
Enter fullscreen mode Exit fullscreen mode

The live page at allratestoday.com/benchmarks/exchange-rate-api updates hourly and adds a rolling 30-day column once there is enough history. If you want another free endpoint added to the harness, open an issue on the data repo and include a keyless URL.

Top comments (0)