A reference rate tells you what a currency pair is worth on paper. Your card, your ATM, and the merchant terminal each tell a different story — and the gap between them is where travel money disappears.
Disclosure: I built the converter this post is about — a free, browser-only Currency Converter on ToolkitLoop. No signup, no upload of your amount. The design decisions below are the ones I actually made.
Reference data is an aggregation, not a price
The tool uses Frankfurter v2, which aggregates institutional reference data, requested through a server-side cache. That sentence hides three decisions worth unpacking.
First, "reference" is doing real work. A reference rate is a published benchmark for a currency pair, not a price at which anyone will transact with you. Your bank, card network, or ATM settles at its own rate, and the difference is not a rounding error — it is issuer rates, markups, foreign-transaction fees, fixed fees, and timing, all stacked.
Second, the cache. The default cache is one hour, and if the provider is temporarily unavailable, an older usable cache is explicitly labelled as old rather than presented as new. Caching is a correctness decision here, not just a performance one: every cached rate is a rate that is ageing, and the user deserves to see the age.
Third, the request boundary. Only the selected currency pair is requested; the amount never leaves the browser. The server receives currency codes, never the raw amount. That is a small architectural fact with a large consequence: there is no conversion history to leak, no per-user rate log to secure, and no account system to maintain.
// Amount × reference rate = converted result.
// The request carries the pair, never the amount.
async function getReferenceRate(from, to) {
const res = await fetch(`/api/rates?from=${from}&to=${to}`);
const { rate, rateDate, fetchedAt, cacheStatus } = await res.json();
return { rate, rateDate, fetchedAt, cacheStatus };
}
function convert(amount, rate) {
return amount * rate; // display rounding happens at render, not here
}
Rate date vs fetch time: two clocks
The page shows the rate date separately from the fetch time, and the distinction matters more than it looks. The rate date is when the provider published the rate. The fetch time is when this site retrieved it. A pipeline that conflates them will happily display yesterday's rate with today's timestamp, and nobody will notice until a user compares it against their card statement.
If you build anything that displays financial data, keep both clocks visible in your data model, not just in the UI. The moment they collapse into a single "updated at" field, you have lost the ability to answer the only question that matters: how old is the number I am looking at?
DCC: the merchant's rate, not yours
Dynamic currency conversion (DCC) is an option that lets a merchant or ATM charge you in your home currency. Its exchange rate and fees can be less favourable than paying in the local currency — because the party setting the rate is the merchant or the ATM operator, not your card network.
The mechanism is simple; the framing is the trap. The terminal shows you a familiar number in your home currency, which feels like transparency. What it does not show is the markup inside that number. Declining DCC at an ATM does not cancel the withdrawal — it just lets your bank do the conversion instead. At a card terminal, choosing the local currency removes one invisible markup and leaves only your card's terms, which you can check in advance. Declining DCC does not guarantee the cheapest outcome; it guarantees that only one party's terms apply instead of two.
What is deliberately missing
Two features are absent on purpose, and both are documented on the page rather than hidden.
Historical-date and trend analysis do not exist yet. This first release focuses on a transparent current/reference conversion, and history will be added to the same tool rather than as empty or duplicate pages. A converter that fakes history with today's rate would be worse than one that admits the gap.
There is also no fee mode yet. Card and ATM fees vary by product, location, and transaction, so the tool does not assume a fixed percentage. A future fee mode will let you enter your own assumptions and clearly distinguish its estimate from the reference rate. Until then, the correct mental model is two numbers, not one: the reference result for planning, and your card's terms for the final cost.
The rounding question
Swapping the currencies recalculates immediately from the loaded reference rate, and the displayed result is rounded for readability. The underlying calculation keeps full precision — but that raises a question I have not fully settled: when a user converts a 14-line trip budget, should each line be rounded, or should only the total be rounded once at the end? Per-line rounding matches bank statements; single rounding at the end is mathematically cleaner. The difference is small per line and real across a trip.
How do you handle it in your own tools — round at display, round at storage, or never round until the final total? And have you ever caught a DCC markup only after the statement arrived? I am curious which of the three rates — reference, card, or merchant — surprised you most.
About the author
- Founder of ToolkitLoop (toolkitloop.com) — 30 free online tools that run 100% in your browser. No sign-ups, no uploads, private by design.
Comments
Join the discussionNo comments yet. Be the first to comment.
