# Historical Exchange Rates and Currency Converter

> Historical exchange rates from the ECB for any pair and date since 1999. Cross rates, weekend and holiday notes, and amount conversion. No API key.

URL: https://cliqtomedia.com/actors/historical-fx-rates-converter/

Category: Finance, markets & sports · Status: live on Apify Store · Apify page: https://apify.com/cliqtomedia/historical-fx-rates-converter?fpr=cliqto

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.

## How to use it: 3 steps

1. **Make a free Apify account.** Apify 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 Start.** No 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 results.** When 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.

## 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.

## Price

Pay per event. Apify bills you, not us.

| What you pay for | Price | When |
|---|---|---|
| Start fee | $0.002 | Charged 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.00003 | One 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. |

- 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.

Prices checked on 24 October 2026. Current price: https://apify.com/cliqtomedia/historical-fx-rates-converter?fpr=cliqto

## 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.

## Data fields

- `pair` (string): Pair as BASE/QUOTE, e.g. EUR/USD.
- `base` (string): Base currency (ISO 4217).
- `quote` (string): Quote currency (ISO 4217).
- `requestedDate` (string): Date you asked for (YYYY-MM-DD).
- `effectiveDate` (string): Publication date the rate comes from. Differs from requestedDate only with last_published; empty when there is no rate.
- `status` (string): Row result: ok, no_rate or unsupported_currency. Dates the source failed for get no rows; they are listed in RUN_SUMMARY (sourceError).
- `note` (string): Machine-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.
- `noteText` (string): The same reason in plain English.
- `rate` (number): Units 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).
- `inverseRate` (number): Units of BASE for 1 QUOTE (1 / rate, 10 significant digits).
- `rateType` (string): How 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).
- `eurToBase` (number): ECB euro reference rate of the base currency on effectiveDate (1 for EUR).
- `eurToQuote` (number): ECB euro reference rate of the quote currency on effectiveDate (1 for EUR).
- `amount` (number): Amount in BASE you asked to convert; empty when no amounts were given.
- `convertedAmount` (number): amount × rate in QUOTE, rounded to the chosen decimals.
- `provider` (string): Rate provider key, e.g. ECB.
- `providerName` (string): Rate provider name.
- `providerLastPublished` (string): Latest publication date the provider had at run time.
- `source` (string): Data access route (Frankfurter API v2).
- `sourceUrl` (string): API request that returned the rates for this row (or the provider currency list for unsupported codes).
- `fetchedAt` (string): When the run fetched the data (ISO 8601, UTC).

## Input settings

- `pairs` (array, required): Up to 10 pairs as BASE/QUOTE with 3-letter ISO codes, e.g. EUR/USD, USD/JPY or GBP/PLN. Also accepted: EURUSD, eur-usd. The rate is how many QUOTE units one BASE unit buys. Any two ECB currencies can be combined; pairs without EUR are computed exactly from the two ECB euro rates. Codes the ECB does not publish get an unsupported_currency row.
- `dates` (array): Up to 100 dates in YYYY-MM-DD format, e.g. 2024-12-31, from 1999-01-04 to today (UTC). Rows keep this order. When set, Date from/to and Last days are ignored.
- `dateFrom` (string): Start of a date range (YYYY-MM-DD), used together with Date to. Every calendar day in the range gets a row, at most 366 days. Ignored when Specific dates is set.
- `dateTo` (string): End of the date range (YYYY-MM-DD), not later than today (UTC).
- `lastDays` (integer): Used only when no dates and no range are given: every calendar day from N−1 days ago to today (UTC). Default 7. Today usually shows not_yet_published until the ECB releases rates around 16:00 CET.
- `provider` (string): Official source of the rates. ECB reference rates are published on TARGET business days around 16:00 CET for about 30 currencies (more historically).
- `missingDatePolicy` (string): What to do on weekends, ECB holidays and days not published yet. last_published looks back at most 10 days and always shows effectiveDate; it never carries forward a currency the ECB stopped quoting. Default: none.
- `amounts` (array): Optional, up to 10 amounts in the BASE currency, e.g. 100 or 2500.50. Each amount gets its own row with convertedAmount = amount × rate. Leave empty to get rates only.
- `rounding` (integer): Decimal places for convertedAmount (0–8), rounded half away from zero. Rates are never rounded beyond what the ECB publishes (cross rates keep 10 significant digits). Default 2.

## 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

- 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



- 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).

## Sample 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`

```python
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)
```

```bash
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}'
```

```python
# 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)
```

run-sync waits up to 300 seconds; for longer runs start a run and use a webhook. LlamaIndex and MCP: https://cliqtomedia.com/actors/ai-agents/

## Use cases with this tool

- [Track prices in shops and marketplaces](https://cliqtomedia.com/actors/use-cases/price-monitoring/): Track prices and offers in shops and marketplaces. See changes before your customers do.

## Similar tools

- [SEC Form D Filing Monitor](https://cliqtomedia.com/actors/sec-edgar-form-d-funding-monitor/)
- [Crypto Prices & OHLC History Export - No Login](https://cliqtomedia.com/actors/crypto-market-data/)
- [Polymarket & Kalshi Prediction Market Data, No Login](https://cliqtomedia.com/actors/prediction-markets-data/)
- [Tennis Scraper: ATP & WTA Matches, Players & Rankings](https://cliqtomedia.com/actors/tennis-stats-scraper/)
