Push API y Notificaciones en JavaScript
La Push API en JavaScript es una herramienta esencial para enviar notificaciones en tiempo real a los usuarios, incluso cuando el navegador está en segundo plano.
Introducción a la Push API en JavaScript
La Push API en JavaScript permite que una aplicación web reciba mensajes enviados desde un servidor, incluso cuando la página está cerrada o el navegador está en segundo plano. Es la base de las notificaciones push web: alertas de noticias, mensajes de chat y recordatorios de reenganche que llegan sin que el usuario mantenga una pestaña abierta.
La Push API nunca funciona sola. Se apoya en otras dos características del navegador:
- Un service worker — un script en segundo plano que permanece activo después de que la página se cierra y recibe el push.
- La Notifications API — lo que el service worker utiliza para mostrar el mensaje al usuario.
Esta página cubre el flujo completo del lado del cliente: registrar un service worker, solicitar permiso, suscribirse con una clave VAPID, recibir el push en el service worker y mostrar una notificación. También explica el rol que desempeña tu servidor.
Cómo funciona el flujo de push
La ruta de extremo a extremo de un solo mensaje push es la siguiente:
- Tu página registra un service worker y se suscribe al push. El navegador devuelve un objeto
PushSubscriptionque contiene una URL de endpoint única. - Tu página envía esa suscripción a tu servidor y la almacena.
- Más tarde, tu servidor firma un mensaje con su clave privada VAPID y lo envía al endpoint de la suscripción, que pertenece a un Push Service de un proveedor (Mozilla, Google, Apple, etc.).
- El Push Service despierta el navegador del usuario y dispara un evento
pushen tu service worker. - El service worker muestra una notificación en respuesta.
La Push API requiere un contexto seguro: la página debe servirse a través de HTTPS (localhost se trata como seguro para el desarrollo). Sin ello, navigator.serviceWorker y PushManager no están disponibles.
Implementación de notificaciones push
Configuración de Service Workers
Primero, necesitamos registrar un service worker que gestione las tareas en segundo plano del envío de notificaciones:
// Registering a service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(function(registration) {
console.log('Service Worker registered with scope:', registration.scope);
}).catch(function(error) {
console.log('Service Worker registration failed:', error);
});
}Solicitar permiso para las notificaciones
Antes de enviar notificaciones, es necesario solicitar permiso al usuario. La solicitud debe iniciarse mediante un gesto del usuario (como un clic): los navegadores rechazan los diálogos de permiso que se disparan automáticamente al cargar la página:
<button id="enable-notif-btn">Enable Notifications</button>
<script>
// Asking user permission for notifications
function requestPermission() {
Notification.requestPermission().then(function(permission) {
console.log('Notification permission:', permission);
});
}
document.getElementById('enable-notif-btn').addEventListener('click', requestPermission);
</script>Suscribirse a notificaciones push
Tras obtener el permiso, la aplicación puede suscribirse a las notificaciones push. La applicationServerKey debe ser un Uint8Array, no el string en base64 que normalmente se almacena, por lo que hay que convertirlo primero. VAPID (Voluntary Application Server Identification) es el par de claves que permite al Push Service verificar que los pushes realmente provienen de tu servidor: la clave pública va aquí, la clave privada permanece en tu backend.
<button id="subscribe-btn">Subscribe to Push Notifications</button>
<script>
// The VAPID public key arrives as a base64url string; the API needs a Uint8Array.
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
const raw = atob(base64);
return Uint8Array.from([...raw].map(c => c.charCodeAt(0)));
}
const VAPID_PUBLIC_KEY = 'YOUR_VAPID_PUBLIC_KEY'; // base64url string from your server
function subscribeToPush() {
navigator.serviceWorker.ready.then(function(registration) {
// userVisibleOnly: true is required — the browser rejects silent push subscriptions.
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(VAPID_PUBLIC_KEY)
});
})
.then(function(subscription) {
console.log('Push subscription:', JSON.stringify(subscription));
// Send the subscription to your backend so it can push to this user later.
return fetch('/api/save-subscription', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription)
});
})
.catch(function(error) {
console.log('Failed to subscribe to push:', error);
});
}
document.getElementById('subscribe-btn').addEventListener('click', subscribeToPush);
</script>Un PushSubscription se serializa a JSON con la URL del endpoint y las keys de cifrado (p256dh y auth). Tu servidor necesita todos estos datos para enviar un mensaje. Establecer userVisibleOnly: true es obligatorio en los navegadores actuales: es una promesa de que cada push dará lugar a una notificación visible para el usuario, razón por la cual los pushes silenciosos en segundo plano no están permitidos en la web.
Gestión de mensajes push entrantes
Para gestionar los mensajes entrantes, el service worker escucha los eventos push. La carga útil enviada llega en event.data; usa event.data.json() (o .text()) para leerla. Envolver showNotification() en event.waitUntil() mantiene el service worker activo hasta que se muestre la notificación:
// Inside service-worker.js
self.addEventListener('push', function(event) {
// Read the payload your server sent (fall back gracefully if there is none).
var payload = event.data ? event.data.json() : {};
var options = {
body: payload.body || 'New notification.',
icon: 'icon.png',
vibrate: [100, 50, 100],
data: { primaryKey: 1 }
};
event.waitUntil(
self.registration.showNotification(payload.title || 'Push Notification', options)
);
});
self.addEventListener('notificationclick', function(event) {
event.notification.close();
event.waitUntil(
clients.openWindow('https://example.com')
);
});
self.addEventListener('pushsubscriptionchange', function(event) {
console.log('Subscription changed, re-subscribing...');
// Re-subscribe using the same parameters
event.registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: 'YOUR_VAPID_PUBLIC_KEY'
}).then(function(newSubscription) {
console.log('Re-subscribed:', newSubscription);
}).catch(function(error) {
console.error('Re-subscription failed:', error);
});
});Este fragmento muestra los tres eventos que vale la pena gestionar: push (mostrar la notificación), notificationclick (enfocar o abrir una ventana cuando el usuario hace clic) y pushsubscriptionchange (volver a suscribirse cuando el navegador rota la suscripción).
El rol del servidor
El navegador no puede enviarse mensajes a sí mismo: todo mensaje se origina en tu backend. El servidor conserva la clave privada VAPID y, para cada suscripción almacenada, envía una solicitud HTTP cifrada y firmada al endpoint de la suscripción. En la práctica, se utiliza una biblioteca de web-push (por ejemplo, web-push en Node.js) en lugar de construir el cifrado manualmente:
// Server side (Node.js) — conceptual example
const webpush = require('web-push');
webpush.setVapidDetails(
'mailto:[email protected]',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY
);
// `subscription` is the JSON object the browser sent to /api/save-subscription
const payload = JSON.stringify({ title: 'Hello', body: 'You have a new message.' });
webpush.sendNotification(subscription, payload)
.catch(err => console.error('Push failed:', err.statusCode));Una respuesta 410 Gone o 404 significa que la suscripción ha expirado: elimínala de tu base de datos. Este es el equivalente en el servidor de gestionar pushsubscriptionchange en el cliente.
Buenas prácticas para las notificaciones push
- Participación del usuario: Diseña las notificaciones para que sean oportunas, relevantes y precisas.
- Cumplimiento de privacidad: Asegúrate siempre de obtener el consentimiento del usuario antes de enviar notificaciones.
- Rendimiento: Gestiona la frecuencia y el momento de las notificaciones para no saturar al usuario.
- Renovación de suscripciones: Las suscripciones push expiran periódicamente. Implementa lógica en el lado del cliente para comprobar el estado de la suscripción y volver a suscribirse cuando sea necesario, o gestiona los eventos de expiración desde el service worker.
Conclusión
La Push API abre un canal de interacción directa con los usuarios, proporcionando una herramienta poderosa para el compromiso. Al aprovechar esta API, los desarrolladores pueden ofrecer una experiencia de usuario más dinámica y receptiva. Una implementación adecuada de las notificaciones push puede mejorar significativamente la funcionalidad y el atractivo de las aplicaciones web, manteniendo a los usuarios informados y comprometidos.