Skip to content

Повний гайд по Web Push API: Від архітектури до практичної реалізації

Олександр Блажейко · IT Friday · Червень 2026


Пам'ятаєте ті часи, коли вебсайт міг до вас докричатися, лише поки ви тримали його вкладку відкритою? 🙃 Web Push поклав цьому край. Тепер сайт здатен надіслати вам сповіщення навіть тоді, коли вкладка давно закрита, а браузер мирно дрімає у фоні. Фактично PWA отримали суперсилу, якою раніше володіли лише нативні мобільні застосунки. 💪

У цій статті ми детально розберемо, як працює екосистема Web Push, з яких компонентів вона складається та як приготувати її на практиці — без магії, але з парою фокусів. 🎩

1. Як працює Web Push: Три головні кити 🐳

Технологія Web Push тримається на взаємодії трьох основних компонентів. Уявіть їх як трикутник, де всі дружать, але кожен робить свою справу:

  • Клієнтська частина (ваш вебсайт): працює в браузері користувача, відповідає за підписку та взаємодію з інтерфейсом. Це той, хто каже «хочу сповіщення!».
  • Ваш сервер (Application Server): зберігає дані підписок та ініціює надсилання повідомлень. Мозок операції. 🧠
  • Push-служба (Push Service): проміжний сервер, яким керує розробник браузера (наприклад, FCM від Google для Chrome чи сервери Mozilla для Firefox). Вона приймає запит від вашого сервера і доставляє його на пристрій користувача. Такий собі поштар, який ніколи не спить. 📮

Схема життєвого циклу повідомлення:

  1. Крок 1: Підписка. Користувач дає дозвіл (момент священний, не профукайте його — про це нижче 😉). Браузер генерує об'єкт підписки (PushSubscription), який містить унікальний URL (endpoint) push-служби та ключі шифрування.
  2. Крок 2: Збереження. Ваш вебсайт відправляє цей об'єкт PushSubscription на ваш бекенд-сервер, де ви дбайливо зберігаєте (або перезаписуєте) його в базі даних.
  3. Крок 3: Тригер. Коли настає час надіслати сповіщення, ваш сервер бере підписку з БД, шифрує корисне навантаження (payload) і робить POST-запит до push-служби за отриманим URL.
  4. Крок 4: Доставка. Push-служба тримає постійне з'єднання з пристроєм користувача. Вона приймає повідомлення та передає його в браузер. Браузер ніжно «будить» ваш Service Worker (☕ кави йому ніхто не пропонує), а той обробляє подію та показує сповіщення.

2. Роль Service Worker 👷

Web Push не може існувати без Service Worker — спеціального JavaScript-файлу, який браузер виконує у фоновому потоці, ізольовано від конкретної вебсторінки. Це такий працьовитий дядько: сидить собі тихенько у фоні й чекає, поки його гукнуть. Оскільки він не прив'язаний до вкладки, браузер може розбудити його будь-якої миті, щойно push-служба надішле сигнал.

Важливо: через високі вимоги до безпеки Service Workers, а отже, і Web Push, працюють виключно через захищений протокол HTTPS (за винятком localhost для розробки — бо ж самі собі ми довіряємо 😎).

3. Підтримка браузерами та обмеження iOS 🍏

Станом на червень 2026 Web Push уже не є експериментальною можливістю: сучасні версії Chrome, Edge, Firefox і Safari підтримують Push API разом із Service Worker та Notifications API. На десктопі це означає нормальну роботу в основних браузерах, а на Android — у браузерах, які підтримують Service Worker і push-підписки.

Але «підтримує» ще не означає «поводиться однаково». У різних браузерах можуть відрізнятися UX дозволів, політики енергозбереження, обмеження фонової активності, поведінка іконок, badge, actions та доставка повідомлень у режимах на кшталт Do Not Disturb або Focus. Класика жанру: усе ідеально працює в Chrome, а потім ви відкриваєте Safari і починаєте по-новому вірити в долю. 🤷 Саме тому в реальному продукті краще робити не browser detection, а feature detection:

js
const isPushSupported =
  'serviceWorker' in navigator &&
  'PushManager' in window &&
  'Notification' in window;

Особливості iOS та iPadOS

А тепер про Apple — ну куди ж без особливих умов (вони собі не зраджують). 🍎 На iPhone та iPad Web Push має важливе обмеження: він працює не для звичайної вкладки Safari, а лише для вебдодатка, який користувач власноруч додав на Home Screen. Підтримка з'явилася аж в iOS та iPadOS 16.4 для Home Screen web apps (так-так, ми теж довго цього чекали).

Практичні наслідки:

  • сайт має бути встановлений на Home Screen як вебдодаток;
  • бажано мати коректний Web App Manifest із display: "standalone" або display: "fullscreen";
  • запит дозволу на сповіщення має відбуватися тільки після прямої дії користувача, наприклад після натискання кнопки «Підписатися»;
  • користувач може керувати дозволами для такого вебдодатка в системних Notifications Settings так само, як для нативних застосунків;
  • сповіщення можуть потрапляти під правила Focus / Do Not Disturb;
  • для доставки Apple використовує Apple Push Notification service, але окремий акаунт Apple Developer Program для стандартного Web Push не потрібен;
  • якщо на сервері або в інфраструктурі є allowlist для push-endpoint URL, потрібно дозволити *.push.apple.com.

Головний висновок для iOS простий: Web Push там варто проектувати як PWA-сценарій (доповідь про PWA вже на каналі), а не як функцію звичайної сторінки в браузері. Якщо користувач просто відкрив сайт у Safari і не додав його на Home Screen — підписка на push може бути недоступною, і жодні танці з бубном не допоможуть. 🥁

4. Практична реалізація: Крок за кроком 🛠️

Досить теорії — руки тянуться до клави. 👨‍💻

Крок 1: Реєстрація Service Worker та підписка користувача

Спочатку потрібно перевірити підтримку технології та зареєструвати Service Worker на клієнтській стороні:

js
// Перевірка підтримки в браузері
if ('serviceWorker' in navigator && 'PushManager' in window) {
  navigator.serviceWorker.register('/sw.js')
    .then(function(swReg) {
      console.log('Service Worker зареєстровано успішно', swReg);
      initialiseUI(swReg);
    })
    .catch(function(error) {
      console.error('Помилка реєстрації Service Worker', error);
    });
}

Після реєстрації (коли користувач виконав якісь дії на вашому сайті) ми можемо підписати користувача за допомогою методу pushManager.subscribe():

js
function subscribeUser(swReg) {
  // Ключ VAPID вашого сервера (у форматі UInt8Array)
  const applicationServerKey = urlB64ToUint8Array('ВАШ_ПУБЛІЧНИЙ_VAPID_КЛЮЧ');

  swReg.pushManager.subscribe({
    // Обов'язковий параметр: обіцянка завжди показувати сповіщення користувачу
    userVisibleOnly: true,
    applicationServerKey: applicationServerKey
  })
    .then(function(subscription) {
      console.log('Користувача успішно підписано:', JSON.stringify(subscription));

      // Відправляємо об'єкт subscription на свій сервер через fetch/axios
      sendSubscriptionToServer(subscription);
    })
    .catch(function(err) {
      console.log('Не вдалося підписати користувача: ', err);
    });
}

Крок 2: Протокол Web Push та VAPID ключі 🔐

Щоб push-служба розуміла, хто саме надсилає повідомлення, і не дозволяла зловмисникам спамити через ваші ендпоінти, використовується специфікація VAPID (Voluntary Application Server Identification).

Ви генеруєте пару ключів: Public (публічний) та Private (приватний). Публічний ключ використовується під час підписки в браузері, а приватний — залишається на вашому сервері й підписує JWT-токени при кожному запиті до push-служби. Правило просте: приватний ключ — як зубна щітка, нікому не давайте і в Git не комітьте. 🪥

js
const webpush = require('web-push');

const vapidKeys = {
  publicKey: 'ВАШ_ПУБЛІЧНИЙ_КЛЮЧ',
  privateKey: 'ВАШ_ПРИВАТНИЙ_КЛЮЧ'
};

webpush.setVapidDetails(
  'mailto:your-email@example.com',
  vapidKeys.publicKey,
  vapidKeys.privateKey
);

// Об'єкт підписки, отриманий від клієнта з БД
const pushSubscription = { ... };

const payload = JSON.stringify({
  title: 'Нове повідомлення!',
  body: 'Привіт, це пуш-сповіщення з нашого сервера.'
});

webpush.sendNotification(pushSubscription, payload)
  .then(response => console.log('Сповіщення надіслано'))
  .catch(err => console.error('Помилка відправки', err));

Крок 3: Обробка події Push у Service Worker (sw.js)

Коли повідомлення доходить до пристрою, воно викликає подію push всередині вашого sw.js. Ось тут наш джин 👷 нарешті прокидається: розшифровує дані та показує нативне вікно за допомогою self.registration.showNotification().

js
self.addEventListener('push', function(event) {
  console.log('[Service Worker] Отримано Push-повідомлення.');

  let data = {
    title: 'За замовчуванням',
    body: 'Нова подія.'
  };

  if (event.data) {
    data = event.data.json();
  }

  const options = {
    body: data.body,
    icon: '/images/icon.png', // Маленька іконка бренду
    image: '/images/big-image.png', // Велике зображення в тілі сповіщення
    badge: '/images/badge.png', // Іконка для сервісного рядка Android
    tag: 'unique-message-tag', // Дозволяє заміняти попередні пуші з цим тегом
    renotify: true, // Змушує телефон вібрувати знову, якщо тег повторюється
    actions: [
      { action: 'explore', title: 'Переглянути деталі' },
      { action: 'close', title: 'Закрити' }
    ]
  };

  // Очікуємо виконання асинхронної операції відображення
  event.waitUntil(
    self.registration.showNotification(data.title, options)
  );
});

5. Поведінка сповіщень: Кліки та взаємодія 🖱️

Просто показати сповіщення замало — потрібно обробити клік користувача по ньому. За замовчуванням, якщо натиснути на пуш, не станеться рівно нічого (трохи незручно, погодьтеся 😅). Щоб реагувати на взаємодію, використовуємо подію notificationclick:

js
self.addEventListener('notificationclick', function(event) {
  const notification = event.notification;
  const action = event.action;

  notification.close(); // Обов'язково закриваємо сповіщення

  if (action === 'close') {
    return;
  }

  // Відкриваємо сайт або фокусуємося на вже відкритій вкладці
  event.waitUntil(
    clients.matchAll({ type: 'window' }).then(function(windowClients) {
      for (var i = 0; i < windowClients.length; i++) {
        var client = windowClients[i];

        if (client.url === '/' && 'focus' in client) {
          return client.focus();
        }
      }

      if (clients.openWindow) {
        return clients.openWindow('/news-page');
      }
    })
  );
});

6. Досвід користувача (UX Permissions) 🤝

І ось ми дійшли до найважливішого — і водночас найчастіше зіпсованого — аспекту: UX запиту дозволу.

  • Антипаттерн: вистрілити запитом дозволу одразу при першому завантаженні сторінки. Це дуже погана стратегія — більшість користувачів буде злякано тиснути «Блокувати», і другого шансу вже не буде (ніколи так не робіть).
  • Best Practice: використовуйте підхід «двоетапного запиту» (Double-prompt / Soft-ask). Спочатку покажіть власну ввічливу плашку на сайті: «Хочете отримувати сповіщення про нові статті?» (а ще краще після активних дій користувача на вашому сайті). І тільки після того, як користувач сам натисне «Так», викликайте системний запит браузера. Спершу побудуйте довіру — потім просіть дозвіл. 😉

Висновок 🎯

Web Push API — це потужний інструмент залучення та утримання користувачів (Retention). Він вимагає злагодженого тріо: клієнт (Service Worker), ваш сервер (через VAPID) та push-служби. Зберіть цей пазл правильно — і отримаєте надійний міст комунікації зі своєю аудиторією, та додатковий шанс підняти процент Retention

Але пам'ятайте золоте правило: з великою силою приходить велика відповідальність. 🕷️ Сповіщення — це привілей, а не право. Надсилайте лише те, що справді важливо, і користувачі любитимуть ваш застосунок. Завалите їх спамом — і кнопка «Блокувати» спрацює швидше, ніж ваш POST-запит долетить до push-служби. 🚫

Тепер ідіть і пушіть відповідально! 🚀


Джерела:

ІТ П'ятниця · @zloyleva