Multi-currency auto-conversion

Sell in EUR, USD and GBP, report all of them in one currency. Beaconry hooks into the dispatch pipeline and rewrites value + every items[].price into your chosen target currency before the event leaves your server, using ECB Daily Rates pulled once per day.

Reading time: ~4 minLast updated: 2026-05-09

What it does

If your shop accepts multiple currencies (WooCommerce Multi-Currency, Aelia, manual switcher, geo-routing) you face the same reporting problem on every ad platform: Meta wants one reporting currency, Google Ads wants one reporting currency, your CFO wants one reporting currency. Without normalisation you get conversion totals split across three buckets that you then add up in a spreadsheet, with FX rates from whatever moment Meta happened to pick.

Multi-currency normalises every transaction in flight. The original currency stays on the event as an internal annotation so your debug logs and the live dashboard can still show "92.59 EUR (USD)" if you want to know what was actually charged.

How to enable

wp-admin, Beaconry, Advanced tab, Multi-Currency reporting card. Pick a target currency from the dropdown (any of the ~30 ECB-published codes). Save. Default is "Disabled", which passes events through unchanged.

Power-user override: set BCNR_CURRENCY_TARGET in wp-config.php to lock the target across deploys, see "Constants for power-users" below.

How it works (under the hood)

  1. Daily ECB pull. A WP-Cron event bcnr_currency_refresh fetches the European Central Bank Daily Rates XML from https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml (5-second timeout, official trusted source). The parsed [code => rate] table is cached in two places: a 24-hour transient bcnr_fx_rates for fast reads and a durable autoload=false option bcnr_fx_rates_fallback that survives a transient eviction.
  2. Pre-dispatch filter. BCNR_Currency::normalize_event() hooks the bcnr_pre_dispatch_event filter at priority 10. It runs once per event, before fan-out to channels, so every channel sees the same already-normalised value.
  3. Cross-currency math via EUR bridge. ECB publishes only EUR-to-X rates. To convert USD → GBP, Beaconry goes USD → EUR (1 / rate[USD]) → GBP (× rate[GBP]). Same-currency events are a no-op pass-through, unknown-currency events are a no-op pass-through (no silent guessing on a typo).
  4. Annotation on the event. After conversion, _bcnr_fx_source (original ISO code) and _bcnr_fx_rate (rate applied) are added to the event payload. Internal fields, stripped before HTTP send by each channel's dispatch_* method (only documented Meta / GA4 / TikTok / LinkedIn / Google-Ads keys go on the wire). Visible in the live dashboard's recent-events table and in bcnr_log on dispatch failures.
  5. Outage handling. ECB occasionally hiccups around 16:00 CET (their own daily publish window). If the pull fails, Beaconry falls back to the durable cache (last successful pull, often hours old, FX rates change at most fractions of a percent per day). If the durable cache is empty too (fresh install during an ECB outage), the filter passes events through unchanged with the original currency, and an admin notice flag bcnr_fx_last_error is set so the next page-load shows the operator what happened. Dispatch never crashes.

Constants for power-users

BCNR_CURRENCY_TARGET in wp-config.php, value is a 3-letter ISO-4217 code (uppercase). When set, the constant wins over the DB setting at read time, the dropdown in the UI is shown locked with a hint pointing back to wp-config.php. Useful for staging-vs-production parity, infra-as-code deploys, and for the rare case where you want a non-listed currency that's not in the ECB feed (the constant accepts any ISO code, the conversion still requires both source and target to be ECB-known though).

Troubleshooting

  • "My values look unchanged": most likely the source currency is empty on the event (non-monetary event like page_view) or matches the target. Both are no-op cases by design. Check the live dashboard recent-events table, the converted event would show _bcnr_fx_source + _bcnr_fx_rate annotations.
  • "Admin notice says ECB unreachable": ECB outage. Beaconry will retry on the next cron tick and self-recover. Existing events kept their original currency in the meantime, no data was lost. If the notice persists for more than a day, check that wp_remote_get can reach www.ecb.europa.eu from your server (firewall, outbound HTTP).
  • "I picked a target currency, the dropdown is now disabled": BCNR_CURRENCY_TARGET is defined in wp-config.php. Constant wins over the DB setting. Either edit wp-config.php or delete the constant if you want the UI to control it.
  • "Can I use a custom rate": not currently exposed. The intent of multi-currency is "one trusted public source, no operator surprise". If you need a hand-rolled rate per market, hook bcnr_pre_dispatch_event yourself at priority 9 (before Beaconry's 10) and rewrite value + currency there.