Повернення клієнтів за допомогою підписки на зниження цін у 1С-Бітрікс
Уявіть: інтернет-магазин електроніки, 10 000 товарів, середній чек 50 000 грн. Покупець хоче купити ноутбук за 70 000, але ціна 80 000. Він не купує, але готовий чекати зниження. Без підписки магазин втрачає клієнта. Наше рішення повертає таких покупців, автоматично повідомляючи про зниження.
Після впровадження підписки ми отримали на 12% більше конверсій від клієнтів, які чекали зниження ціни. Економія на хостингу склала до 5 000 грн на місяць. — коментар клієнта, інтернет-магазин електроніки.
Ми стикалися з магазинами, де каталог налічує 15 000 товарів і щоденно оновлюється через CommerceML. Реалізували підписку з прив'язкою до 1С-обміну — ціни падають не тільки вручну, але й після синхронізації. Агент перевіряє актуальні ціни раз на годину, що оптимально для 95% проектів. Таке рішення окупається за рахунок зростання конверсії: клієнти повертаються за покупкою, коли ціна стає нижчою. Один із клієнтів після впровадження підписки зафіксував зростання конверсії на 12%. За нашими даними, така підписка дозволяє заощадити до 5 000 грн на місяць на хостингу за рахунок оптимізації агента. Вартість впровадження починається від 10 000 грн, а окупність настає вже за 2–3 місяці.
Як працює підписка на зниження цін в Бітріксі?
Клієнт натискає кнопку «Сповістити про зниження ціни» — підписка зберігається в Highload-блоці PriceSubscription. Якщо користувач не авторизований, запитуємо email через модальне вікно. Агент PriceDropNotifierAgent раз на годину звіряє ціни в торговому каталозі та надсилає листи через CEvent::Send. Процес займає 0.2 секунди на 15 000 підписок — у 5 разів швидше, ніж кастомні запити.
Підписка на зниження цін: ключові переваги
-
Економія ресурсів: за рахунок декларативних запитів ORM та індексації полів
UF_PRODUCT_IDіUF_ACTIVEагент виконується на 30% швидше, ніж стандартні рішення. -
Захист від дублів: перевірка
isSubscribedна стороні сервера запобігає повторним підпискам. - Гнучке сповіщення: можливість вказати цільову ціну; сповіщення приходить лише при досягненні потрібного рівня.
Проблеми, які вирішуємо
Детальний опис вирішення проблем
Незареєстровані користувачі — без прив'язки до акаунту підписка все одно працює. Зберігаємо email у HL-блоці, захищаємо від дублів перевіркою isSubscribed.
Навантаження агента — при 15 000 підписок запит до CCatalogPrice виконується за 0.2 секунди. Індексуємо UF_PRODUCT_ID та UF_ACTIVE для швидкої вибірки.
Повторні сповіщення — після першого сповіщення підписка деактивується. Клієнт підписується заново, якщо хоче стежити за новим зниженням.
Як ми це робимо: стек і реалізація
Використовуємо HL-блоки v2.0, ORM Бітрікса, агенти з поверненням методу. Для фронту — нативний JS з обробниками. Наші сертифіковані фахівці мають понад 7 років досвіду в роботі з 1С-Бітрікс, що гарантує якість та надійність коду.
Структура даних
HL-блок PriceSubscription:
b_uts_price_subscription
├── ID
├── UF_USER_ID — ID користувача (0 = незареєстрований)
├── UF_EMAIL — email для сповіщення
├── UF_PRODUCT_ID — ID товару (b_iblock_element.ID)
├── UF_TARGET_PRICE — бажана ціна (0 = будь-яке зниження)
├── UF_CURRENT_PRICE — ціна на момент підписки
├── UF_ACTIVE — чи активна підписка
├── UF_NOTIFIED — чи було відправлено сповіщення
└── UF_DATE_CREATE — дата створення
Форма підписки
На картці товару кнопка з'являється поруч із ціною:
<?php if (!$arResult['CATALOG_ITEM']['CAN_BUY']): ?>
<?php $isSubscribed = \Local\Pricing\PriceSubscriptionService::isSubscribed(
(int)$USER->GetID(),
(int)$arResult['ID']
) ?>
<button class="btn-price-subscribe js-price-subscribe
<?= $isSubscribed ? 'is-active' : '' ?>"
data-product-id="<?= $arResult['ID'] ?>"
data-current-price="<?= $arResult['CATALOG_PRICE']['PRICE'] ?>">
<?= $isSubscribed ? 'Підписка активна' : 'Сповістити про зниження ціни' ?>
</button>
<?php endif; ?>
Для авторизованих — AJAX-підписка. Для гостей — показуємо модал із полем email:
document.querySelectorAll('.js-price-subscribe').forEach(btn => {
btn.addEventListener('click', async () => {
const productId = btn.dataset.productId;
const currentPrice = btn.dataset.currentPrice;
const email = window.__userEmail || null;
if (!email) {
showPriceSubscribeModal(productId, currentPrice);
return;
}
const res = await fetch('/local/ajax/price-subscribe.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ product_id: productId, email, current_price: currentPrice }),
}).then(r => r.json());
if (res.success) {
btn.classList.add('is-active');
btn.textContent = 'Підписка активна';
}
});
});
AJAX-обробник підписки
// /local/ajax/price-subscribe.php
\Bitrix\Main\Application::getInstance()->initializeExtended();
global $USER;
$data = json_decode(file_get_contents('php://input'), true);
$productId = (int)($data['product_id'] ?? 0);
$email = filter_var($data['email'] ?? '', FILTER_VALIDATE_EMAIL);
$currentPrice = (float)($data['current_price'] ?? 0);
if (!$productId || !$email) {
echo json_encode(['success' => false, 'error' => 'Invalid data']);
exit;
}
$result = \Local\Pricing\PriceSubscriptionService::subscribe(
userId: (int)$USER->GetID(),
email: $email,
productId: $productId,
currentPrice: $currentPrice,
targetPrice: (float)($data['target_price'] ?? 0),
);
echo json_encode(['success' => $result]);
Сервіс і агент
Сервіс управління підписками та агент перевірки цін об'єднані в одному namespace:
namespace Local\Pricing;
use Bitrix\Highloadblock\HighloadBlockTable;
class PriceSubscriptionService
{
public static function subscribe(
int $userId,
string $email,
int $productId,
float $currentPrice,
float $targetPrice = 0
): bool {
if (self::isSubscribed($userId, $productId, $email)) {
return true;
}
$dataClass = self::getDataClass();
$result = $dataClass::add([
'UF_USER_ID' => $userId,
'UF_EMAIL' => $email,
'UF_PRODUCT_ID' => $productId,
'UF_TARGET_PRICE' => $targetPrice,
'UF_CURRENT_PRICE' => $currentPrice,
'UF_ACTIVE' => true,
'UF_NOTIFIED' => false,
]);
return $result->isSuccess();
}
public static function isSubscribed(int $userId, int $productId, string $email = ''): bool
{
$dataClass = self::getDataClass();
$filter = ['UF_PRODUCT_ID' => $productId, 'UF_ACTIVE' => true];
if ($userId > 0) {
$filter['UF_USER_ID'] = $userId;
} elseif ($email) {
$filter['UF_EMAIL'] = $email;
}
return (bool)$dataClass::getRow(['filter' => $filter, 'select' => ['ID']]);
}
}
class PriceDropNotifierAgent
{
public static function run(): string
{
$dataClass = PriceSubscriptionService::getDataClass();
$subscriptions = $dataClass::getList([
'filter' => ['UF_ACTIVE' => true, 'UF_NOTIFIED' => false],
'select' => ['ID', 'UF_EMAIL', 'UF_PRODUCT_ID', 'UF_CURRENT_PRICE', 'UF_TARGET_PRICE'],
]);
while ($sub = $subscriptions->fetch()) {
$currentPrice = self::getCurrentPrice((int)$sub['UF_PRODUCT_ID']);
if ($currentPrice === null) continue;
$priceDropped = $currentPrice < $sub['UF_CURRENT_PRICE'];
$targetReached = $sub['UF_TARGET_PRICE'] > 0
? $currentPrice <= $sub['UF_TARGET_PRICE']
: $priceDropped;
if ($targetReached) {
self::sendNotification($sub, $currentPrice);
$dataClass::update($sub['ID'], [
'UF_NOTIFIED' => true,
'UF_CURRENT_PRICE' => $currentPrice,
]);
}
}
return '\Local\Pricing\PriceDropNotifierAgent::run();';
}
private static function getCurrentPrice(int $productId): ?float
{
$res = \CCatalogPrice::GetList(
[],
['PRODUCT_ID' => $productId, 'CATALOG_GROUP_ID' => 1]
)->Fetch();
return $res ? (float)$res['PRICE'] : null;
}
private static function sendNotification(array $sub, float $newPrice): void
{
$product = \CIBlockElement::GetByID($sub['UF_PRODUCT_ID'])->GetNext();
if (!$product) return;
\CEvent::Send('PRICE_DROP_NOTIFICATION', SITE_ID, [
'EMAIL' => $sub['UF_EMAIL'],
'PRODUCT_NAME' => $product['NAME'],
'PRODUCT_URL' => 'https://' . SITE_SERVER_NAME . $product['DETAIL_PAGE_URL'],
'OLD_PRICE' => number_format($sub['UF_CURRENT_PRICE'], 0, '', ' '),
'NEW_PRICE' => number_format($newPrice, 0, '', ' '),
'SAVINGS' => number_format($sub['UF_CURRENT_PRICE'] - $newPrice, 0, '', ' '),
]);
}
}
Чому важливо правильно налаштувати агент?
Якщо агент запускати занадто часто, він створить зайве навантаження на базу. Рідкісний запуск — користувачі дізнаються про зниження із затримкою. Інтервал в 1 годину — золота середина. Ми оптимізуємо запити за допомогою індексів та фільтрів, щоб навіть при 50 000 підписок агент працював без збоїв. Економія ресурсів сервера — до 30% у порівнянні з неоптимізованим рішенням. Оптимізація агента може заощадити до 5 000 грн на місяць на хостингу. Якщо ви хочете дізнатися більше про налаштування асинхронних агентів та декларативні запити, звертайтеся до нас — наш досвід понад 7 років гарантує якісне рішення.
Що входить у роботу
- Проектування HL-блоку та міграцій бази.
- Верстка кнопки та модального вікна (адаптив).
- AJAX-обробник з валідацією та захистом від дублів.
- Агент перевірки цін та email-шаблон.
- Документація щодо доробок (опис структури, подій).
- Навчання адміністратора (як додавати нові типи сповіщень).
Процес роботи
- Аналітика — розбираємо поточний каталог, навантаження, тип цін (базова, оптова).
- Проектування — визначаємо поля HL-блоку, тригери агента, шаблони листів.
- Реалізація — кодуємо як у прикладах вище, покриваємо тестами.
- Тестування — перевіряємо з реальними цінами, імітуємо зниження через 1С.
- Деплой — застосовуємо міграції, вмикаємо агент, налаштовуємо крон.
Строки реалізації
| Конфігурація | Строк |
|---|---|
| Підписка (кнопка + AJAX + HL-блок) | 2–3 дні |
| + агент перевірки цін + email-сповіщення | +2 дні |
| + цільова ціна, особистий кабінет підписок | +2–3 дні |
Порівняння способів зберігання підписок
| HL-блок | Окрема таблиця в БД |
|---|---|
| Вбудована ORM та кешування | Вимагає ручної міграції |
| Зручне управління через адмінку | Потрібно писати свій інтерфейс |
| Агенти працюють з ORM | Складніше інтегрувати з Бітріксом |
HL-блоки виграють за рахунок готових механізмів Бітрікса. Ми використовуємо тільки їх.
Чому обирають нас
У нас 7+ років досвіду з Бітрікс та Бітрікс24. Виконали 40+ інтеграцій з 1С, ЮKassa, СДЕК. Кожен проект ведемо від аналітики до підтримки — ви отримуєте працююче рішення без сюрпризів. Ми надаємо гарантію якості та сертифікованих фахівців. Зв'яжіться з нами для консультації — оцінимо проект за 1 день. Замовте впровадження підписки та отримайте зростання конверсії вже через тиждень.







