Web push уведомления: как они работают и как использовать их правильно
Как работают web push уведомления, от service worker и VAPID до реальной поддержки в браузерах, включая iOS, плюс UX запроса разрешения и метрики, которые решают результат.
Web push уведомления являются единственным маркетинговым каналом, где одно неудачное решение в дизайне может навсегда закрыть вам доступ к клиенту. Запросите разрешение не в тот момент, посетитель нажмёт «Блокировать», и этот браузер закрыт для вас навсегда. Ни повторного запроса, ни второй кампании, ни письма для возврата. Именно эта асимметрия делает механику достойной изучения ещё до того, как вы напишете первое сообщение.
Что такое web push уведомления
Web push уведомление является сообщением, которое ваш сервер отправляет в браузер подписчика, оно отображается в центре уведомлений операционной системы и доставляется даже когда ваш сайт закрыт. Последнее и есть весь смысл: в отличие от всплывающего окна на странице, web push достаёт до человека, который сейчас не смотрит на ваш сайт.
Он собран из трёх API веб-платформы, работающих вместе, и разделение между ними объясняет большую часть поведения канала: Service Worker API, Push API и Notifications API.
Как web push работает изнутри
Service worker
Service worker является JavaScript-воркером, который выступает прокси между вашим веб-приложением, браузером и сетью. Он работает в собственном потоке, не имеет доступа к DOM и продолжает существовать после закрытия страницы, которая его зарегистрировала. Именно эта живучесть позволяет ему получить push-сообщение и показать уведомление, когда ваша вкладка ни у кого не открыта. Service worker работает только в защищённых контекстах, то есть по HTTPS, при этом http://localhost считается защищённым для разработки.
Подписка: эндпоинт плюс два ключа
Как только service worker активен, страница вызывает registration.pushManager.subscribe(). Браузер обращается к push-сервису своего вендора и возвращает PushSubscription, который содержит:
endpoint, уникальный URL-возможность, на который push-сервис принимает сообщенияkeys.p256dh, публичный ключ Elliptic Curve Diffie-Hellman на кривой P-256keys.auth, секрет аутентификации
Ваш сервер хранит все три значения и относится к эндпоинту как к секрету, потому что любой, у кого он есть, может отправлять этому подписчику. Ключи нужны потому, что полезная нагрузка шифруется сквозным образом. RFC 8291 описывает как: обмен ECDH на P-256 устанавливает общий секрет, HKDF выводит из него ключи, а полезная нагрузка запечатывается алгоритмом AES-128-GCM с кодировкой содержимого aes128gcm. Push-сервис передаёт шифротекст, который не может прочитать.
Push-сервис
Вы не отправляете push-сообщения прямо на устройство. Вы отправляете их в push-сервис, который держит вендор браузера: эндпоинты FCM от Google для Chrome, autopush от Mozilla для Firefox, push-сервис Apple для Safari. Протокол определён в RFC 8030, «Generic Event Delivery Using HTTP Push». Ваш сервер отправляет POST на эндпоинт подписки, а push-сервис берёт на себя сложные части мобильной доставки: одно энергоэффективное соединение с устройством, очередь на время офлайна, пробуждение браузера при приходе сообщения. По этой же причине доставка не может быть гарантирована. Если устройство выключено достаточно долго, сообщения истекают согласно своему TTL и отбрасываются.
VAPID: подтверждение отправителя
Секретность эндпоинта является слабой защитой. RFC 8292 добавляет Voluntary Application Server Identification, или VAPID, чтобы push-сервис мог определить, от какого сервера приложения пришло сообщение.
Вы один раз генерируете пару ключей ECDSA на кривой NIST P-256. Публичный ключ попадает в applicationServerKey при подписке в браузере и привязывает подписку к вашему серверу. Для каждой отправки ваш сервер посылает JWT, подписанный соответствующим приватным ключом алгоритмом ES256, с полем aud для источника push-сервиса, полем exp не более чем на 24 часа вперёд и опционально полем sub с контактными данными. Push-сервис проверяет подпись, поэтому одного украденного эндпоинта уже недостаточно, чтобы спамить вашим подписчикам.
Путь доставки от начала до конца
- Страница регистрирует service worker и после выдачи разрешения вызывает
subscribe()с вашим публичным ключом VAPID. - Ваш сервер сохраняет полученные эндпоинт и ключи в записи подписчика.
- Для отправки ваш сервер шифрует полезную нагрузку с помощью
p256dhиauth, подписывает JWT для VAPID и отправляет POST на эндпоинт. - Push-сервис проверяет запрос и доставляет зашифрованное сообщение.
- Браузер будит service worker событием
push, тот расшифровывает нагрузку и вызываетServiceWorkerRegistration.showNotification(). - Клик порождает событие
notificationclickв service worker, где вы открываете целевой URL.
Почему модель разрешений так строга
Посмотрите, что даёт подписка: фоновый процесс, работающий без открытого сайта, плюс возможность рисовать на поверхности уведомлений операционной системы. Поэтому браузеры закрывают её явным разрешением, выданным пользователем для конкретного источника, и большинство требует, чтобы запрос следовал за настоящим жестом пользователя.
Второе ограничение удивляет многих. Chrome и Edge требуют userVisibleOnly: true при подписке, то есть обещание, что каждый push произведёт видимое пользователю уведомление, поэтому тихие фоновые отправки не являются поддерживаемым сценарием API. Firefox дополнительно применяет квоту к push-сообщениям, которые не порождают уведомление.
Поддержка в браузерах и на платформах
По данным MDN, Push API имеет статус Baseline widely available с марта 2023 года, то есть работает в актуальных версиях Chrome, Edge, Firefox и Safari на десктопе, а также в Chrome и Firefox для Android. Две оговорки важнее самого заголовка.
Во-первых, Notifications API доступен не везде одинаково. MDN помечает его как limited availability, потому что конструктор Notification() выбрасывает TypeError в большинстве мобильных браузеров. Для всего, что должно работать на телефонах, используйте постоянные уведомления через ServiceWorkerRegistration.showNotification(), то есть тот же путь через service worker, на котором вы и так находитесь.
Во-вторых, опции уведомлений реализованы неравномерно. Кнопки действий, значки, изображения и requireInteraction различаются между браузерами и операционными системами, поэтому проектируйте уведомления так, чтобы они корректно читались при наличии только заголовка, тела и иконки.
Требование для iOS и iPadOS
Эта оговорка решает, жизнеспособен ли web push для мобильной аудитории, и почти везде её излагают неверно.
Apple добавила Web Push в iOS и iPadOS 16.4, и он работает только для веб-приложений, добавленных на домашний экран. Как сформулировала WebKit, «we are adding support for Web Push to Home Screen web apps» и «a web app that has been added to the Home Screen can request permission to receive push notifications». Пользователь добавляет приложение через меню «Поделиться» и «На экран Домой», после чего разрешение нужно запрашивать в ответ на прямое действие пользователя, например нажатие кнопки подписки.
Сайт, открытый в обычной вкладке Safari на iPhone, не может создать push-подписку. Это настоящий барьер: вы просите об установке ещё до того, как получаете право просить разрешение. На macOS проще, потому что Safari 16.1 в macOS Ventura добавил стандартный Web Push для обычных сайтов без шага установки.
Минимальный пример подписки
Это весь клиентский поток целиком. Ему место в обработчике клика, а не при загрузке страницы.
async function subscribeToPush(vapidPublicKey) { // Push и service worker требуют защищённого контекста (HTTPS). if (!("serviceWorker" in navigator) || !("PushManager" in window)) return null;
const registration = await navigator.serviceWorker.register("/sw.js");
// Должно вызываться из жеста пользователя и только один раз на пользователя. const permission = await Notification.requestPermission(); if (permission !== "granted") return null;
const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: vapidPublicKey, // публичный ключ P-256 в кодировке base64url });
// Сохраните эндпоинт и ключи на сервере; относитесь к эндпоинту как к секрету. await fetch("/api/push/subscribe", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(subscription), });
return subscription;}Внутри sw.js вы обрабатываете событие push, вызываете self.registration.showNotification(title, options) и обрабатываете notificationclick, чтобы открыть целевой URL.
UX запроса разрешения: где проваливается большинство программ
Никогда не спрашивайте при загрузке страницы
У Lighthouse есть отдельная проверка на этот счёт: «if your page asks for permission to send notifications on page load, those notifications may not be relevant to your users or their needs». Рекомендация состоит в том, чтобы предложить конкретный тип уведомлений и запрашивать разрешение только после того, как пользователь согласился на этот тип. Safari 12.1 и другие браузеры пошли дальше и требуют взаимодействия со страницей, прежде чем запрос вообще может быть сделан.
Используйте мягкий предварительный запрос
Сначала покажите собственное приглашение на странице. Оно называет ценность, его можно закрыть без необратимых последствий, и только клик по нему запускает настоящий диалог браузера. Того, кто проигнорировал ваш мягкий запрос сегодня, можно спросить снова через месяц. Того, кто нажал «Блокировать», нельзя. Работает это при двух правилах: описывайте, что вы действительно будете присылать, а не «получайте обновления», и никогда не подстраивайте ошибочный клик, потому что случайное согласие даёт мгновенную отписку.
Спрашивайте в контексте
Собственная рекомендация Chrome звучит так: «let your users take the initiative and turn on notifications at their own pace», размещая переключатели скромно внутри существующих элементов интерфейса, и избегать «showing prompts and/or overlays without context or immediately after a user lands on the site».
Работающие моменты в электронной коммерции вполне конкретны: элемент «сообщить, когда снова появится» на распроданном товаре, страница подтверждения заказа с предложением следить за доставкой, переключатель отслеживания цены на часто просматриваемом товаре. Разрешение обменивается на названную выгоду, а не выманивается.
Отказ практически необратим
Когда человек блокирует уведомления, браузер сохраняет это решение для вашего источника. Последующие вызовы Notification.requestPermission() возвращают сохранённое значение denied, ничего не показывая, поэтому собственный пример MDN проверяет Notification.permission до того, как вообще вызвать requestPermission(). Снять блокировку означает копаться в настройках сайта, чего фактически никто не делает.
Что делают браузеры, когда вы ошибаетесь
Последствия уже не сводятся к низкой доле подписок.
- Chrome автоматически переводит источники с очень низкой долей согласий в более тихий интерфейс разрешений, отдельно по типам устройств, подавляя запрос для всех.
- Chrome ограничивает частоту для сайтов, которые сочетают большой объём push с низкой вовлечённостью, и возвращает HTTP 429. Эскалация идёт один день, затем семь, затем четырнадцать, и сбрасывается только после 42 подряд идущих дней без нарушений.
- Chrome теперь автоматически отзывает разрешение на уведомления у сайтов, с которыми пользователь давно не взаимодействовал, там где есть «very low user engagement and a high volume of notifications being sent». Обоснование Google звучит жёстко: «Less than 1% of all notifications receive any interaction from users».
Вы можете потерять уже заработанных подписчиков просто потому, что плохо отправляете.
Web push в сравнении с email и SMS
| Фактор | Web push | SMS | |
|---|---|---|---|
| Охват | Только браузеры, давшие согласие | Любой, у кого есть адрес | Любой, у кого есть номер |
| Предельная стоимость | Практически нулевая | Очень низкая | За сообщение, самая высокая |
| Скорость | Секунды, показ через ОС | От минут до дней, теряется во входящих | Секунды |
| Длина сообщения | Заголовок и короткое тело | Не ограничена, богатое оформление | Примерно 160 символов на сегмент |
| Согласие | Диалог браузера, один клик | Сбор адреса, желательно double opt-in | Явное и жёстко регулируемое |
| Идентичность | Браузер на одном устройстве | Человек | Человек |
| Переносимость | Отсутствует | Полная выгрузка | Полная выгрузка |
Разница во владении, которая меняет стратегию
Push-подписка является URL-возможностью, привязанной к одному профилю браузера на одном устройстве. Это не человек. Один и тот же клиент с Chrome на ноутбуке и Firefox на телефоне даёт две несвязанные подписки, и вы не можете знать, что это один человек, пока он не представится сам.
Она также не переносима. Список email можно выгрузить и завтра загрузить в другую платформу. Push-подписки перенести между вендорами нельзя, потому что ключи и привязка VAPID созданы под конкретный ключ сервера приложения.
Поэтому относитесь к web push как к ускорителю собственного канала, а не как к его замене. Используйте момент push, чтобы получить адрес email или номер телефона, а не наоборот. Полное руководство по автоматизации маркетинга разбирает, как связать несколько каналов в один сценарий.
Сценарии, которые действительно работают
Канал вознаграждает сообщения, которые чувствительны ко времени, лично релевантны и выполнимы в одно касание.
- Брошенная корзина. Push в течение часа, подкреплённый письмом позже. Руководство по письмам о брошенной корзине разбирает последовательность.
- Оповещения о возврате товара в наличие. Сильнейший случай, потому что пользователь сам попросил сообщить.
- Снижение цены на отслеживаемые товары. Та же логика, самостоятельно выбранная релевантность.
- Доставка и статус заказа. Высокая готовность открыть, низкий риск жалоб.
- Срочные обновления по подписанной теме. Новости, результаты, окна доступности.
Что проваливается, столь же очевидно: общие рассылки «мы опубликовали новый пост», недифференцированные ежедневные акции, всё, чему нужно больше заголовка и одной строки, реанимационные веерные отправки подписчикам, которые проигнорировали последние двадцать уведомлений, и транзакционное содержимое, требующее долговременной записи.
Частота, тайминг и сегментация
Начинайте консервативно: от одного до трёх уведомлений на подписчика в неделю, расширяя только если доля отписок и кликов держится. Усталость проявляется быстрее, чем в email, потому что выключение стоит одного касания на уведомлении, которое операционная система уже показала.
Тайминг является и преимуществом, и опасностью. Push приходит немедленно, поэтому сообщение, отправленное в 02:00, придёт в 02:00. Сохраняйте или выводите часовой пояс подписчика в момент подписки и держите отправки внутри заданного окна.
Сегментация ограничена тем, что вы знаете о подписке, а не о человеке, поэтому рабочими измерениями являются поведенческие: просмотренные страницы, отслеживаемые товары, состояние корзины, давность покупки, платформа. Руководство по сегментации клиентов идёт глубже.
Как измерять web push
Значение имеют четыре метрики, и измеряются они по-разному.
- Доставка. Принял ли push-сервис запрос. Ответ 201 означает принято, а не доставлено. Ответ 404 или 410 означает, что подписка мертва.
- Показ. Было ли уведомление показано. Вы знаете это только если service worker отчитывается, когда
showNotification()завершается. - Кликабельность. Клики, делённые на показы. Именно это число стоит оптимизировать.
- Доля отписок. Отписки и отзывы разрешения на отправку. Следите за ней внимательнее, чем за кликабельностью, потому что она является опережающим индикатором смерти канала.
Ловушки атрибуции
Атрибуция push льстит себе. Уведомление приходит на устройство, которое подписчик и так держит в руках, поэтому оно часто приписывает себе сессию, которая случилась бы в любом случае. Используйте контрольные группы вместо предположений об инкрементальности. Показы недосчитываются, тогда как каждый клик фиксируется, поэтому кликабельность, посчитанная от отправок, завышает результат. А поскольку подписка является браузером, а не человеком, push, кликнутый на телефоне и завершившийся покупкой на десктопе, выглядит как два несвязанных события. Руководство по метрикам email-маркетинга разбирает гигиену измерений по всем каналам.
Согласие, GDPR и отписка
Разрешение в браузере является техническим шлагбаумом. Оно не становится автоматически полноценным правовым основанием для маркетинга.
Если вы ведёте маркетинг людям в ЕС или Великобритании, относитесь к push так же, как к email. Объясните, что будете присылать, до появления запроса, чтобы согласие было информированным и конкретным. Фиксируйте, когда и где создана подписка, и никогда не привязывайте согласие на push к постороннему действию. Если вы связываете подписки с идентифицированными клиентами, эти данные попадают в ваши обязанности по персональным данным, включая запросы на удаление.
Гигиена отписки важна ровно так же. Дайте на сайте настройку предпочтений, чтобы люди могли снизить частоту вместо блокировки, вызывайте PushSubscription.unsubscribe() и удаляйте запись на сервере, когда они это делают, и вычищайте подписки при ответе 404 или 410. Рекомендация MDN коротка и верна: пользователям следует «offered an easy way to opt out of getting more in the future».
Место web push в стеке каналов
Web push является хорошим третьим каналом и плохим первым: быстрый, бесплатный на пределе и непревзойдённый для срочных оповещений, но привязанный к устройству, невыгружаемый и в одном клике от безвозвратной потери.
Из-за этого настоящей задачей становится оркестрация. Какое сообщение уходит в какой канал, как подавить письмо, если push уже сконвертировал, и как удержать единое представление о клиенте на поверхностях, которые опознают людей по-разному. Brevo предлагает web и мобильный push наряду с email и SMS, а Tajo работает поверх Brevo и координирует эту кросс-канальную логику для магазинов на Shopify. По части SMS смотрите руководство по автоматизации SMS.
Главное
- Web push является тремя взаимодействующими API: service worker для фонового выполнения, Push API для подписки и транспорта, Notifications API для показа. Подписка является эндпоинтом плюс ключ
p256dhи секретauth, полезные нагрузки шифруются сквозным образом, а VAPID подтверждает отправителя. - Push имеет статус Baseline widely available с марта 2023 года, но на iOS и iPadOS работает только для веб-приложений, добавленных на домашний экран.
- Никогда не запрашивайте разрешение при загрузке страницы. Используйте мягкий предварительный запрос, спрашивайте в контексте и помните, что блокировка навсегда закрывает этот источник.
- Chrome теперь применяет тихие запросы, лимиты частоты и автоматический отзыв разрешения, поэтому плохие отправки стоят вам уже заработанных подписчиков.
- Подписка является браузером, а не человеком, и выгрузить её нельзя. Сначала стройте базу email, а push используйте для ускорения.