Web Push SDK
Браузерный пакет pushdata подписывает браузер на Web Push, регистрирует его в PushData, снимает подписку при выходе и вместе с эталонным service worker отмечает доставку и клик. Работает только с публичным ключом приложения (pk_…), который безопасно хранить в JavaScript страницы; отправки и контакты — с вашего сервера, секретным ключом.
Пакет публикуется. Покаpushdataне появился в npm, соберите его из каталогаapp/sdkрепозитория PushData (pnpm install && pnpm build→dist/) и подключите какfile:-зависимость или скопируйтеdist/index.jsна сайт. API и шаги руководства те же.
Требования: сайт по HTTPS (или localhost), Chrome / Edge / Firefox / Opera, Safari 16.4+ (на iOS — после добавления сайта на экран «Домой»).
1. Ключи приложения
В дашборде откройте Приложения → ваше приложение → Настройки: понадобятся ID приложения и публичный ключ pk_… (раздел «API-ключи»). Секретный ключ pd_… на страницу не попадает.
2. Web Push в PushData
Приложения → ваше приложение → Провайдеры Push → Web Push: нажмите «Сгенерировать ключи VAPID» и укажите контакт (mailto: или URL сайта). Публичный ключ VAPID SDK получает сам (GET /api/v1/public/apps/:id/vapid).
3. Установка
npm install pushdataЭталонный service worker: скачайте app.pushdata.ru/sw.js и положите в корень сайта как /sw.js — воркер обязан быть на том же origin, что и страница. Он показывает уведомление, открывает click_action и сам отмечает delivered / clicked.
4. Подписка
import { PushDataClient } from 'pushdata'
const client = new PushDataClient({
appId: 'APP_ID', // Приложения → Настройки
publicKey: 'pk_…', // Приложения → Настройки → API-ключи (публичный)
apiUrl: 'https://api.pushdata.ru',
// При включённой проверке идентичности — HMAC id пользователя с вашего сервера (шаг 7):
// identityHash: async userId => (await fetch(`/api/pushdata-identity?user=${encodeURIComponent(userId)}`)).text(),
})
if (client.isSupported()) {
// По клику пользователя (браузеры блокируют запрос разрешения без жеста):
// разрешение, регистрация /sw.js, подписка VAPID, POST /api/v1/public/devices.
const device = await client.subscribe({ userId: 'user-123', tags: ['news'] })
console.log(device.id, device.created ? 'new' : 'refreshed')
}Идемпотентно: вызывайте subscribe при каждом визите вошедшего пользователя — подписка обновится, строка устройства останется той же. Без userId SDK держит случайный id браузера, чтобы устройство переподписывалось на свою же строку.
5. Выход пользователя
await client.unsubscribe() // отписка в браузере + DELETE /api/v1/public/devices
const { isSubscribed } = await client.getSubscriptionStatus()6. События
Эталонный воркер отмечает delivered при получении push и clicked при клике по уведомлению (POST /api/v1/events с pushdata_notification_id / pushdata_device_id из payload). Со страницы — client.trackEvent(notificationId, 'opened').
Свой воркер: передайте его путь в swPath и отмечайте события сами:
globalThis.addEventListener('push', (event) => {
const payload = event.data.json()
event.waitUntil(globalThis.registration.showNotification(payload.title, { body: payload.body, data: payload.data }))
})
globalThis.addEventListener('notificationclick', (event) => {
const { pushdata_notification_id, pushdata_device_id, click_action } = event.notification.data ?? {}
event.notification.close()
event.waitUntil(fetch('https://api.pushdata.ru/api/v1/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': 'Public pk_…' },
body: JSON.stringify({ type: 'clicked', notification_id: pushdata_notification_id, device_id: pushdata_device_id }),
}))
})7. Проверка идентичности
При включённой Приложения → Настройки → Проверка идентичности подписка с userId должна нести заголовок X-Identity-Hash — hex HMAC-SHA256 от id пользователя на секрете идентичности приложения. Секрет не попадает в браузер: сделайте авторизованный эндпоинт, который возвращает хэш, и передайте функцию в identityHash. Без него PushData ответит 401 identity_unverified. Анонимной подписке хэш не нужен.
8. Без пакета
Тот же сценарий на чистом JavaScript — регистрация воркера, подписка VAPID, POST /api/v1/public/devices с platform: "web", token (endpoint) и ключами web_push_p256dh / web_push_auth в base64url:
const API = 'https://api.pushdata.ru'
const PUBLIC_KEY = 'pk_…'
const VAPID_PUBLIC_KEY = '…' // Приложения → Провайдеры Push → Web Push
const registration = await navigator.serviceWorker.register(`/sw.js?key=${encodeURIComponent(PUBLIC_KEY)}&api=${encodeURIComponent(API)}`)
const toBytes = (s: string) => Uint8Array.from(atob(s.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0))
const toBase64Url = (buf: ArrayBuffer | null) => btoa(String.fromCharCode(...new Uint8Array(buf ?? new ArrayBuffer(0)))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: toBytes(VAPID_PUBLIC_KEY) })
const res = await fetch(`${API}/api/v1/public/devices`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Public ${PUBLIC_KEY}` },
body: JSON.stringify({
platform: 'web',
token: subscription.endpoint,
web_push_p256dh: toBase64Url(subscription.getKey('p256dh')),
web_push_auth: toBase64Url(subscription.getKey('auth')),
user_id: 'user-123',
}),
})
const { id: deviceId } = await res.json()Публичные эндпоинты отвечают на CORS для любого origin.
9. Проверка
- Откройте сайт, нажмите кнопку подписки, разрешите уведомления.
- Приложения → ваше приложение → Устройства: появилась строка с платформой Web и браузером.
- Отправить уведомление → цель «пользователь» или «устройство» → уведомление появляется в браузере; в карточке уведомления растут
deliveredиclicked.
| Симптом | Проверьте |
|---|---|
NOT_SUPPORTED | HTTPS, поддерживаемый браузер; Safari на iOS — сайт добавлен на экран «Домой» |
PERMISSION_DENIED | разрешение запрошено по клику; в настройках сайта уведомления не заблокированы |
VAPID_MISSING | ключи VAPID сгенерированы у провайдера Web Push |
401 unauthorized | publicKey — ключ pk_ именно этого приложения |
401 identity_unverified | проверка идентичности включена — передайте identityHash или подписывайте анонимно |
| воркер не регистрируется | /sw.js лежит в корне сайта на том же origin, отдаётся с Content-Type: application/javascript |
Ошибки SDK — PushDataError с code (NOT_SUPPORTED, PERMISSION_DENIED, VAPID_MISSING, INVALID_CONFIG или код сервиса: unauthorized, identity_unverified, validation_error, rate_limited).