npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@allratestoday/react-currency-localizer-realtime

v2.0.0

Published

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.

Downloads

177

Readme

Scoped mirror of react-currency-localizer-realtime published by the AllRatesToday org — same code, same versions.

react-currency-localizer-realtime

npm version TypeScript Tests license zero dependencies

Show prices in your visitor's local currency. No API key needed to start.

import { LocalizedPrice } from '@allratestoday/react-currency-localizer-realtime'

<LocalizedPrice basePrice={99.99} baseCurrency="USD" />
// A visitor in Tokyo sees "¥15,300", in Berlin "86,20 €", in London "£75.99"

That's the whole integration. Country detection and the exchange rate both come from AllRatesToday — keyless, free, no signup.

See it running on a real pricing page: allratestoday.com/pricing (it uses this same logic in keyed mode).

Two modes

| | Keyless (default) | With API key | |---|---|---| | Setup | none | apiKey="art_live_…"free key | | Rates | ECB daily reference rates | Real-time mid-market, updated every minute | | 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+ | | Cost | Free, forever | Free tier, paid plans for volume | | Condition | Visible "Rates by AllRatesToday" link (rendered for you) | none |

Start keyless. Add a key when you need a currency the ECB doesn't publish, or real-time rates for checkout-grade accuracy.

Features

  • 🆓 Zero setup — no signup, no key, no third-party geo-IP service
  • 🌍 Automatic currency detection — from the visitor's IP, via Cloudflare's country header on allratestoday.com (no ipapi.co dependency, no daily cap)
  • Real-time upgrade path — add a key for 60-second mid-market rates and 160+ currencies
  • 🧠 Aggressive caching — one ECB table fetch per hour serves every price on the page; geo cached 24h
  • 🔀 Hook, batch hook, or component — pick the level of control you want
  • 🛡️ Graceful fallbacks — the original price is always shown if anything fails
  • 🔷 TypeScript, 📦 zero runtime deps, 🪶 ~4 KB gzipped

Installation

npm install @allratestoday/react-currency-localizer-realtime
# yarn add / pnpm add @allratestoday/react-currency-localizer-realtime

React 17+ is the only peer dependency.

Quick start

1. Component (simplest)

import { LocalizedPrice } from '@allratestoday/react-currency-localizer-realtime'

function ProductCard() {
  return (
    <div>
      <h3>Premium Plan</h3>
      <LocalizedPrice basePrice={99.99} baseCurrency="USD" />
    </div>
  )
}

Keyless renders ¥15,300 ECB rates via AllRatesToday. Pass apiKey and the attribution disappears.

2. Hook (full control)

import { useCurrencyConverter, RatesAttribution } from '@allratestoday/react-currency-localizer-realtime'

function ProductPrice({ price }: { price: number }) {
  const { convertedPrice, localCurrency, rateSource, isLoading, error } = useCurrencyConverter({
    basePrice: price,
    baseCurrency: 'USD',
  })

  if (isLoading) return <span>…</span>
  if (error) return <span>${price}</span>

  return (
    <span>
      {new Intl.NumberFormat(undefined, { style: 'currency', currency: localCurrency! }).format(convertedPrice!)}
      <RatesAttribution rateSource={rateSource} />
    </span>
  )
}

3. Batch conversion (product lists, pricing tables)

One rate lookup, unlimited prices:

import { useCurrencyLocalizer, RatesAttribution } from '@allratestoday/react-currency-localizer-realtime'

function ProductList({ products }) {
  const { convertAndFormat, isReady, rateSource } = useCurrencyLocalizer({ baseCurrency: 'USD' })

  return (
    <>
      <ul>
        {products.map(p => (
          <li key={p.id}>{p.name}: {isReady ? convertAndFormat(p.price) : '…'}</li>
        ))}
      </ul>
      <RatesAttribution rateSource={rateSource} />
    </>
  )
}

4. Real-time mode

<LocalizedPrice
  basePrice={99.99}
  baseCurrency="USD"
  apiKey={import.meta.env.VITE_ALLRATESTODAY_KEY}   // CRA: REACT_APP_…, Next.js: NEXT_PUBLIC_…
/>

Same 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.


API reference

useCurrencyConverter(options)

| Option | Type | Required | Description | |---|---|---|---| | basePrice | number | Yes | Price in the base currency | | baseCurrency | string | Yes | ISO 4217 code, case-insensitive | | apiKey | string | No | Enables real-time mode. Omit for keyless ECB mode | | manualCurrency | string | No | Skip detection, use this currency | | geoEndpoint | string | No | Any URL returning { currency }. Default https://allratestoday.com/api/open/geo | | onSuccess | (result) => void | No | Called with { convertedPrice, localCurrency, exchangeRate, rateSource, rateDate } | | onError | (error) => void | No | |

Returns { convertedPrice, localCurrency, baseCurrency, exchangeRate, rateSource, rateDate, isLoading, error }.

  • rateSource is 'ecb' (keyless) or 'realtime' (keyed).
  • rateDate is YYYY-MM-DD for ECB, an ISO timestamp for real-time.

useCurrencyLocalizer(options)

Same options minus basePrice, plus onReady. Returns { convert, format, convertAndFormat, localCurrency, baseCurrency, exchangeRate, rateSource, rateDate, isLoading, isReady, error }.

<LocalizedPrice />

All hook options as props, plus:

| Prop | Type | Description | |---|---|---| | attribution | boolean | Default true keyless, false keyed. Set false and render <RatesAttribution /> once for lists | | loadingComponent | ReactNode | Custom loading state | | errorComponent | (error, basePrice, baseCurrency) => ReactNode | Custom error state (default: original price) | | formatPrice | (price, currency) => string | Custom formatter |

<RatesAttribution />

The "Rates by AllRatesToday" link. Props: rateSource, className, style. Render it once per page when you use the hooks keyless.

detectCurrency(geoEndpoint?) / fetchRate(apiKey, from, to)

The underlying functions, exported for non-React use or custom hooks. fetchRate returns { rate, source, date }.


How keyless mode works

  1. Currency detectionGET 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.
  2. RateGET 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.
  3. Attribution — the endpoint is free because embeds link back. LocalizedPrice renders the link for you; with hooks, add <RatesAttribution /> once.

If 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.

Caching

| Data | Where | TTL | |---|---|---| | Detected currency | localStorage | 24 h | | ECB table (keyless) | memory + localStorage | 1 h | | Real-time rate (keyed) | memory | 1 h | | Same-currency | instant 1 | — |

SSR (Next.js, Remix)

Detection uses the requesting IP, so on the server it reflects the server's location. Convert on the client only:

const [isClient, setIsClient] = useState(false)
useEffect(() => setIsClient(true), [])

<LocalizedPrice basePrice={99.99} baseCurrency="USD" manualCurrency={isClient ? undefined : 'USD'} />

Migrating from 1.x

  • apiKey is now optional. Existing keyed code works unchanged.
  • fetchRate() now returns { rate, source, date } instead of a bare number (only matters if you called it directly).
  • onSuccess receives two extra fields: rateSource, rateDate.
  • Default geolocation moved from ipapi.co to allratestoday.com/api/open/geo. Pass geoEndpoint="https://ipapi.co/json/" to keep the old behaviour.
  • New: RatesAttribution component, attribution prop on LocalizedPrice.

Testing

npm test               # 42 unit tests, mocked network
npm run test:coverage

Links

License

MIT