Setting up browser notifications for 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    565
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    980

Browser Push Notification Setup in 1C-Bitrix

Push notifications in the browser stop working in three typical scenarios: the server doesn't send VAPID keys, the worker registers with the wrong scope, or the subscription silently fails when the HTTPS certificate changes. In each of these cases, the user simply doesn't receive notifications — without front-end errors.

How subscription works in Bitrix

The push.sender module implements Web Push through the VAPID standard. When a user first visits the site, the browser registers a Service Worker from the file /bitrix/js/push-sender/sw/push-worker.js. This worker subscribes to the browser's push endpoint (Google FCM, Mozilla Autopush, or Safari's own). The obtained subscription object (PushSubscription) is saved via an AJAX call to BX.PushServer.subscribe(), which writes the data to the b_push_sender_subscription table.

The server part stores VAPID keys in module settings — table b_option, parameters push_server_public_key and push_server_private_key. When sending a notification, the method \Bitrix\PushSender\Model\Subscription::send() is used, which accesses the \Bitrix\Main\Web\HttpClient class for a POST request to the push endpoint.

Scope and worker path problem

The most common error — Service Worker registers with the wrong scope. This happens when Bitrix is installed in a subdirectory, or when nginx has a non-standard alias. A worker from /bitrix/js/... cannot manage pages on /shop/ because the scope by default equals the directory from which the worker file is loaded.

The solution is to explicitly pass the scope parameter when registering. In the file /bitrix/js/push-sender/push-sender.js, the navigator.serviceWorker.register() call should contain:

navigator.serviceWorker.register('/bitrix/js/push-sender/sw/push-worker.js', {
    scope: '/'
});

If the worker file is in /bitrix/ and scope is needed on /, the server must send the header Service-Worker-Allowed: / for this JS file. In nginx this is added via add_header for the location with the path to the worker.

VAPID keys and their recreation

When changing domain or migrating a site, old VAPID keys in b_option remain, but all existing subscriptions in b_push_sender_subscription become invalid — the browser rejects them with 410 Gone. Bitrix doesn't clean up the table automatically.

Correct procedure for recreating keys:

// Generate new VAPID pair
$keys = \Bitrix\PushSender\Security\VapidKey::generateKeyPair();
\Bitrix\Main\Config\Option::set('push.sender', 'push_server_public_key', $keys['publicKey']);
\Bitrix\Main\Config\Option::set('push.sender', 'push_server_private_key', $keys['privateKey']);

// Clean up outdated subscriptions
\Bitrix\PushSender\Model\SubscriptionTable::deleteByFilter([]);

After this, all active users will automatically re-subscribe on their next visit — the browser will receive the new public key and create a new subscription.

Segmentation and sending

The module supports sending to users (USER_ID), by sessions, and broadcasting. For programmatic sending:

\Bitrix\PushSender\MessageSender::send(
    \Bitrix\PushSender\MessageSender::TYPE_PUSH,
    [
        'USER_ID' => [15, 42],
        'MESSAGE' => 'Your order has been sent',
        'TITLE' => 'Order Update',
        'URL' => '/personal/orders/123/',
    ]
);

The send() method iterates through subscriptions from b_push_sender_subscription by the passed USER_ID and queues tasks in the agents queue — table b_agent, agent \Bitrix\PushSender\Agent\SendMessageAgent.

Diagnostics through logs

For debugging, enable logging in the push.sender module settings: parameter log_level in b_option. At debug value, all requests to push endpoints are written to /bitrix/modules/push.sender/logs/. Typical response codes: 201 — delivered, 404 — endpoint doesn't exist, 410 — subscription deleted by user, 429 — rate limit on FCM side.

For mass 410 responses, clean up b_push_sender_subscription by filtering by the date of the last failed response — otherwise the agent will waste cycles running outdated records on each run.