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:
-
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.
-
Multi-entity support through a custom
local_personal_companytable (linkinguser_id → company_id), with a company switcher in the account header that reloads context via React QueryinvalidateQueries. -
"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. -
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,crmas 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.







