Build a Custom Product Rating in 1C-Bitrix with ORM & AJAX

We integrate a custom product rating system into 1C-Bitrix using a separate ORM table, AJAX voting, and fraud protection. Unlike the standard `vote` module, our approach stores ratings in `b_product_vote` and aggregates results into infoblock properties, enabling smooth catalog integration and sorti

Our competencies:

Frequently Asked Questions

We integrate a custom product rating system into 1C-Bitrix using a separate ORM table, AJAX voting, and fraud protection. Unlike the standard vote module, our approach stores ratings in b_product_vote and aggregates results into infoblock properties, enabling smooth catalog integration and sorting. With over 10 years of Bitrix development experience and 50+ deployed projects, we guarantee stable operation under load. Typical project cost: €600-1200, with a development timeline of 3-7 days.

Why the standard vote module is not suitable for product ratings?

The vote module in Bitrix is designed for abstract polls and cannot directly bind to infoblock elements. For products, a lot of custom logic is needed: duplicate checking, aggregation recalculation, and order linking. Moreover, vote uses its own tables and components, complicating catalog sorting. Our scheme with a separate b_product_vote table and infoblock properties eliminates these shortcomings. Furthermore, Bitrix rating optimization in our approach is achieved through direct SQL queries and caching.

Rating storage architecture

Table b_product_vote for individual ratings:

Field Type Purpose
ID int Primary key
PRODUCT_ID int Product ID
USER_ID int User ID (NULL = guest)
IP varchar(45) IP address (for guests and anti-fraud)
RATING tinyint Rating 1–5
CREATED_AT datetime When voted

ORM class ProductVoteTable extends \Bitrix\Main\ORM\Data\DataManager. In the product infoblock, two numeric properties are added:

  • RATING_AVG — average rating (float, updated after each vote)
  • RATING_COUNT — number of ratings

This allows sorting and filtering by rating through standard CIBlockElement::GetList() without JOINs.

How we implement ratings: step-by-step process

  1. Audit the current store architecture on 1C-Bitrix: assess load, product types, and existing modules.
  2. Design the ORM model: create b_product_vote table, write ProductVoteTable class.
  3. Develop an AJAX voting controller with duplicate protection.
  4. Integrate aggregation into infoblock properties using SetPropertyValuesEx.
  5. Create a star widget with partial fill (SVG, CSS-clip).
  6. Configure catalog sorting by rating.
  7. Load test: simulate 10,000 votes, measure response time.
  8. Document API and components, train administrators.

Voting algorithm

Voting is done via an AJAX request. The component outputs a star form; a click sends a POST to the controller:

// local/ajax/product_vote.php \Bitrix\Main\Loader::includeModule('main'); \Bitrix\Main\Loader::includeModule('catalog'); $productId = (int)($_POST['product_id'] ?? 0); $rating = (int)($_POST['rating'] ?? 0); if ($rating < 1 || $rating > 5 || $productId <= 0) { echo json_encode(['success' => false, 'error' => 'invalid_data']); exit; } $userId = $GLOBALS['USER']->GetID() ?: null; $ip = \Bitrix\Main\Context::getCurrent()->getRequest()->getRemoteAddress(); // Check: already voted? $existing = ProductVoteTable::getList([ 'filter' => ['=PRODUCT_ID' => $productId, '=USER_ID' => $userId ?: false, '=IP' => $ip], 'limit' => 1, ])->fetch(); if ($existing && $userId === null) { echo json_encode(['success' => false, 'error' => 'already_voted']); exit; } 

For authorized users, we check by USER_ID. For guests, by IP. An authorized user can change their rating (update the existing record instead of creating a new one).

Aggregated rating recalculation

After each vote, we update the aggregates. More details on SetPropertyValuesEx in the official documentation:

function updateProductRating(int $productId): void { $conn = \Bitrix\Main\Application::getConnection(); $row = $conn->query( "SELECT AVG(RATING) as AVG_RATING, COUNT(*) as CNT FROM b_product_vote WHERE PRODUCT_ID = {$productId}" )->fetch(); \CIBlockElement::SetPropertyValuesEx($productId, false, [ 'RATING_AVG' => round((float)$row['AVG_RATING'], 2), 'RATING_COUNT' => (int)$row['CNT'], ]); } 

SetPropertyValuesEx works faster than Update() of the whole element — it updates only the specified properties.

Star widget implementation

On the frontend, the rating is displayed as a set of SVG stars. Partial fill logic: for a rating of 4.2, four stars are fully filled, the fifth is 20% filled. Implemented via CSS-clip or SVG gradient with width proportional to the fractional part.

Component for displaying rating in product card and listing accepts parameters:

$APPLICATION->IncludeComponent('custom:product.rating', '', [ 'PRODUCT_ID' => $arResult['ID'], 'SHOW_FORM' => $USER->IsAuthorized() ? 'Y' : 'N', 'CURRENT_RATING' => $arResult['PROPERTIES']['RATING_AVG']['VALUE'], 'VOTE_COUNT' => $arResult['PROPERTIES']['RATING_COUNT']['VALUE'], ]); 

How to protect ratings from fraud?

IP restrictions are good for guests but not for organized attacks:

  • For authorized users — one rating per product (strict check via USER_ID + PRODUCT_ID).
  • Restriction: cannot vote for a product that has never been viewed (check via b_stat_session or custom view table).
  • Optionally: allow voting only to users who purchased the product (similar to verification in review systems).

Thanks to this approach, we block up to 99% of fraud in real projects. Experience shows that the combination of USER_ID + IP reduces fake votes to almost zero. In one electronics store project (catalog of 10,000 products, load 500 votes per hour), implementing the rating increased conversion by 18% in the first month — products with a score above 4.0 sold twice as often. The average score across the store was 4.2. Rating update time after a vote is less than 0.3 seconds.

What is included in the work

  • Audit of the current store architecture on 1C-Bitrix
  • Design of the ORM model for storing ratings
  • Development of AJAX voting controller with protection
  • Integration of aggregation into infoblock properties
  • Creation of a star widget with partial fill
  • Configuration of catalog sorting by rating
  • Load testing and debugging
  • API and component documentation
  • Training administrators on the system
  • Post-release support for one month

Experimentally confirmed: product rating increases conversion by 15–20%.

Development timeline and cost

Scope Content Duration Cost (€)
Basic ORM model, AJAX voting, star widget, aggregation in property 3–4 days 500-700
Full Rating modification, fraud protection, catalog sorting by rating, voting history 5–7 days 900-1200

Contact us for a free project assessment. Order a turnkey rating system development — increase trust in your catalog. Get a consultation on your project.