Developing a personal account in React for 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

React Customer Account Development for 1C-Bitrix

The standard customer account in 1C-Bitrix is a set of PHP components bitrix:sale.personal.* that render server-side, return a full HTML page, and perform a complete page reload on every user action (changing a delivery address, checking order status). For small stores this is tolerable. When the account grows to include order history with 200+ entries, a loyalty program, multiple delivery addresses, documents, and third-party service integrations — the standard approach becomes a bottleneck for both UX and performance.

A React account solves this differently: the server delivers only data through REST, the interface lives in the browser. This means instant transitions between sections, data updates without page reloads, and the ability to build complex interactive forms without page re-composition.

Integration Architecture

There are two fundamentally different ways to embed a React account into Bitrix.

Option 1: React inside a Bitrix template. A React application is mounted in a <div id="personal-root"></div> container on a PHP page at /personal/. Bitrix handles authentication, SEO (title, meta), and the common layout (header, footer). React controls only the account content. Routing uses React Router with BrowserRouter, and browser history is synchronized with the URL.

This option is simpler to integrate: authentication uses the standard $USER->Login(), the Bitrix session is passed automatically, and the CSRF token comes from BX.bitrix_sessid().

Option 2: SPA with JWT authentication. The React application lives separately (a separate domain or subdomain) and communicates with Bitrix exclusively through a REST API using JWT tokens. Authentication uses a custom endpoint; the token is stored in an httpOnly cookie or localStorage. This option is justified when the account must serve both a mobile app and a web version through the same API.

For most projects, Option 1 is the better choice — it is simpler to maintain, requires no separate deployment, and authentication is already handled.

API Layer on the Bitrix Side

React components work with data through AJAX requests to Bitrix. A controller is created at /local/php_interface/include/api/personal/:

// Example: endpoint for the order list
class PersonalOrdersController extends \Bitrix\Main\Engine\Controller
{
    public function getListAction(int $page = 1, int $limit = 20): array
    {
        $userId = \Bitrix\Main\Engine\CurrentUser::get()->getId();

        $orderList = \Bitrix\Sale\Order::getList([
            'filter' => ['USER_ID' => $userId],
            'select' => ['ID', 'DATE_INSERT', 'PRICE', 'STATUS_ID', 'CURRENCY'],
            'order'  => ['DATE_INSERT' => 'DESC'],
            'limit'  => $limit,
            'offset' => ($page - 1) * $limit,
        ]);

        $orders = [];
        while ($order = $orderList->fetch()) {
            $orders[] = $order;
        }

        return [
            'orders' => $orders,
            'total'  => \Bitrix\Sale\Internals\OrderTable::getCount(['USER_ID' => $userId]),
        ];
    }
}

Routing in Bitrix through local/ajax/personal.php with a dispatcher or via \Bitrix\Main\Engine\Router. For CSRF protection, all POST requests from React include the BX-Ajax: true header and the session token.

React Application Structure

src/
  personal/
    api/           # axios instance, request types
    components/    # reusable UI elements
    pages/
      Orders/      # order history
      OrderDetail/ # order detail page
      Profile/     # profile data
      Addresses/   # delivery addresses
      Loyalty/     # loyalty program
    store/         # state (Zustand or Redux Toolkit)
    App.tsx
    router.tsx

State management: for simple accounts, React Query alone (request cache + synchronization) is sufficient without a global store. For more complex ones, Zustand is a lighter alternative to Redux.

Case Study: B2B Distributor Account

Wholesale electronics supplier, ~1,500 active client accounts. Task: an account for client managers — visibility into purchase history, repeat ordering from history, managing multiple legal entities within one account, downloading closing documents.

The standard Bitrix account had no multi-entity support at all, and order history with 3,000+ lines took 4–6 seconds to render server-side.

What was implemented:

  1. An API controller for orders with server-side pagination, filtering by date/status, and search by order number. A page of 50 items: 80–120 ms versus 4+ seconds for the full render.

  2. Multi-entity support through a custom local_personal_company table (linking user_id → company_id), with a company switcher in the account header that reloads context via React Query invalidateQueries.

  3. "Repeat order" — a button in history that adds all order items to the cart via \Bitrix\Sale\Basket::create() with a bulk product insert. On the frontend: an animated indicator and a success toast notification.

  4. Documents — integration with 1C: requesting documents through the 1C REST API, polling for generation status every 3 seconds, downloading the PDF directly from 1C via a temporary link.

Metric Before After
Order page load time 4.2 s 0.9 s
Repeat order 5 steps, 2 minutes 1 click, 3 seconds
Support requests about documents ~40/month ~8/month

Authentication and Security

All API requests from React are executed only for authenticated users. Server-side check:

if (!\Bitrix\Main\Engine\CurrentUser::get()->isAuthorized()) {
    throw new \Bitrix\Main\AccessDeniedException('Not authorized');
}

One user's data is inaccessible to another: all queries are filtered by USER_ID from the session; IDs from URL parameters or request parameters are ignored or validated against the session value.

XSS protection: React escapes output by default; HTML from Bitrix is not inserted via dangerouslySetInnerHTML without sanitization.

Build and Deployment

Vite with a configured API proxy for development mode. The production build is deployed to /local/assets/personal/ and included in the component template:

// template.php
\Bitrix\Main\Page\Asset::getInstance()->addJs(
    '/local/assets/personal/index.js'
);

For cache busting — content hash versioning in Vite (rollupOptions.output.assetFileNames).

Scope of Work

  • API design: endpoints, data structure, pagination
  • Server-side development: controllers, authentication, access control
  • React application development: routing, components, state
  • Integration with Bitrix modules: sale, catalog, crm as needed
  • Build, deployment, API response cache configuration

Timeline depends on the feature set: a minimal account (profile + orders + addresses) — 3–4 weeks; a full-featured B2B account with integrations — 2–4 months.