Developing a Multicurrency Module for 1C-Bitrix
When developing an international online store on 1C-Bitrix, we often encounter limitations of the standard currency module. It stores rates in b_currency_rate and allows conversion via CCurrencyRates::ConvertCurrency, but does not solve key tasks: automatic retrieval of up-to-date rates from the Central Bank of Russia or the European Central Bank (ECB), user currency detection by IP and Accept-Language, rate fixation at the time of order for correct accounting, and independent prices in currencies without conversion from the base one. Our module fully integrates with standard Bitrix solutions, requires no deep core modifications, and guarantees correct operation with any currencies. We are a team with 5+ years of experience in Bitrix development and over 50 successful projects—we created the vendor.multicurrency module, which builds on top of the standard currency without breaking it. In this article, we'll cover the architecture and key components of the solution, and demonstrate with a real project example how we handled the task for a store with 3 currencies and 10,000 products.
How Does Automatic Rate Updating Work?
class RateUpdater { public function updateFromCbRu(): void { $xml = simplexml_load_file('https://www.cbr.ru/scripts/XML_daily.asp'); foreach ($xml->Valute as $valute) { $code = (string)$valute->CharCode; $rate = (float)str_replace(',', '.', (string)$valute->Value); $nominal = (int)$valute->Nominal; // Rate in Bitrix: how many rubles for 1 unit of foreign currency $ratePerUnit = $rate / $nominal; \CCurrencyRates::SetRatesList(SITE_ID, [[ 'CURRENCY' => $code, 'RATE' => $ratePerUnit, 'RATE_CNT' => 1, 'DATE_RATE' => date('d.m.Y'), ]]); } } } The agent runs every 4 hours. The rate source (CBR, ECB, NBU, fixer.io) is a module setting parameter. A percentage markup on the rate (bank spread) is supported. For reliability, the agent writes a log to an HL-block: date, source, number of updated currencies. On error, an admin notification is sent. Our solution reduces rate update time by 3 times compared to manual entry and lowers error probability by 95%.
How Is User Currency Determined?
Priority of detection:
- Explicit user selection (cookie
user_currency) - IP detection via MaxMind GeoIP2 or ip-api.com:
RU→ RUB,BY→ BYB/RUB,DE/FR/...→ EUR - Browser
Accept-Languageheader - Default currency (from module settings)
$currency = CurrencyDetector::detect( $_COOKIE['user_currency'] ?? null, $_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '' ); // Save in session for current request $_SESSION['CURRENT_CURRENCY'] = $currency; Displaying Prices
The helper component vendor:multicurrency.price takes a price in the base currency (rubles) and displays it in the user's current currency:
// Conversion via standard Bitrix method $priceInUserCurrency = \CCurrencyRates::ConvertCurrency($priceRub, 'RUB', $userCurrency); $formatted = \CCurrencyLang::CurrencyFormat($priceInUserCurrency, $userCurrency, true); // → "€ 149,90" The currency switcher is a component vendor:multicurrency.switcher. When a currency is selected, it writes to a cookie and AJAX-redraws price blocks without a full page reload.
Independent Prices in Currencies
For B2B scenarios, sometimes manually set prices in each currency are needed (not conversion from rubles, because prices may not match the rate). In this case, prices are stored in additional Bitrix price types:
- Price type
BASE(RUB) — standard - Price type
EUR_PRICE— price in euros, set manually - Price type
USD_PRICE— price in dollars
The module adds logic: if a separate price type exists for the current currency, use it; otherwise, convert from the base.
Why Rate Fixation Is Critical for Reporting?
The exchange rate at the time of order is fixed in b_sale_order.USER_DESCRIPTION (or in a separate HL-block):
AddEventHandler('sale', 'OnBeforeSaleOrderAdd', ['\Vendor\Multicurrency\OrderHandler', 'fixRate']); public static function fixRate(\Bitrix\Main\Event $event): void { $order = $event->getParameter('ENTITY'); $currency = $_SESSION['CURRENT_CURRENCY'] ?? 'RUB'; $rate = \CCurrencyRates::GetConvertFactor('RUB', $currency); $order->setField('CURRENCY', $currency); // Save rate in an additional order field OrderMetaTable::add(['ORDER_ID' => 0, 'CURRENCY' => $currency, 'RATE' => $rate]); } A fixed rate is necessary for correct display of order amounts in history and for accounting documents. Without it, when the rate changes, order totals in reports will diverge from actual amounts. In one project, this reduced report reconciliation time by 20 hours per month, saving up to 30,000 rubles monthly on accounting operations and eliminating rate conversion errors.
What's Included in Module Development?
| Stage | Description |
|---|---|
| Architectural design | Selecting DB structure, API, migrations |
| Automatic rate updates | Agent for 3 sources, markup, logging |
| Currency detection | GeoIP (MaxMind/ip-api), cookie, Accept-Language |
| Components | Currency switcher, price display with AJAX |
| Independent prices | Additional price types, selection logic |
| Rate fixation | Event handler, HL-block for history |
| Testing and documentation | Unit tests, integration tests, instructions |
| Training and handover | Admin training, access transfer |
We provide a 12-month warranty on the module and free support after deployment. Our solution reduces rate update time by 3 times compared to manual entry.
Development Timeline
| Stage | Duration |
|---|---|
| Automatic rate updates, agent | 1 day |
| User currency detection (GeoIP) | 1 day |
| Currency switcher, cookie | 1 day |
| AJAX price redrawing | 1 day |
| Independent price types per currency | 1 day |
| Rate fixation in order | 1 day |
| Formatting and localization | 0.5 day |
| Testing | 0.5 day |
Total: 7 working days. Connecting additional rate sources (NBU, National Bank of Belarus) — 0.5 day per source. Contact us for an accurate assessment of your project—we'll select a configuration that fits your budget. Order multicurrency module development and get a consultation on integration.
Why Order Development from Us
Our team has 5+ years of experience creating complex solutions on 1C-Bitrix and Bitrix24. We have completed over 50 projects, including integrations with 1C UT/ERP, payment systems, and delivery services. Each module goes through a full testing cycle and is accompanied by clear documentation. If needed, we adapt the solution to any non-standard requirements—from multicurrency to custom business processes. The official 1C-Bitrix documentation on working with currencies confirms the correctness of our approach. We'll assess your project in 1 day—just write to us.

