Sitios web y PWA (Web Push)

Notificaciones en Chrome, Edge, Firefox, Safari y Opera con el SDK web y un service worker.

Con Web Push tu sitio envía notificaciones al navegador del usuario, aunque la pestaña esté cerrada (con el navegador abierto). Funciona en Chrome, Edge, Opera, Brave y Samsung Internet (Android y escritorio), Firefox y Safari (macOS 13+). En iPhone y iPad solo funciona si el usuario agregó tu sitio a la pantalla de inicio (iOS 16.4+).

El navegador entrega el mensaje cifrado a través de su servicio push (Google, Mozilla, Apple o Microsoft); Pushtifly lo cifra para cada navegador y lo firma con tus llaves VAPID. No hace falta Firebase.

1. Prepara la app en el panel

  1. En la app, en Configuración, marca la plataforma Web (navegadores).
  2. En Credenciales → Web Push, escribe un contacto (mailto:soporte@tuempresa.com o una URL https) y pulsa Generar llaves.
    • ¿Ya usabas otro servicio con tus propias llaves VAPID? Usa Importar llaves con la pública y la privada (base64url): así los navegadores ya suscritos siguen recibiendo.
  3. En API keys, crea una llave pública (pk_live_…) limitada a esta app.

2. Instala el SDK

npm install @daertech/pushtifly-web

Copia node_modules/@daertech/pushtifly-web/dist/pushtifly-sw.js a la raíz pública de tu sitio (que se sirva en https://tusitio.com/pushtifly-sw.js). El navegador solo acepta un service worker de tu mismo dominio.

¿Sin bundler? Usa dist/pushtifly.js con una etiqueta <script>: expone PushtiflyWeb.Pushtifly.

3. Inicia y pide el permiso

import { Pushtifly } from '@daertech/pushtifly-web';

const pushtifly = new Pushtifly({ appKey: 'pk_live_…' });
await pushtifly.init(); // registra /pushtifly-sw.js; si el usuario ya dio permiso, sincroniza la suscripción

// Pide el permiso tras un gesto del usuario: los navegadores bloquean los pedidos automáticos
botonActivar.addEventListener('click', async () => {
  if ((await pushtifly.requestPermission()) === 'granted') {
    console.log('Navegador registrado', pushtifly.state().deviceId);
  }
});

Buenas prácticas para que acepten el permiso: explica antes qué vas a enviar (un banner propio con un botón «Activar») y no lo pidas al cargar la página.

4. Usuarios, tags y topics

await pushtifly.identify('cliente-123');   // al iniciar sesión
await pushtifly.setTags({ plan: 'gold' });
await pushtifly.addTopic('ofertas');
await pushtifly.logout();                  // al cerrar sesión
await pushtifly.unsubscribe();             // el usuario no quiere más notificaciones

5. Al tocar la notificación

El service worker abre la URL de destino (el deep link del envío o del botón; puede ser relativa a tu sitio) y reporta la apertura o el clic. Si tu sitio está abierto, recibes la notificación:

pushtifly.onNotificationClick((n) => console.log(n.id, n.url, n.actionId, n.data));
pushtifly.onData((data) => { /* envíos de solo datos con la página abierta */ });

Qué se muestra

Campo del envío En el navegador
Título y texto (con el subtítulo antes del texto) title y body
Icono grande del envío, o el icono de la app icon
Imagen (o el póster de un GIF o video) image (Chrome y Edge en escritorio y Android)
Deep link URL que se abre al tocar
Botones hasta 2 (actions)
Prioridad alta / normal encabezado Urgency
TTL cuánto guarda el servicio push el mensaje si el navegador está cerrado (máximo 4 semanas)

El contenido cifrado tiene un máximo de 3 993 bytes: el creador lo valida antes de enviar.

Si ya tienes un service worker

Importa el de Pushtifly dentro del tuyo y pásale la configuración:

// tu-sw.js
self.PUSHTIFLY_CONFIG = { appKey: 'pk_live_…' };
importScripts('/pushtifly-sw.js');

y en la página: new Pushtifly({ appKey: 'pk_live_…', serviceWorkerRegistration: await navigator.serviceWorker.register('/tu-sw.js') }).

Con la API, sin el SDK

Registra la suscripción que devuelve PushManager.subscribe() (con la llave de GET /v1/web-push/key):

curl -X POST https://api.pushtifly.com/v1/devices \
  -H "Authorization: Bearer pk_live_TU_LLAVE" -H "Content-Type: application/json" \
  -d '{ "platform": "web", "subscription": { "endpoint": "https://fcm.googleapis.com/fcm/send/…",
        "keys": { "p256dh": "BN…", "auth": "q1…" } } }'

El service worker recibe este JSON (event.data.json()): _phid (id del envío), title, body, icon, image, url, actions ([{ action, title, url }]), tag, data (tus datos) y silent (envío de solo datos). Para reportar aperturas, llama a POST /v1/events con token = el endpoint de la suscripción. Como el token es una URL, las rutas /v1/devices/{token} aceptan también el id del dispositivo.

Problemas comunes

  • El permiso aparece como «bloqueado»: el usuario lo negó; solo puede cambiarlo desde la configuración del sitio en su navegador.
  • No llega nada en iPhone: el sitio debe estar agregado a la pantalla de inicio y abrirse desde ahí.
  • VAPID_KEY_MISMATCH: esa suscripción se creó con otras llaves; el SDK la rehace al abrir el sitio.
  • SUBSCRIPTION_GONE: el navegador dio de baja la suscripción (permiso quitado o datos borrados); Pushtifly marca el navegador como inválido.