Questions or problems? Post in GitHub Discussions.

Google Sheets has GOOGLEFINANCE for exchange rates, and for a quick conversion it's fine. The catch is the source: an unnamed market blend you can't inspect or choose. Frankfurter blends central bank rates you can inspect, and when the source has to be exact you can pin one authority: the ECB reference rate for EU VAT, Poland's NBP, or Brazil's PTAX. A pinned provider's history stays as published. The formulas below go wherever you'd put GOOGLEFINANCE.

Quick Start

No setup and no API key. Drop a live rate into a cell with IMPORTDATA and the CSV endpoint:

=IMPORTDATA("https://api.frankfurter.dev/v2/rates.csv?base=usd&quotes=eur")

Sheets fills in a small date,base,quote,rate table. The date column arrives as a serial number. Select it and pick Format, Number, Date to read it back. Ask for several quotes at once by separating them with commas:

=IMPORTDATA("https://api.frankfurter.dev/v2/rates.csv?base=usd&quotes=eur,gbp,jpy")

Convert an Amount

IMPORTDATA returns the rate, not a converted total. Multiply your amount by the imported rate cell, or use the custom function below for a single clean call.

Custom Function

For a reusable =FRANKFURTER() function, add a short Apps Script. In your sheet, open Extensions, Apps Script, paste this, and save:

/**
 * Converts an amount between currencies, at today's rate or on a date.
 * @customfunction
 */
function FRANKFURTER(amount, from, to, date) {
  let url = `https://api.frankfurter.dev/v2/rate/${from}/${to}`;
  if (date) {
    const tz = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
    url += `?date=${Utilities.formatDate(date, tz, "yyyy-MM-dd")}`;
  }
  const data = JSON.parse(UrlFetchApp.fetch(url).getContentText());
  return amount * data.rate;
}

Then call it from any cell:

=FRANKFURTER(100, "usd", "eur")

Pass a date for a historical rate:

=FRANKFURTER(100, "usd", "eur", DATE(2020, 1, 2))

Pin an Official Provider

By default you get the blend across every provider. Add providers to pin a single authority. This matters for tax and accounting: many countries require their own central bank's published rate when converting foreign-currency amounts.

=IMPORTDATA("https://api.frankfurter.dev/v2/rates.csv?base=usd&quotes=eur&providers=ecb")
ECB
European Central Bank reference rate, the standard for EU VAT and customs.
NBP
Narodowy Bank Polski. Polish VAT and CIT convert at the NBP rate.
CNB
Czech National Bank fixing, used for Czech accounting and tax.
BCB
Banco Central do Brasil PTAX, the reference for Brazilian contracts and tax.
BANXICO
Banco de México FIX rate for settling US dollar obligations.

Browse all providers. A pinned provider follows its own publishing schedule, so its latest rate can trail the blended latest by a day.

Historical Series

Use from for a date range and group=month to collapse it to one row per month, ready to chart. Blended history can shift slightly as new data comes in, so pin a provider when figures must stay fixed.

=IMPORTDATA("https://api.frankfurter.dev/v2/rates.csv?from=1949-12-01&base=usd&quotes=gbp&providers=bbk&group=month")

That pulls the US dollar against the pound back to 1949 from the Deutsche Bundesbank archive. You can watch the $2.80 cable peg hold flat for years, then break in 1967. Deep history runs through the Bundesbank's Frankfurt fixings: the dollar against the mark from 1948, most other dollar crosses from 1949 to 1970. The European Central Bank takes over from 1999, so a continuous modern series uses the default blend or providers=ecb.