FX & Analytics Currency

Roll multi-currency revenue into one reporting currency for analytics, using a daily FX rate snapshotted onto each order, without ever changing what a customer is charged.

A store that sells into several regions takes money in several currencies. FX & analytics currency is how the dashboard rolls that mixed revenue into numbers a merchant can read, either kept split per currency, or converted into a single reporting currency using a daily exchange rate.

FX here is analytics-only. Conversion never changes what a customer is charged, because the buyer always pays the order's own currency. FX only affects how revenue is displayed in reports.

The two modes

A store's analyticsCurrencyMode decides how multi-currency revenue is summed:

  • NATIVE (default): revenue is grouped by currency, with no conversion. A report shows one row per currency (€4,200 / $3,100 / ₪9,000). Nothing is added across currencies, so there's no FX error to introduce. This is the existing behavior for every store that never touches the setting.
  • AGGREGATE: every order is converted into the store's reportingCurrency so the dashboard can show a single total. The reporting currency is only meaningful in this mode; when it's null/unset it defaults to the store's default region currency.

The merchant chooses the mode (and, in AGGREGATE, the reporting currency) under Settings → Analytics Display.

Daily FX rates

Conversion uses an FxRate table with one row per (store, fromCurrency, toCurrency, effectiveDate), where effectiveDate is date-only. A daily cron fetches rates from the configured fxProvider and writes a fresh row per pair:

  • ECB: the European Central Bank reference rates (free; the default).
  • OPENEXCHANGE: Open Exchange Rates (provider key required).
  • MANUAL: no cron; the merchant enters rates by hand. Manual rates can't be dated in the future and must be greater than zero.

The rate used to convert an order is the newest row on or before the order's date (from → to as of date). Same-currency conversions are always 1. If no rate row exists for a pair, the conversion resolves to null, and the dashboard leaves that order's converted value blank rather than guessing or blocking the order.

Per-order snapshot

FX is captured once, at order creation, and frozen onto the order, so later rate changes never rewrite historical revenue. Each order stores three fields:

  • reportingCurrency: the currency the order was converted into (null in NATIVE mode or when no rate was available).
  • fxRateToReporting: the exact rate applied (order currency → reporting currency), or null.
  • reportingAmount: totalAmount × fxRateToReporting, the order's value in the reporting currency, or null.

Because the snapshot lives on the order, an AGGREGATE report is a plain sum of reportingAmount, with no rate lookups at read time, and the figures are reproducible forever regardless of how today's rate moves.

The order's own totalAmount / currency are untouched. That is what the customer paid and what every refund, payout, and invoice uses. reportingAmount sits beside it purely for analytics.

See also Regions for the currencies these orders arrive in.