Dynamic Pricing: From Rules to Handler
Imagine an electronics e-commerce platform on 1C-Bitrix with 10,000 SKUs. One product — an SSD drive. When stock levels drop below 10 units, the price automatically rises by 20% — no manual discounts, just logic in the code. This dynamic pricing setup can be implemented by hooking the OnGetOptimalPrice event — we override the price on the fly without touching the b_catalog_price table. We have implemented over 40 projects with demand-based pricing for stores of various sizes, leveraging price elasticity coefficients. Our clients get transparent audit: all modifications are logged in a separate table. https://en.wikipedia.org/wiki/Dynamic_pricing
How Bitrix Calculates the Final Price
The calculation chain: base price (b_catalog_price) → catalog discounts (b_catalog_discount) → basket rules (b_sale_discount) → total. Dynamic pricing works at the first level — it changes the base price or intercepts it via the OnGetOptimalPrice event and returns a different value. The Bitrix event is triggered on every price request: in the product list, on the detail page, in the cart. Without optimization, one DB query costs 0.3 ms, but a catalog page with 48 items means 48 queries, risking cache stampede. The solution is price caching with a TTL of 5 minutes, using atomic cache updates to prevent stale data. This reduces load by 10x.
Event-Based vs Direct DB Writes
| Criterion | Via OnGetOptimalPrice event |
Direct price change in b_catalog_price |
|---|---|---|
| Price history cleanliness | Price remains unchanged, modifier applied on the fly | Fills history with unnecessary entries |
| Rollback speed | Instant — disabling the rule | Requires restoring previous values (up to 2 hours) |
| Price feed indexing | No impact | Can distort exports |
| Performance | One cache request per product | Many write queries on each change |
The event reduces rollback time to 1 minute, while direct writes require recovery from backup. The event-based approach is 10 times faster than direct DB writes for rollback. Price caching with invalidation by tag dynamic_price_{productId} speeds up work by 10x.
Dynamic Pricing Rules Configuration
Rules are stored in a custom table bl_dynamic_pricing_rules. Here are its fields with examples:
| Field | Description | Example |
|---|---|---|
rule_type |
stock / demand / competitor / time |
stock |
iblock_id |
Information block or NULL (all) | 17 |
product_id |
Specific product or NULL (all in section) | 1234 |
condition_json |
Condition parameters (stock, hour, coefficient) | {"min_stock": 5} |
price_modifier |
Coefficient (1.15 = +15%, 0.9 = -10%) | 1.2 |
priority |
Application order in case of conflict | 10 |
active |
Enabled/disabled | Y |
When rules conflict, the one with the highest priority is applied.
Example: Stock-Based Rule
When product stock falls below a threshold, we raise the price. This encourages faster purchases or curbs demand spikes. Stock is fetched from b_catalog_store_product:
Example PHP Code
$stock = \Bitrix\Catalog\StoreProductTable::getList([ 'filter' => ['PRODUCT_ID' => $productId], 'select' => ['AMOUNT'], 'runtime' => [new \Bitrix\Main\ORM\Fields\ExpressionField('TOTAL', 'SUM(%s)', 'AMOUNT')], ])->fetch()['TOTAL'] ?? 0; if ($stock < 5) return 1.2; // +20% when stock < 5 if ($stock < 20) return 1.1; // +10% when stock < 20 return 1.0; You can configure thresholds and coefficients in the admin interface.
Steps to Configure a Stock Rule
- Create a rule in the admin interface ("Dynamic Pricing" section).
- Set type to
stock. - Define stock thresholds (e.g.,
<5,5-20). - Assign a price modifier coefficient (e.g.,
1.2for +20%). - Enable caching with TTL 300 seconds.
- Test on a single product — check the price on the storefront.
- Activate the rule for the entire catalog.
Performance Optimization
Without caching, a catalog page with 48 products triggers 48 OnGetOptimalPrice event calls to the DB. With price caching, there is 1 query every 5 minutes. Load drops by 10x, and we prevent cache stampede via atomic updates. We also use Bitrix's tagged cache (\Bitrix\Main\Data\Cache) with a 300-second TTL and invalidation by tag dynamic_price_{productId}. This allows supporting catalogs up to 100,000 products without degradation, even with high concurrency.
Work Process
- Analysis: we study the current pricing scheme, business requirements, and site load, incorporating price elasticity and inventory turnover metrics.
- Design: we create the table structure
bl_dynamic_pricing_rulesand priority logic with event-driven architecture. - Development: we write the
DynamicPricingEngineclass with caching, attach theOnGetOptimalPricehandler ininit.php. - Admin interface: we create a form for managing rules (add, edit, enable/disable).
- Logging: we record all rule applications in
bl_dynamic_pricing_logfor audit. - Testing: load testing on a catalog of 100,000 products, price correctness checks, and stress testing for cache stampede.
- Deployment and documentation: operator instructions for rule setup.
What's Included in the Result
After completion, you receive:
- A working dynamic pricing engine based on rules;
- Admin interface for rule management without code access;
- Logs of all price changes for audit;
- Documentation for setup and operation;
- Load testing on a catalog of up to 100,000 products;
- One month of warranty support after implementation.
Timeline and Consultation
Setup takes from 3 to 10 business days depending on the number of rules and catalog size. Standard pricing setup costs between $1,500 and $4,000. The cost is calculated individually — we will evaluate the project after a brief. Our clients typically see a 20% reduction in pricing management costs, equating to savings of $2,000–$5,000 annually for a mid-size catalog. Get a consultation — contact us, and we will prepare a roadmap. Order implementation — and your store will gain flexible pricing without manual management.
We guarantee the solution will work stably: it will withstand peak loads and won't cause storefront errors. Our certificates and portfolio are available on request.







