Preact hooks and a context provider for the UniRate currency-exchange API.
useRate(from, to)— single exchange rateuseRates(from)— full rate table for a baseuseConversion(from, to, amount)— converted amountuseCurrencies()— list of supported codes (~600)useVatRates(country?)— EU/global VAT ratesuseHistoricalRate(date, from, to)— historical rate (Pro)useUniRate()— grab the client for imperative calls<UniRateProvider>— one client for the whole tree- Zero runtime deps. Native
fetch. AbortController cleanup on unmount.
Built on preact + preact/hooks. preact is a peer dep (>=10), so the package adds nothing to your bundle beyond a few hundred lines of hook code.
npm install @unirate/preact
# or
pnpm add @unirate/preact
# or
yarn add @unirate/preactPeer dep: preact >=10. Requires Node 18.17+ for build/server use.
import { UniRateProvider, useRate, useConversion } from "@unirate/preact";
export function App() {
return (
<UniRateProvider apiKey={import.meta.env.VITE_UNIRATE_API_KEY}>
<Cart />
</UniRateProvider>
);
}
function Cart() {
const { data: rate, loading } = useRate("USD", "EUR");
const { data: total } = useConversion("USD", "EUR", 42.99);
if (loading) return <p>Loading…</p>;
return (
<p>
1 USD = {rate} EUR. Your total: {total} EUR
</p>
);
}Get a free API key at unirateapi.com — the free tier covers latest rates, conversions, and VAT rates for ~600 currencies including crypto. Historical rates, time-series, and commodity feeds require Pro.
Every hook returns the same shape:
interface QueryState<T> {
data: T | undefined;
error: Error | undefined;
loading: boolean; // true while a request is in flight
refetch: () => void; // re-run the request manually
}Every hook also accepts an options object:
{
client?: UniRateClient; // override the provider's client
enabled?: boolean; // skip the fetch until true (default true)
}const { data, error, loading } = useRate("USD", "EUR");
// data: 0.92Returns the full rate table for a base.
const { data } = useRates("USD");
// data: { EUR: 0.92, GBP: 0.80, JPY: 154.21, ... }const { data } = useConversion("USD", "EUR", 100);
// data: 92.50const { data: codes } = useCurrencies();
// data: ["USD", "EUR", "GBP", "JPY", "BTC", ...]Pass a country code for one country, or undefined for the full table. The
result is a discriminated union — narrow on vat_data vs vat_rates.
const { data } = useVatRates("DE");
// data: { country: "DE", vat_data: { country_code: "DE", country_name: "Germany", vat_rate: 19 } }
const { data: all } = useVatRates(undefined);
// data: { total_countries: 50, date: "…", vat_rates: { DE: { vat_rate: 19 }, ... } }Pro endpoint. Returns
ProRequiredErroron the free tier.
const { data } = useHistoricalRate("2025-01-01", "USD", "EUR");
// data: 0.851Returns the UniRateClient from the nearest provider. Use it when you want to
call the client imperatively from an event handler or effect rather than via a
query hook.
import { useUniRate } from "@unirate/preact";
function ConvertButton() {
const client = useUniRate();
return (
<button
onClick={async () => {
const eur = await client.convert("EUR", 100, "USD");
console.log(eur);
}}
>
Convert
</button>
);
}Putting an API key directly in client-side Preact means the key ships to every visitor's browser. For production deployments you have two options:
-
Proxy through your backend. Point
baseUrlat your own endpoint and have that endpoint hold the realUNIRATE_API_KEY:<UniRateProvider apiKey="placeholder" baseUrl="/api/unirate" />
The placeholder still passes the client's "apiKey is required" check; your server inspects requests and inserts the real key before forwarding to
api.unirateapi.com. -
Free-tier-only public key. Free-tier UniRate keys are rate-limited per key; if a leaked key only unlocks endpoints you don't mind being shared, shipping it client-side is acceptable.
Server-side (SSR, prerender, or any Node context): you can use the raw UniRateClient directly without the provider.
import { UniRateClient } from "@unirate/preact/client";
const client = new UniRateClient({ apiKey: process.env.UNIRATE_API_KEY! });
const rate = await client.getRate("USD", "EUR");The same error classes the hooks expose are also exported for instanceof checks:
AuthenticationError— 401, bad / missing keyRateLimitError— 429InvalidCurrencyError— 404, unknown currency codeInvalidRequestError— 400, bad paramsProRequiredError— 403, endpoint requires a Pro subscriptionUniRateError— base class for any other failure
import { InvalidCurrencyError } from "@unirate/preact";
const { error } = useRate("USD", "XYZ");
if (error instanceof InvalidCurrencyError) {
return <p>Unsupported currency.</p>;
}UniRate ships official client libraries and framework integrations across the ecosystem. The repos below are all maintained under the UniRate-API org.
- Languages: Python · Node.js / TypeScript · Go · Rust · Java · Ruby · PHP · .NET · Swift
- Web frameworks: React · Vue · Angular · NestJS · Django / Wagtail · FastAPI · Flask
- Static-site generators: Astro · Eleventy · Hugo
- Data / orchestration: Airflow · dbt · LangChain
- Workflow / no-code: n8n · Google Sheets · MCP server
- Editors / tools: VS Code · Obsidian
Get a free API key at unirateapi.com.
MIT © Unirate Team