Web Push Notifications
debt(d8/e7/b5/t6)
Closest to 'silent in production until users hit it' (d9), slightly better at d8 because Lighthouse PWA audits can flag missing push/service-worker setup, but absence of push as a feature is not caught by linters — it manifests as low re-engagement metrics.
Closest to 'cross-cutting refactor across the codebase' (e7), because adding web push requires VAPID key generation, service worker registration on the frontend, subscription storage schema in MySQL, a sending pipeline using web-push-php, and permission UX flows — touches frontend, backend, and DB.
Closest to 'persistent productivity tax' (b5), because subscription lifecycle (410 Gone handling, expiry, unsubscribe), VAPID key management, and notification content workflows impose ongoing maintenance across the notification subsystem, though contained to that component.
Closest to 'serious trap' (t7), per the misconception that web push requires a native app — devs wrongly build email-only or native-only flows when iOS Safari 16.4+ PWAs now support the same PHP backend; also the permission-prompt-on-load mistake is a well-known UX trap.
Also Known As
TL;DR
Explanation
Web Push uses three components: Push API (browser API to subscribe), Web Push Protocol (RFC 8030 — standardised push delivery), and Service Worker (receives and displays notifications when the browser is closed). Flow: (1) user grants notification permission, (2) browser creates a push subscription (endpoint URL + encryption keys), (3) PHP backend stores the subscription, (4) PHP sends a push message to the subscription's endpoint via web-push library (minishlink/web-push), (5) push service delivers to browser, (6) service worker shows a notification. VAPID (Voluntary Application Server Identification) authenticates your server to the push service.
Common Misconception
Why It Matters
Common Mistakes
- Requesting notification permission immediately on page load — users deny unsolicited permission requests.
- Not handling push subscription expiry — subscriptions expire or become invalid; handle 410 Gone responses.
- No unsubscribe mechanism — users must be able to revoke permission.
- Sending too many notifications — notification fatigue causes users to revoke permission.
Code Examples
// Immediate permission request — high denial rate:
document.addEventListener('DOMContentLoaded', () => {
Notification.requestPermission(); // Before user understands the value
// 80%+ denial rate for unprompted permission requests
});
// Context-triggered permission request:
orderCompleteButton.addEventListener('click', async () => {
await submitOrder();
// Now user understands value:
if (Notification.permission === 'default') {
const perm = await Notification.requestPermission();
if (perm === 'granted') await subscribeToNotifications();
}
});
async function subscribeToNotifications() {
const sw = await navigator.serviceWorker.ready;
const sub = await sw.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: VAPID_PUBLIC_KEY,
});
await fetch('/api/push/subscribe', {
method: 'POST', body: JSON.stringify(sub)
});
}