Setting up push notification for abandoned product view in 1C-Bitrix
15–20% of recipients open email about abandoned view — those who open email at all. Push notification in the browser appears immediately, without needing to open email. Push has higher click-through rate if the notification arrives 20–40 minutes after view, not in a day. Setting up this mechanics in Bitrix requires integrating the push.sender module with abandoned view logic.
Delivery architecture
Push notification path: Bitrix agent → MessageSender::send() method → queue in b_agent → POST request to browser push endpoint (FCM for Chrome, Mozilla Autopush for Firefox). Subscriptions are stored in b_push_sender_subscription with fields FUSER_ID, USER_ID, ENDPOINT, AUTH, P256DH.
Critical moment: b_push_sender_subscription contains records for both anonymous users (via FUSER_ID) and authorized users (via USER_ID). When working with abandoned views you need to search for subscription by FUSER_ID since the view could have been anonymous.
Linking view trigger with push subscription
The abandoned view agent (described in separate service) finds pair (fuser_id, product_id). Next step — find active push subscription:
$subscription = \Bitrix\PushSender\Model\SubscriptionTable::getList([
'filter' => [
'FUSER_ID' => $fuserID,
'=STATUS' => 'ACTIVE',
],
'order' => ['DATE_INSERT' => 'DESC'],
'limit' => 1,
])->fetch();
if ($subscription) {
// Subscription exists — send push
} else {
// Fall back to email via b_subscribe_subscriber
}
The STATUS field in b_push_sender_subscription can be ACTIVE, UNSUBSCRIBED or EXPIRED. Before sending check exactly ACTIVE — otherwise we get 410 Gone from FCM and pollute logs.
Forming notification payload
Web Push payload is limited to 4 KB. For abandoned view sufficient: title, text, product URL, image URL. Product data taken from infoblock:
$product = \CIBlockElement::GetByID($productId)->GetNextElement();
$fields = $product->GetFields();
$props = $product->GetProperties();
$imageId = $fields['PREVIEW_PICTURE'] ?: $fields['DETAIL_PICTURE'];
$imageUrl = \CFile::GetPath($imageId);
\Bitrix\PushSender\MessageSender::send(
\Bitrix\PushSender\MessageSender::TYPE_PUSH,
[
'FUSER_ID' => [$fuserID],
'TITLE' => 'You viewed: ' . $fields['NAME'],
'MESSAGE' => 'Item still in stock. Back to selection?',
'URL' => $fields['DETAIL_PAGE_URL'],
'IMAGE' => $imageUrl,
'TAG' => 'abandoned_view_' . $productId,
]
);
The TAG field is Web Push notification tag. If user viewed 5 products and didn't buy any, without tag they get 5 separate notifications. With one tag — each new notification replaces the previous, which is correct from UX perspective.
Sending time and relevance window
Push about abandoned view loses meaning in 3–4 hours. If user didn't open browser in that period, notification arrives later — and becomes inappropriate. Solution: set TTL (Time-To-Live) in FCM request. In Bitrix this is passed via additional options in MessageSender::send(), but standard method doesn't support TTL directly. You need to extend \Bitrix\PushSender\Transport\WebPush class and pass header TTL: 3600 in POST request to endpoint.
Alternatively — check in agent: if b_push_sender_subscription.DATE_INSERT is older than 30 days and no activity — subscription is likely stale, skip.
Mobile app scenario
If the store has mobile app on Bitrix Mobile Framework, push goes via APNs/FCM directly. Subscriptions in this case are stored in b_push_sender_device (not b_push_sender_subscription). Logic is similar but fields differ: DEVICE_ID, TOKEN, PLATFORM (ios/android).
What we configure
- Finding push subscriptions by
FUSER_IDinb_push_sender_subscription - Forming payload with product data from infoblock
- Using
TAGfield to replace duplicate notifications - Setting TTL via extending
WebPushtransport class - Email fallback when push subscription doesn't exist
- Deduplication table shared with abandoned view trigger







