European Central Bank logo

Finance & markets · Live on Apify

Historical Exchange Rates and Currency Converter

Get official ECB exchange rates for any pair and date since 1999. Convert amounts with them. Days without a rate are marked with a clear reason.

About $0.90 for 1,000 rate rows$0.0009 per rate row + $0.002 per run. Apify bills you, not us.Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed.

Run it on Apify Opens apify.com, the website where our tools run. Sign up free with Google or email, no card needed.

Apify links on this page are affiliate links. We may earn a commission. You pay the same price. Affiliate disclosure

What you get, for example

pairUSD/JPY
baseUSD
quoteJPY

How to use it: 3 steps

  1. Make a free Apify accountApify is the cloud platform where our tools run. The free plan gives you $5 of usage every month, no credit card needed. You pay Apify, not us.
  2. Paste your input and press StartNo code needed: you fill in a form (the input). It already has a working example. For example: EUR/USD in Currency pairs. Each start is one run.
  3. Download the resultsWhen the run ends, the results are in a table (the dataset). Open Output, press Export and pick Excel or CSV. JSON and the API are there too.

This tool is an Apify Actor: a small program that runs on Apify. You can also run it on a schedule, for example every Monday. New to it? Read how it works, step by step and the 8 words you need first.

What it does

Get official European Central Bank (ECB) exchange rates for any currency pair and any date since 1999, and convert amounts with them. Add a pair like USD/JPY and a date, and you get one clear row per pair and day. Weekends, ECB holidays and days not published yet are marked, not hidden. No API key is needed, and a typical run (2 pairs, last 7 days) costs about $0.01.

  • Any pair. The ECB publishes rates against the euro. For pairs without the euro, like USD/JPY, the Actor computes the cross rate from the two euro rates and shows both of them (eurToBase, eurToQuote). You can check the math yourself.
  • Any date since 1999-01-04. You can use a list of dates, a date range or the last N days.
  • Every day explained. A day without a rate has status: no_rate and a reason in note: weekend, ecb_holiday, not_yet_published or currency_not_quoted.
  • Optional fill. With missingDatePolicy: last_published, a missing day gets the last published rate before it. effectiveDate always shows which day's rate was used.
  • Conversion. Add amounts and get convertedAmount = amount × rate, rounded the way you choose.

Good for

  • Accounting and invoices: the official ECB rate for the invoice date.
  • Finance and audit: a full rate history for a pair, with holidays clearly marked.
  • Reports and BI: a clean daily table of rates for several pairs.

Not a good fit

  • No live or intraday rates. The ECB publishes once a day; today's rate appears after about 16:00 CET.
  • About 30 currencies are quoted today (45 in the full history). No crypto, no exotic currencies outside the ECB list.
  • These are reference rates for information. They are not bank buy/sell rates.

Who uses it

Accountants

Get the official ECB rate for each invoice date.

Finance and audit teams

Build a rate history for a pair with holidays marked.

BI analysts

Get a clean daily table of rates for several pairs.

Price

Pay per event: you pay for each result the tool saves, plus a small start fee for each run. The price includes Apify platform costs. Apify bills you, not us. Prices below are for the Apify free plan.

What you pay forPriceWhen
Start fee$0.002Charged once per run. This tool uses 1 GB of memory or less by default; more memory costs more.
Exchange rate row$0.0009 (from $0.00075 on paid Apify plans)One row with an official ECB rate (direct, inverse or cross) for one pair, date and amount, saved to the Dataset.
Row without a rate$0.00003One row that explains why there is no rate (weekend, holiday, not yet published, currency not quoted or not supported) or a same-currency pair. Dates the source failed for are not written or charged.

Examples

  • One rate row: about $0.0029.
  • 1,000 rate rows: about $0.90.
  • Every day 100 rate rows, for 30 days: about $2.76 a month.

Free to try: the Apify free plan gives you $5 of usage every month, no credit card needed. That is enough for about 5,500 rate rows.

Prices checked on 24 October 2026. See the current price on Apify.

Questions

Why is there no rate on Saturday?

The ECB does not publish on weekends and its holidays. The row says why.

Are these bank rates?

No. They are reference rates for information, not buy or sell rates.

Can I get USD to JPY?

Yes. The tool computes the cross rate from two euro rates and shows both.

Does it have crypto?

No. Only about 30 currencies from the ECB list.

Do I need an API key?

No. The Actor reads public ECB data.

How fresh is the data?

The Actor reads the source on every run. providerLastPublished shows the latest ECB publication at that time.

Details

Step by step on Apify
  1. Open the Input tab.
  2. In Currency pairs (pairs), keep the prefill EUR/USD and EUR/GBP or add your own, for example USD/JPY.
  3. Keep Last days (lastDays) at 7, or add Specific dates (dates), for example 2024-12-31.
  4. Click Start.
  5. Open the Output tab. Each row has pair, requestedDate, status, rate and note.
Tips for better results
  • Use the last published option to fill weekends with Friday's rate.
  • Check effectiveDate. It shows which day's rate was used.
  • Run after about 16:00 CET to get today's rate.
Limits and good to know
  • Platform usage (compute, storage) is included. You do not pay it
  • Rows from missingDatePolicy: skip are not written and not charged
  • If the source fails, no rows are written for the failed dates, so they are not charged
  • An invalid input costs only the Actor start
  • If you set a maximum cost for the run, the Actor stops writing rows before it goes over it. The summary says CAPPED
  • Up to 10 pairs, 100 dates or a 366-day range, 10 amounts and 10,000 rows per run
  • The largest tested run (10,000 rows) took about 30 seconds
  • Dates from 1999-01-04 to today (UTC)

For developers

Sample result

One result from a real test run, in JSON. Real values change from run to run. In Excel or CSV each field is a column.

one result · JSON
{
  "pair": "USD/JPY",
  "base": "USD",
  "quote": "JPY",
  "requestedDate": "2024-12-31",
  "effectiveDate": "2024-12-31",
  "status": "ok",
  "note": null,
  "noteText": null,
  "rate": 156.9544711,
  "inverseRate": 0.006371274377,
  "rateType": "cross_via_EUR",
  "eurToBase": 1.0389,
  "eurToQuote": 163.06,
  "amount": 1000,
  "convertedAmount": 156954.47,
  "provider": "ECB",
  "providerName": "European Central Bank",
  "providerLastPublished": "2026-10-09",
  "source": "Frankfurter API v2 (frankfurter.dev)",
  "sourceUrl": "https://api.frankfurter.dev/v2/rates?base=EUR&quotes=GBP%2CJPY%2CUSD&providers=ECB&from=2024-12-21&to=2024-12-31",
  "fetchedAt": "2026-10-12T10:48:11.221Z"
}

Use it from code

Actor ID: cliqtomedia/historical-fx-rates-converter. You need your Apify API token from Apify Console → Settings → API & Integrations.

Python · apify-client
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("cliqtomedia/historical-fx-rates-converter").call(run_input={
    "pairs": [
        "EUR/USD",
        "EUR/GBP"
    ],
    "lastDays": 7
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
cURL
curl -X POST "https://api.apify.com/v2/acts/cliqtomedia~historical-fx-rates-converter/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"pairs": ["EUR/USD", "EUR/GBP"], "lastDays": 7}'
LangChain · langchain-apify
# pip install langchain-apify
# set APIFY_TOKEN in your environment
from langchain_apify import ApifyActorsTool

tool = ApifyActorsTool("cliqtomedia/historical-fx-rates-converter")
result = tool.invoke({"run_input": {"pairs": ["EUR/USD", "EUR/GBP"], "lastDays": 7}})
print(result)

The cURL call waits for the results, up to 300 seconds. For longer runs, start a run (/runs) and get the results with a webhook or by checking the run. Apify API docs. LlamaIndex, MCP for AI agents and the JavaScript client: AI agents & MCP.

Data fields (21)
FieldTypeMeaning
pairstringPair as BASE/QUOTE, e.g. EUR/USD.
basestringBase currency (ISO 4217).
quotestringQuote currency (ISO 4217).
requestedDatestringDate you asked for (YYYY-MM-DD).
effectiveDatestringPublication date the rate comes from. Differs from requestedDate only with last_published; empty when there is no rate.
statusstringRow result: ok, no_rate or unsupported_currency. Dates the source failed for get no rows; they are listed in RUN_SUMMARY (sourceError).
notestringMachine-readable reason: weekend, ecb_holiday, not_yet_published, currency_not_quoted, last_published_used, same_currency or unsupported_currency. Empty for a normal published rate.
noteTextstringThe same reason in plain English.
ratenumberUnits of QUOTE for 1 BASE on effectiveDate. ECB value as published for EUR/X; exact computation from the two ECB euro rates otherwise (10 significant digits).
inverseRatenumberUnits of BASE for 1 QUOTE (1 / rate, 10 significant digits).
rateTypestringHow the rate was obtained: direct (EUR/X as published), inverse (X/EUR), cross_via_EUR (X/Y from both euro rates) or identity (X/X).
eurToBasenumberECB euro reference rate of the base currency on effectiveDate (1 for EUR).
eurToQuotenumberECB euro reference rate of the quote currency on effectiveDate (1 for EUR).
amountnumberAmount in BASE you asked to convert; empty when no amounts were given.
convertedAmountnumberamount × rate in QUOTE, rounded to the chosen decimals.
providerstringRate provider key, e.g. ECB.
providerNamestringRate provider name.
providerLastPublishedstringLatest publication date the provider had at run time.
sourcestringData access route (Frankfurter API v2).
sourceUrlstringAPI request that returned the rates for this row (or the provider currency list for unsupported codes).
fetchedAtstringWhen the run fetched the data (ISO 8601, UTC).
Input settings (9)

The main fields of the input form. With the API you send them as JSON.

SettingName in the APITypeExample value
Currency pairs requiredpairsarray["EUR/USD", "EUR/GBP"]
Specific datesdatesarray
Date fromdateFromstring
Date todateTostring
Last dayslastDaysinteger7
Rate providerproviderstring"ECB"
Days without a ratemissingDatePolicystring"none"
Amounts to convertamountsarray
Decimals for converted amountsroundinginteger2

Use cases with this tool

Each guide shows all the steps and the other tools.

Start on Apify

Make a free Apify account: you get $5 of free usage every month. Missing a tool? Suggest it. We read every idea, but we do not promise to build it.

Apify links on this page are affiliate links. We may earn a commission. You pay the same price. Affiliate disclosure