# How to Implement a Currency Converter in FlutterFlow

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 30-40 min
- Compatibility: FlutterFlow Free+
- Last updated: March 2026

## TL;DR

Build a currency converter in FlutterFlow by calling the exchangerate-api.com API to fetch live exchange rates, caching the full rates map in App State so you only call the API once per session, displaying two currency DropDowns and an amount TextField, and computing the converted result in a Custom Function. A historical chart shows rate trends using fl_chart.

## Real-Time Exchange Rate Conversion with Smart Caching

This tutorial shows you how to build a functional currency converter inside FlutterFlow. The key design decision is caching: instead of calling the exchange rate API on every keystroke or every DropDown change, you fetch the full rates map once on app start and store it in App State. The conversion calculation happens entirely in a Custom Function using the cached data — zero additional API calls. Two DropDown widgets let users select the from and to currencies. A TextField accepts the input amount and triggers the Custom Function on every change event. A results display shows the converted amount in real time. An optional historical chart section uses the fl_chart package to show how the selected currency pair has moved over 7 days.

## Before you start

- FlutterFlow account (Free plan works for this tutorial)
- A free API key from exchangerate-api.com (sign up takes 1 minute)
- Basic familiarity with FlutterFlow's API Calls panel and Custom Functions
- App State variables created for caching rate data

## Step-by-step guide

### 1. Set Up the Exchange Rate API Call in FlutterFlow

In FlutterFlow, open the API Calls panel from the left sidebar. Click the + button to create a new API call. Name it GetExchangeRates. Set the method to GET and the URL to https://v6.exchangerate-api.com/v6/YOUR_API_KEY/latest/USD. In FlutterFlow Settings, add your API key as an App Constant named EXCHANGE_RATE_API_KEY and reference it in the URL: https://v6.exchangerate-api.com/v6/[EXCHANGE_RATE_API_KEY]/latest/USD. Click Test API Call — you should see a JSON response with a conversion_rates object containing ~160 currency codes and their rates relative to USD. Click the JSON path arrows next to conversion_rates to create a JSON path for the rates map. Save the API call.

**Expected result:** The API call returns a 200 response with conversion_rates containing currency codes and exchange rates.

### 2. Cache Exchange Rates in App State

Open FlutterFlow's App State panel. Create two variables: ratesJson (String, persisted — stores the raw JSON string of conversion_rates), and ratesLastFetched (DateTime, persisted — records when rates were last fetched). On the App Start action (Settings → App Start Actions), add a conditional: if ratesLastFetched is null OR if the difference between DateTime.now() and ratesLastFetched is greater than 3 hours, then call GetExchangeRates. On success, update ratesJson with the response's conversion_rates JSON string and update ratesLastFetched to DateTime.now(). This means the API is called at most once every 3 hours per device, not on every user action.

**Expected result:** Exchange rates are fetched on first app launch and cached in App State. Subsequent opens within 3 hours skip the API call.

### 3. Build the Converter UI with Two DropDowns and a TextField

Create the converter page layout. Add a TextField at the top for the amount input. Set its keyboard type to Decimal. Store its value in a Page State variable named inputAmount (String). Below it, add a Row with two DropDown widgets side by side. Both DropDowns use a static option list of currency codes — add the most common ones: USD, EUR, GBP, JPY, CAD, AUD, CHF, CNY, INR, MXN, BRL, SGD. Store the selected values in Page State variables fromCurrency (String, default USD) and toCurrency (String, default EUR). Add a swap IconButton between the two DropDowns. On tap, swap the fromCurrency and toCurrency Page State values and trigger recalculation. Below the DropDowns, add a large Text widget that will display the converted result, bound to a Page State variable named convertedAmount (String).

**Expected result:** The page shows a numeric input field, two currency DropDowns with a swap button, and a converted amount display area.

### 4. Calculate Conversion with a Custom Function

Create a Custom Function named convertCurrency. It takes four arguments: ratesJson (String), fromCurrency (String), toCurrency (String), and amount (String). It returns a String. The function parses ratesJson, finds the rates for both currencies relative to USD, converts the amount from fromCurrency to USD then from USD to toCurrency, and returns a formatted result string. In FlutterFlow, wire this function to trigger whenever inputAmount, fromCurrency, or toCurrency changes: on the TextField's On Change action, call Update Page State and set convertedAmount to the result of convertCurrency. Do the same for both DropDowns' On Change actions.

```
// Custom Function: convertCurrency
// Arguments: ratesJson (String), fromCurrency (String),
//            toCurrency (String), amount (String)
// Return type: String
import 'dart:convert';

String convertCurrency(
  String ratesJson,
  String fromCurrency,
  String toCurrency,
  String amount,
) {
  if (ratesJson.isEmpty || amount.isEmpty) return '0.00';
  final input = double.tryParse(amount);
  if (input == null || input <= 0) return '0.00';

  try {
    final rates = Map<String, dynamic>.from(json.decode(ratesJson) as Map);
    final fromRate = (rates[fromCurrency] as num?)?.toDouble() ?? 1.0;
    final toRate = (rates[toCurrency] as num?)?.toDouble() ?? 1.0;
    // Convert: amount / fromRate * toRate (both relative to USD)
    final result = (input / fromRate) * toRate;
    if (result >= 1000000) return result.toStringAsFixed(0);
    if (result >= 100) return result.toStringAsFixed(2);
    return result.toStringAsFixed(4);
  } catch (_) {
    return 'Error';
  }
}
```

**Expected result:** Typing an amount or changing a currency DropDown instantly updates the converted amount display without any API calls.

### 5. Add a Historical Rate Chart with fl_chart

For the historical chart, create a second API call named GetHistoricalRates using the exchangerate-api.com history endpoint: GET https://v6.exchangerate-api.com/v6/YOUR_API_KEY/history/USD/YEAR/MONTH/DAY. You will need to call this endpoint for each of the last 7 days using a loop or parallel API calls. Store the 7 data points in a Page State variable named historicalRates (List of Doubles). Create a Custom Widget named RateChart that uses the fl_chart package's LineChart. The widget accepts historicalRates (List of Doubles) and currencyPair (String) as parameters. Display the 7 data points as a line chart with date labels on the x-axis and rate values on the y-axis. Place this widget below the converter in a collapsible container.

**Expected result:** A line chart appears below the converter showing the selected currency pair's rate over the past 7 days.

## Complete code example

File: `convert_currency.dart`

```dart
// Custom Function: convertCurrency
// FlutterFlow Custom Functions panel
// Arguments:
//   ratesJson: String (from App State)
//   fromCurrency: String (from Page State)
//   toCurrency: String (from Page State)
//   amount: String (from TextField)
// Return type: String

import 'dart:convert';

String convertCurrency(
  String ratesJson,
  String fromCurrency,
  String toCurrency,
  String amount,
) {
  // Handle empty inputs
  if (ratesJson.isEmpty) return 'Loading...';
  if (amount.isEmpty) return '0.00';

  // Normalize decimal separator for European locales
  final normalizedAmount = amount.replaceAll(',', '.');
  final input = double.tryParse(normalizedAmount);
  if (input == null) return 'Invalid';
  if (input <= 0) return '0.00';

  // Same currency shortcut
  if (fromCurrency == toCurrency) {
    return input.toStringAsFixed(2);
  }

  try {
    final decoded = json.decode(ratesJson);
    final rates = Map<String, dynamic>.from(decoded as Map);

    // Rates are all relative to USD base
    final fromRate = (rates[fromCurrency] as num?)?.toDouble();
    final toRate = (rates[toCurrency] as num?)?.toDouble();

    if (fromRate == null || fromRate == 0) return 'N/A';
    if (toRate == null) return 'N/A';

    // Convert to USD first, then to target currency
    final inUsd = input / fromRate;
    final result = inUsd * toRate;

    // Format based on magnitude
    if (result >= 1000000) {
      return '${(result / 1000000).toStringAsFixed(2)}M';
    } else if (result >= 1000) {
      return result.toStringAsFixed(2);
    } else if (result >= 1) {
      return result.toStringAsFixed(4);
    } else {
      return result.toStringAsFixed(6);
    }
  } catch (e) {
    return 'Error';
  }
}

// Custom Function: getRateForPair
// Returns the direct exchange rate between two currencies
// Arguments: ratesJson (String), fromCurrency (String), toCurrency (String)
// Return type: String
String getRateForPair(String ratesJson, String fromCurrency, String toCurrency) {
  if (ratesJson.isEmpty) return '';
  try {
    final rates = Map<String, dynamic>.from(json.decode(ratesJson) as Map);
    final fromRate = (rates[fromCurrency] as num?)?.toDouble() ?? 1.0;
    final toRate = (rates[toCurrency] as num?)?.toDouble() ?? 1.0;
    final rate = toRate / fromRate;
    return '1 $fromCurrency = ${rate.toStringAsFixed(4)} $toCurrency';
  } catch (_) {
    return '';
  }
}
```

## Common mistakes

- **Calling the exchange rate API on every keystroke in the amount TextField** — A user typing 1234.56 generates 7 API calls in under a second. The free exchangerate-api.com plan allows 1,500 requests per month — a single power user could exhaust the quota in minutes. Fix: Fetch rates once on app start and cache them in App State for 3 hours. The conversion calculation runs entirely in a Custom Function using cached data — no API call needed on keystroke.
- **Storing the exchange rates as a separate App State variable for each currency code (e.g., usdToEur, usdToGbp, usdToJpy...)** — The exchangerate-api.com response contains ~160 currencies. Creating 160 App State variables is not maintainable and makes the Custom Function impossible to update dynamically. Fix: Store the entire conversion_rates JSON object as a single String in App State. Parse it in the Custom Function using dart:convert's json.decode. This keeps App State clean and supports all ~160 currencies.
- **Not handling the case where fromCurrency and toCurrency are the same** — Converting USD to USD should return the exact input amount. Without this check, floating-point arithmetic can return 0.9999999 instead of 1.0. Fix: Add an early return in the Custom Function: if fromCurrency == toCurrency, return the input amount formatted to 2 decimal places.

## Best practices

- Cache exchange rates in persisted App State for 3-6 hours to minimize API calls and support offline usage.
- Always show the last-updated timestamp next to the exchange rate so users know how fresh the data is.
- Handle the same-currency case explicitly in your Custom Function to avoid floating-point rounding errors.
- Support comma as decimal separator for European users by normalizing input in the Custom Function.
- Show a loading indicator while rates are being fetched on first app launch and disable the converter UI until rates are ready.
- Display the direct exchange rate (e.g., '1 USD = 0.9234 EUR') below the result so users can verify the calculation.
- Add a favorites row of commonly used currency pairs at the top of the converter for quick access.

## Frequently asked questions

### Does the free exchangerate-api.com plan work for a production app?

The free plan gives 1,500 requests per month. With caching (one call per user per 3 hours), this supports around 1,500 unique active user sessions per month. For apps with more traffic, upgrade to the paid plan ($9.99/month for 100,000 requests) or switch to Open Exchange Rates.

### How do I update the exchange rates more frequently for a trading app?

Reduce the cache TTL from 3 hours to 15 minutes, and change the App State fetch trigger to run when ratesLastFetched is older than 15 minutes. For real-time rates under 1-minute delay, use a paid Forex API like Fixer.io or Open Exchange Rates, not exchangerate-api.com.

### Can I support cryptocurrencies like Bitcoin and Ethereum?

exchangerate-api.com does not include crypto. Use the CoinGecko API (free, no key required) as a separate API call for crypto rates. Create a second GetCryptoRates API call and merge the results into your ratesJson App State variable in the App Start action.

### How do I show the amount in both currencies at the same time as the user types?

This already works with the TextField On Change action trigger. Every keystroke calls Update Page State with the convertCurrency result, which the result Text widget displays in real time. The Custom Function is synchronous and runs in microseconds so there is no noticeable delay.

### Why does the converter show 'Error' instead of a result?

This usually means ratesJson is empty (rates not yet fetched) or the currency code in the DropDown does not match the key in the API response exactly. Currency codes are case-sensitive — the API uses uppercase codes like USD, EUR, GBP. Check that your DropDown options exactly match the API's currency code format.

### Can I let users save favorite currency pairs?

Yes. Create a Firestore favorites collection with fields: userId, fromCurrency, toCurrency. Add a star IconButton on the converter page that saves the current pair to Firestore. On the converter page load, query the user's favorites and display them as quick-select chips above the DropDowns.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-implement-a-currency-converter-in-flutterflow
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-implement-a-currency-converter-in-flutterflow
