Setting Up Web-Push Notifications on 1C-Bitrix
A user leaves your site without completing an order. A standard email reminder gets lost in their inbox. But a push notification arrives even when the browser is closed on a mobile device. Implementing this on Bitrix is non-trivial: you need VAPID, a Service Worker, correct handling of expired subscriptions, and integration with CRM events. We break down the technical details we use in every project. Our experience — over 5 years with Bitrix and 20+ projects with push alerts. In one project (an online store with 50,000 products), we increased abandoned cart recovery by 25% using push notifications configured with the scheme described below. Clients typically save $2,000–$5,000 per month in recovered sales.
Problems We Solve
Push alerts outperform email in several ways: they are not filtered by spam filters, delivered instantly, and visible even with the browser closed (on mobile). While email open rates average 20–30%, push notifications achieve 60–80%. According to the Web Push Protocol specification, push notifications are 3 times more likely to be opened. They are especially effective for abandoned carts — user return increases by 20–30%. On one project, we recorded a 25% return of users who did not complete a purchase within an hour.
| Parameter | Web-push | |
|---|---|---|
| Delivery time | 1–2 sec | 1–10 min |
| Open rate | 60–80% | 20–30% |
| Requires permission | Yes (one-time) | No |
| Works with closed browser | Yes (on mobile) | No |
| Spam filters | None | Yes |
Web-push is 3 times more effective than email for open rates.
How We Do It: Infrastructure
VAPID Keys – a public/private key pair for authenticating the server to the browser push service. Generated once. Install the library via composer require minishlink/web-push, then:
use Minishlink\WebPush\VAPID;
$keys = VAPID::createVapidKeys();
// ['publicKey' => '...', 'privateKey' => '...']
// Save to settings
COption::SetOptionString('local', 'vapid_public_key', $keys['publicKey']);
COption::SetOptionString('local', 'vapid_private_key', $keys['privateKey']);
The public key is passed to the browser during subscription registration; the private key stays on the server. Service Worker – a JS file registered by the browser for background work. The file service-worker.js must be in the site root (/service-worker.js) due to browser scope restrictions.
How to Subscribe Users Correctly
On the client side, request permission and create a subscription. The Service Worker handles incoming push events and notification clicks:
Code example
// service-worker.js
self.addEventListener('push', function(event) {
const data = event.data.json();
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body,
icon: data.icon || '/local/images/push-icon.png',
data: { url: data.url }
})
);
});
self.addEventListener('notificationclick', function(event) {
event.notification.close();
event.waitUntil(clients.openWindow(event.notification.data.url));
});
// Subscription in main script
async function subscribeToPush() {
const registration = await navigator.serviceWorker.register('/service-worker.js');
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('YOUR_VAPID_PUBLIC_KEY')
});
await fetch('/local/ajax/push_subscribe.php', {
method: 'POST',
body: JSON.stringify(subscription),
headers: { 'Content-Type': 'application/json' }
});
}
On the server, /local/ajax/push_subscribe.php saves the subscription. The subscriptions table contains fields: ID, USER_ID (NULL for unauthenticated), ENDPOINT, P256DH, AUTH, CREATED_AT, LAST_ACTIVE. Unique index on ENDPOINT.
Sending Notifications from Bitrix
Service class using minishlink/web-push:
use Minishlink\WebPush\WebPush;
use Minishlink\WebPush\Subscription;
function sendPushNotification(array $subscription, string $title, string $body, string $url): void {
$auth = [
'VAPID' => [
'subject' => 'https://developer.mozilla.org',
'publicKey' => COption::GetOptionString('local', 'vapid_public_key'),
'privateKey' => COption::GetOptionString('local', 'vapid_private_key'),
],
];
$webPush = new WebPush($auth);
$webPush->queueNotification(
Subscription::create([
'endpoint' => $subscription['ENDPOINT'],
'keys' => ['p256dh' => $subscription['P256DH'], 'auth' => $subscription['AUTH']],
]),
json_encode(['title' => $title, 'body' => $body, 'url' => $url])
);
foreach ($webPush->flush() as $report) {
if ($report->isSubscriptionExpired()) {
deleteExpiredSubscription($report->getEndpoint());
}
}
}
Integration with Bitrix Events
Abandoned cart reminder. An agent runs hourly, finds carts with products older than 2 hours for users with subscriptions, and sends push. Table b_sale_basket, filter by DATE_UPDATE < NOW() - INTERVAL 2 HOUR and ORDER_ID IS NULL.
Order status change notification. Handler OnSaleOrderStatusUpdate:
AddEventHandler("sale", "OnSaleOrderStatusUpdate", function($orderId, $arFields) {
if ($arFields['STATUS_ID'] === 'D') { // Delivered
$userId = CSaleOrder::GetByID($orderId)['USER_ID'];
sendPushToUser($userId, 'Order delivered', 'Your order #' . $orderId . ' is waiting');
}
});
Mass campaigns – select all subscribers from b_local_push_subscription, send in batches of 100 via webPush->queueNotification() + flush(). Large campaigns use an agent with pagination to avoid script timeout.
Handling Expired Subscriptions
Expired subscriptions (endpoint returns 404 or 410) should be removed immediately — they accumulate quickly and slow down campaigns. We recommend adding an agent for periodic cleanup: for example, once a day check all subscriptions and delete those not updated in the last 30 days. This reduces database load and improves deliverability.
Browser Support
| Browser | Minimum Version | Notes |
|---|---|---|
| Chrome | 42 | Full support |
| Firefox | 44 | Full support |
| Safari | 16.4 | Requires macOS 13+ |
| Edge | 17 | Full support |
| Opera | 29 | Full support |
Process and Timeline
Our process: data collection → audit/analysis → design → estimation → development → testing → launch. We start with an analysis of your current notification scheme and CRM events. Then we implement VAPID keys, Service Worker, subscription table, and integrate with your business logic. A working prototype is ready within 3–5 days. Final timeline depends on the number of events and complexity of triggers.
What's Included in the Turnkey Setup
- Installation and configuration of VAPID keys
- Service Worker registration at site root
- Subscription table creation and save script
- Integration with events: abandoned carts, order status changes, mass campaigns
- Expired subscription handling (cleanup agent)
- Testing on all supported browsers
- Documentation for extending functionality
- Analysis of your current notification scheme and recommendations
As a certified Bitrix partner with over 5 years of experience, we guarantee reliable push notification setup. Contact us for a consultation — we will assess your project and propose the optimal solution. Order turnkey web-push notification setup and get a working prototype in 3–5 days. For quick testing of push alerts on your site, reach out to our engineers.







