A live currency converter with real exchange rates, instant typing conversion, popular pairs rate card, and support for 150+ currencies — no API key needed.
open.er-api.com offers a completely free endpoint with no API key required.
const BASE_URL = 'https://open.er-api.com/v6/latest/USD';
async function fetchRates() {
try {
const res = await fetch(BASE_URL);
const data = await res.json();
if (data.result !== 'success') throw new Error('API error');
const rates = data.rates;
console.log(`Loaded ${Object.keys(rates).length} currencies`);
console.log(`1 USD = ${rates.INR} INR`);
console.log(`1 USD = ${rates.EUR} EUR`);
return rates;
} catch (err) {
console.error('Failed to fetch rates:', err);
return null;
}
}
fetchRates().then(r => console.log(r));
Select currencies from dropdowns, type an amount, and see the conversion instantly.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Currency Converter</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; }
body { font-family:'Segoe UI',sans-serif; background:#0f172a; color:#fff; min-height:100vh; display:flex; align-items:center; justify-content:center; padding:20px; }
.card { background:#1e293b; border-radius:20px; padding:36px; max-width:440px; width:100%; }
h1 { font-size:1.4rem; text-align:center; margin-bottom:24px; }
.row { display:flex; gap:10px; margin-bottom:16px; }
.col { flex:1; display:flex; flex-direction:column; gap:6px; }
label { font-size:0.75rem; color:#94a3b8; font-weight:600; text-transform:uppercase; letter-spacing:0.05em; }
input, select { padding:12px 14px; background:#0f172a; border:1px solid #334155; color:#fff; border-radius:10px; font-size:0.95rem; width:100%; }
input:focus, select:focus { outline:none; border-color:#3b82f6; }
.swap-btn { background:#334155; border:none; color:#94a3b8; font-size:1.3rem; padding:10px; border-radius:10px; cursor:pointer; margin-top:18px; flex-shrink:0; }
.swap-btn:hover { background:#3b82f6; color:#fff; }
.rate-info { text-align:center; color:#64748b; font-size:0.82rem; margin-top:12px; }
.popular { margin-top:28px; }
.popular h3 { font-size:0.8rem; color:#64748b; text-transform:uppercase; letter-spacing:0.06em; margin-bottom:12px; }
.pairs-grid { display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.pair { background:#0f172a; border-radius:10px; padding:12px 14px; }
.pair .pair-label { font-size:0.75rem; color:#64748b; margin-bottom:2px; }
.pair .pair-rate { font-weight:700; font-size:0.95rem; }
</style>
</head>
<body>
<?php require_once __DIR__ . '/../promo_banner.php'; ?>
<div class="card">
<h1>💱 Currency Converter</h1>
<div class="row">
<div class="col"><label>Amount</label><input type="number" id="amount" value="1" min="0" oninput="convert()"></div>
<div class="col"><label>From</label><select id="from" onchange="convert()"></select></div>
<button class="swap-btn" onclick="swapCurrencies()" title="Swap">⇄</button>
<div class="col"><label>To</label><select id="to" onchange="convert()"></select></div>
</div>
<input type="text" id="result" readonly placeholder="Result..." style="font-size:1.3rem;font-weight:700;text-align:center;margin-bottom:8px">
<div class="rate-info" id="rateInfo">Loading rates...</div>
<div class="popular">
<h3>Popular pairs (1 USD =)</h3>
<div class="pairs-grid" id="popularGrid"></div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
Fetch rates, populate selects, convert on input, and show popular pairs.
// app.js
const POPULAR = ['EUR','GBP','INR','JPY','CAD','AUD','CHF','CNY'];
let rates = {};
async function init() {
try {
const res = await fetch('https://open.er-api.com/v6/latest/USD');
const data = await res.json();
rates = data.rates;
populateSelects();
showPopularPairs();
convert();
} catch {
document.getElementById('rateInfo').textContent = 'Failed to load rates. Check your connection.';
}
}
function populateSelects() {
const currencies = Object.keys(rates).sort();
['from','to'].forEach((id, i) => {
const sel = document.getElementById(id);
currencies.forEach(c => {
const opt = document.createElement('option');
opt.value = opt.textContent = c;
if ((i === 0 && c === 'USD') || (i === 1 && c === 'EUR')) opt.selected = true;
sel.appendChild(opt);
});
});
}
function convert() {
const amount = parseFloat(document.getElementById('amount').value);
const fromCurr = document.getElementById('from').value;
const toCurr = document.getElementById('to').value;
if (isNaN(amount) || !rates[fromCurr] || !rates[toCurr]) return;
const result = (amount / rates[fromCurr]) * rates[toCurr];
document.getElementById('result').value = result.toFixed(4) + ' ' + toCurr;
const rate = (rates[toCurr] / rates[fromCurr]).toFixed(6);
document.getElementById('rateInfo').textContent = `1 ${fromCurr} = ${rate} ${toCurr}`;
}
function swapCurrencies() {
const f = document.getElementById('from'); const t = document.getElementById('to');
[f.value, t.value] = [t.value, f.value];
convert();
}
function showPopularPairs() {
const grid = document.getElementById('popularGrid');
POPULAR.forEach(c => {
const div = document.createElement('div'); div.className = 'pair';
div.innerHTML = `<div class="pair-label">USD/${c}</div><div class="pair-rate">${rates[c]?.toFixed(4) || '–'}</div>`;
grid.appendChild(div);
});
}
init();
A live, fully functional currency converter with real exchange rates in under 100 lines — no server, no API key, no fees. The same convert() function pattern works in any app that needs unit conversion.
Spotted a bug, broken code, or something that doesn't look right? Tell us what's off and we'll fix it.