{"_id":"@allratestoday/react-currency-localizer-realtime","name":"@allratestoday/react-currency-localizer-realtime","dist-tags":{"latest":"2.0.0"},"versions":{"2.0.0":{"name":"@allratestoday/react-currency-localizer-realtime","version":"2.0.0","description":"React hooks and components that show prices in your visitor's local currency. Works with no API key (free daily ECB rates) — add a free AllRatesToday key for real-time mid-market rates across 160+ currencies.","main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"build":"tsup src/index.ts --format cjs,esm --dts --external react","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage"},"keywords":["react","currency","converter","hook","geolocation","exchange-rate","localization","pricing","internationalization","allratestoday","mid-market-rate","free","no-api-key","ecb","central-bank","local-currency","price-localization"],"author":{"name":"AllRatesToday","email":"info@allratestoday.com"},"license":"MIT","homepage":"https://allratestoday.com","repository":{"type":"git","url":"git+https://github.com/allratestoday/exchange-rates-api.git","directory":"sdks/react"},"peerDependencies":{"react":">=17.0.0"},"devDependencies":{"@testing-library/react":"^16.0.0","@types/react":"^18.3.0","@vitest/coverage-v8":"^4.1.4","jsdom":"^25.0.0","react":"^18.3.0","react-dom":"^18.3.0","tsup":"^8.0.0","typescript":"^5.0.0","vitest":"^4.1.4"},"publishConfig":{"access":"public"},"bugs":{"url":"https://github.com/allratestoday/exchange-rates-api/issues"},"_id":"@allratestoday/react-currency-localizer-realtime@2.0.0","_nodeVersion":"22.22.1","_npmVersion":"9.2.0","dist":{"integrity":"sha512-rTXXUs3daMQTYYLeGpiaK+hBUpzE1yNYOixOm8ilfIEkMDsaXZvMGWn7kTKtDdvd3TLm0pxgcuRVaEN5U/CY6w==","shasum":"a1db065f61bceb398d8f28577412799e80588c47","tarball":"https://registry.npmjs.org/@allratestoday/react-currency-localizer-realtime/-/react-currency-localizer-realtime-2.0.0.tgz","fileCount":6,"unpackedSize":55166,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCul7Qi312SBiBE9gEURr2/92qI1mcirES8Qj4cgc3CAQIgXO47lOH5h5kcUgGy5Q+z7icUfLditzRhcJ0WlK89+pc="}]},"_npmUser":{"name":"chathurangac8","email":"basnayakac8@gmail.com"},"directories":{},"maintainers":[{"name":"chathurangac8","email":"basnayakac8@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-currency-localizer-realtime_2.0.0_1787947809144_0.6822302420918076"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-28T20:10:08.868Z","2.0.0":"2026-08-28T20:10:09.274Z","modified":"2026-08-28T20:10:09.566Z"},"maintainers":[{"name":"chathurangac8","email":"basnayakac8@gmail.com"}],"description":"React hooks and components that show prices in your visitor's local currency. Works with no API key (free daily ECB rates) — add a free AllRatesToday key for real-time mid-market rates across 160+ currencies.","homepage":"https://allratestoday.com","keywords":["react","currency","converter","hook","geolocation","exchange-rate","localization","pricing","internationalization","allratestoday","mid-market-rate","free","no-api-key","ecb","central-bank","local-currency","price-localization"],"repository":{"type":"git","url":"git+https://github.com/allratestoday/exchange-rates-api.git","directory":"sdks/react"},"author":{"name":"AllRatesToday","email":"info@allratestoday.com"},"bugs":{"url":"https://github.com/allratestoday/exchange-rates-api/issues"},"license":"MIT","readme":"> Scoped mirror of [`react-currency-localizer-realtime`](https://www.npmjs.com/package/react-currency-localizer-realtime) published by the AllRatesToday org — same code, same versions.\n\n# react-currency-localizer-realtime\n\n[![npm version](https://img.shields.io/npm/v/react-currency-localizer-realtime.svg)](https://www.npmjs.com/package/react-currency-localizer-realtime)\n[![TypeScript](https://badges.frapsoft.com/typescript/code/typescript.svg?v=101)](https://www.typescriptlang.org/)\n[![Tests](https://github.com/allratestoday/exchange-rates-api/actions/workflows/test.yml/badge.svg)](https://github.com/allratestoday/exchange-rates-api/actions/workflows/test.yml)\n[![license](https://img.shields.io/npm/l/react-currency-localizer-realtime.svg)](https://github.com/allratestoday/exchange-rates-api/blob/main/LICENSE)\n[![zero dependencies](https://img.shields.io/badge/runtime_deps-0-brightgreen.svg)](https://www.npmjs.com/package/react-currency-localizer-realtime)\n\n**Show prices in your visitor's local currency. No API key needed to start.**\n\n```tsx\nimport { LocalizedPrice } from '@allratestoday/react-currency-localizer-realtime'\n\n<LocalizedPrice basePrice={99.99} baseCurrency=\"USD\" />\n// A visitor in Tokyo sees \"¥15,300\", in Berlin \"86,20 €\", in London \"£75.99\"\n```\n\nThat's the whole integration. Country detection and the exchange rate both come from [AllRatesToday](https://allratestoday.com) — keyless, free, no signup.\n\nSee it running on a real pricing page: [allratestoday.com/pricing](https://allratestoday.com/pricing) (it uses this same logic in keyed mode).\n\n## Two modes\n\n| | **Keyless** (default) | **With API key** |\n|---|---|---|\n| Setup | none | `apiKey=\"art_live_…\"` — [free key](https://allratestoday.com/register) |\n| Rates | ECB daily reference rates | Real-time mid-market, updated every minute |\n| Currencies | ~30 (USD, GBP, JPY, CHF, CAD, AUD, CNY, INR, BRL, MXN, KRW, SEK, NOK, DKK, PLN, CZK, HUF, RON, TRY, ZAR, SGD, HKD, NZD, ILS, IDR, MYR, PHP, THB, ISK) | 160+ |\n| Cost | Free, forever | Free tier, paid plans for volume |\n| Condition | Visible \"Rates by AllRatesToday\" link (rendered for you) | none |\n\nStart keyless. Add a key when you need a currency the ECB doesn't publish, or real-time rates for checkout-grade accuracy.\n\n## Features\n\n- 🆓 **Zero setup** — no signup, no key, no third-party geo-IP service\n- 🌍 **Automatic currency detection** — from the visitor's IP, via Cloudflare's country header on allratestoday.com (no ipapi.co dependency, no daily cap)\n- ⚡ **Real-time upgrade path** — add a key for 60-second mid-market rates and 160+ currencies\n- 🧠 **Aggressive caching** — one ECB table fetch per hour serves every price on the page; geo cached 24h\n- 🔀 **Hook, batch hook, or component** — pick the level of control you want\n- 🛡️ **Graceful fallbacks** — the original price is always shown if anything fails\n- 🔷 **TypeScript**, 📦 **zero runtime deps**, 🪶 **~4 KB gzipped**\n\n## Installation\n\n```bash\nnpm install @allratestoday/react-currency-localizer-realtime\n# yarn add / pnpm add @allratestoday/react-currency-localizer-realtime\n```\n\nReact 17+ is the only peer dependency.\n\n## Quick start\n\n### 1. Component (simplest)\n\n```tsx\nimport { LocalizedPrice } from '@allratestoday/react-currency-localizer-realtime'\n\nfunction ProductCard() {\n  return (\n    <div>\n      <h3>Premium Plan</h3>\n      <LocalizedPrice basePrice={99.99} baseCurrency=\"USD\" />\n    </div>\n  )\n}\n```\n\nKeyless renders `¥15,300 ECB rates via AllRatesToday`. Pass `apiKey` and the attribution disappears.\n\n### 2. Hook (full control)\n\n```tsx\nimport { useCurrencyConverter, RatesAttribution } from '@allratestoday/react-currency-localizer-realtime'\n\nfunction ProductPrice({ price }: { price: number }) {\n  const { convertedPrice, localCurrency, rateSource, isLoading, error } = useCurrencyConverter({\n    basePrice: price,\n    baseCurrency: 'USD',\n  })\n\n  if (isLoading) return <span>…</span>\n  if (error) return <span>${price}</span>\n\n  return (\n    <span>\n      {new Intl.NumberFormat(undefined, { style: 'currency', currency: localCurrency! }).format(convertedPrice!)}\n      <RatesAttribution rateSource={rateSource} />\n    </span>\n  )\n}\n```\n\n### 3. Batch conversion (product lists, pricing tables)\n\nOne rate lookup, unlimited prices:\n\n```tsx\nimport { useCurrencyLocalizer, RatesAttribution } from '@allratestoday/react-currency-localizer-realtime'\n\nfunction ProductList({ products }) {\n  const { convertAndFormat, isReady, rateSource } = useCurrencyLocalizer({ baseCurrency: 'USD' })\n\n  return (\n    <>\n      <ul>\n        {products.map(p => (\n          <li key={p.id}>{p.name}: {isReady ? convertAndFormat(p.price) : '…'}</li>\n        ))}\n      </ul>\n      <RatesAttribution rateSource={rateSource} />\n    </>\n  )\n}\n```\n\n### 4. Real-time mode\n\n```tsx\n<LocalizedPrice\n  basePrice={99.99}\n  baseCurrency=\"USD\"\n  apiKey={import.meta.env.VITE_ALLRATESTODAY_KEY}   // CRA: REACT_APP_…, Next.js: NEXT_PUBLIC_…\n/>\n```\n\nSame API — the key switches the rate source from the daily ECB table to `/api/v1/rates` (real-time, 160+ currencies) and drops the attribution requirement.\n\n---\n\n## API reference\n\n### `useCurrencyConverter(options)`\n\n| Option | Type | Required | Description |\n|---|---|---|---|\n| `basePrice` | `number` | Yes | Price in the base currency |\n| `baseCurrency` | `string` | Yes | ISO 4217 code, case-insensitive |\n| `apiKey` | `string` | No | Enables real-time mode. Omit for keyless ECB mode |\n| `manualCurrency` | `string` | No | Skip detection, use this currency |\n| `geoEndpoint` | `string` | No | Any URL returning `{ currency }`. Default `https://allratestoday.com/api/open/geo` |\n| `onSuccess` | `(result) => void` | No | Called with `{ convertedPrice, localCurrency, exchangeRate, rateSource, rateDate }` |\n| `onError` | `(error) => void` | No | |\n\nReturns `{ convertedPrice, localCurrency, baseCurrency, exchangeRate, rateSource, rateDate, isLoading, error }`.\n\n- `rateSource` is `'ecb'` (keyless) or `'realtime'` (keyed).\n- `rateDate` is `YYYY-MM-DD` for ECB, an ISO timestamp for real-time.\n\n### `useCurrencyLocalizer(options)`\n\nSame options minus `basePrice`, plus `onReady`. Returns `{ convert, format, convertAndFormat, localCurrency, baseCurrency, exchangeRate, rateSource, rateDate, isLoading, isReady, error }`.\n\n### `<LocalizedPrice />`\n\nAll hook options as props, plus:\n\n| Prop | Type | Description |\n|---|---|---|\n| `attribution` | `boolean` | Default `true` keyless, `false` keyed. Set `false` and render `<RatesAttribution />` once for lists |\n| `loadingComponent` | `ReactNode` | Custom loading state |\n| `errorComponent` | `(error, basePrice, baseCurrency) => ReactNode` | Custom error state (default: original price) |\n| `formatPrice` | `(price, currency) => string` | Custom formatter |\n\n### `<RatesAttribution />`\n\nThe \"Rates by AllRatesToday\" link. Props: `rateSource`, `className`, `style`. Render it once per page when you use the hooks keyless.\n\n### `detectCurrency(geoEndpoint?)` / `fetchRate(apiKey, from, to)`\n\nThe underlying functions, exported for non-React use or custom hooks. `fetchRate` returns `{ rate, source, date }`.\n\n---\n\n## How keyless mode works\n\n1. **Currency detection** — `GET https://allratestoday.com/api/open/geo` returns `{ country, currency }` from Cloudflare's per-request country header. No third-party service, no key, no quota. Cached in `localStorage` for 24 h.\n2. **Rate** — `GET https://allratestoday.com/api/open/central-bank/ecb` returns the ECB's daily EUR reference table (edge-cached, keyless, CORS-open). Any pair is cross-derived: `USD→GBP = (EUR→GBP) / (EUR→USD)`. One fetch per hour serves every price on the page.\n3. **Attribution** — the endpoint is free because embeds link back. `LocalizedPrice` renders the link for you; with hooks, add `<RatesAttribution />` once.\n\nIf the visitor's currency isn't in the ECB table (e.g. NGN, PKR, VND), the hook errors with a clear message and `LocalizedPrice` falls back to the base price. Add an `apiKey` to cover 160+ currencies.\n\n## Caching\n\n| Data | Where | TTL |\n|---|---|---|\n| Detected currency | `localStorage` | 24 h |\n| ECB table (keyless) | memory + `localStorage` | 1 h |\n| Real-time rate (keyed) | memory | 1 h |\n| Same-currency | instant `1` | — |\n\n## SSR (Next.js, Remix)\n\nDetection uses the *requesting* IP, so on the server it reflects the server's location. Convert on the client only:\n\n```tsx\nconst [isClient, setIsClient] = useState(false)\nuseEffect(() => setIsClient(true), [])\n\n<LocalizedPrice basePrice={99.99} baseCurrency=\"USD\" manualCurrency={isClient ? undefined : 'USD'} />\n```\n\n## Migrating from 1.x\n\n- `apiKey` is now optional. Existing keyed code works unchanged.\n- `fetchRate()` now returns `{ rate, source, date }` instead of a bare number (only matters if you called it directly).\n- `onSuccess` receives two extra fields: `rateSource`, `rateDate`.\n- Default geolocation moved from ipapi.co to `allratestoday.com/api/open/geo`. Pass `geoEndpoint=\"https://ipapi.co/json/\"` to keep the old behaviour.\n- New: `RatesAttribution` component, `attribution` prop on `LocalizedPrice`.\n\n## Testing\n\n```bash\nnpm test               # 42 unit tests, mocked network\nnpm run test:coverage\n```\n\n## Links\n\n- [Live example — allratestoday.com/pricing](https://allratestoday.com/pricing)\n- [Keyless ECB endpoint docs](https://allratestoday.com/official-rates-widget/)\n- [Get a free API key](https://allratestoday.com/register) · [API docs](https://allratestoday.com/developers)\n- [Core SDK (Node.js)](https://www.npmjs.com/package/@allratestoday/sdk) · [GitHub](https://github.com/allratestoday/exchange-rates-api)\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-56eb24b4c4149e3b674ba7d5161824a3"}