Notificaciones push y alertas en tiempo real para web
Cómo diseñar un sistema de notificaciones push y alertas en tiempo real para tu aplicación web
He visto demasiados sistemas de notificaciones nacer así: alguien pide "que avise por correo cuando pase X", se cablea a pelo en el controlador, y dos años después hay catorce sitios del código mandando mails, push y mensajes Slack, ninguno respeta las preferencias del usuario y nadie sabe quién genera ese resumen semanal que todos mandan a spam. Si vas a montar notificaciones push y alertas en tiempo real en una aplicación web a medida, trátalo como un subsistema con su arquitectura, sus métricas y su política de respeto por la atención del usuario.
Cuento aquí cómo lo monto cuando me dejan diseñarlo desde cero y dónde compensa pelearse con Web Push frente a tirar de SSE o WebSockets.
Arquitectura del sistema de notificaciones: componentes y flujo de datos
Lo primero, separar capas. Si no, acabas con lógica de negocio, plantillas de correo y llamadas push entrelazadas en el mismo método. Cuatro capas.
Capa de generación de eventos. Cada módulo emite eventos cuando pasa algo potencialmente notificable: un pedido cambia de estado, alguien menciona a un usuario, un cron falla. Esos eventos van a un bus interno (RabbitMQ, Kafka o Redis Streams, según volumen) con un esquema fijo: tipo de evento, actor, destinatario, timestamp, prioridad y payload. El módulo que dispara el evento no sabe cómo se entrega.
Capa de enrutamiento y reglas. Un servicio que consume el bus y decide. Mira las preferencias del destinatario, aplica agrupación (15 comentarios nuevos en el mismo hilo no son 15 notificaciones, son una con un contador), aplica deduplicación y escupe instrucciones de entrega por canal. Aquí vive la inteligencia del sistema; mantenlo aislado porque vas a cambiar reglas constantemente.
Capa de entrega por canal. Un adaptador por canal, con su cola y reintentos:
- Notificaciones push en el navegador con la Push API del W3C y Service Workers.
- Alertas en tiempo real dentro de la aplicación (in-app), persistidas en base de datos y empujadas al cliente por Server-Sent Events o una conexión persistente.
- Correo electrónico vía un servicio transaccional (Amazon SES, Postmark, Mailgun). No montes tu propio MTA, no merece la pena.
- Mensajería instantánea contra Slack o Microsoft Teams a través de sus APIs.
Capa de almacenamiento y consulta. Toda notificación se persiste antes de intentar entregarse. Eso te da el centro de notificaciones del usuario, el historial para depurar quejas del tipo "no me llegó nada" y las métricas de entrega y apertura. Si solo persistes lo entregado, estás ciego cuando algo falla.
Partir el sistema así es operativo: cada capa escala por su cuenta, cambias reglas sin tocar la generación de eventos, y cuando el correo se cae no se lleva el resto.
Notificaciones push en el navegador: implementación técnica
Las notificaciones push del navegador llegan al usuario aunque tenga la pestaña cerrada. La implementación se apoya en tres piezas del estándar web, y la mayoría de problemas que verás están en cómo se piden los permisos, no en el código.
Service Worker. Un script que el navegador ejecuta en segundo plano, al margen de las pestañas. Intercepta eventos push y dispara la notificación. Si lo registras tarde, no recibes nada, y depurarlo es tedioso porque su ciclo de vida tiene su propia lógica.
Push API. Permite al servidor mandar mensajes al Service Worker a través del servicio push del navegador (FCM en Chromium, el suyo en Firefox). El flujo, sin maquillar:
- La aplicación pide permiso al usuario para notificaciones push.
- Si acepta, el navegador genera una suscripción con un endpoint y claves de cifrado.
- La aplicación manda esa suscripción al servidor y la guarda asociada al usuario.
- Cuando hay que notificar, el servidor envía un POST cifrado al endpoint según el protocolo Web Push (RFC 8030 y RFC 8291).
- El servicio push reenvía el mensaje al Service Worker, que lo descifra y muestra la notificación.
Notifications API. El Service Worker la usa para pintar la notificación con título, cuerpo, icono y acciones. Al pulsarla, abres la URL relevante.
Y ahora el detalle por el que la mitad de los sistemas push fracasan: el momento del prompt. Si pides permiso al navegador en el primer segundo de la primera visita, tienes garantizado el rechazo y los navegadores empiezan a penalizarte. Lo que funciona es un prompt en dos pasos: primero una explicación dentro de tu interfaz con contexto sobre qué vas a mandar y por qué le interesa; cuando el usuario acepta esa pre-petición, disparas la del navegador. El salto de aceptación pasa del 3-5 por ciento al 15-25 por ciento. Se conoce desde hace años y aun así se ve hecho mal en muchos productos.
Alertas en tiempo real dentro de la aplicación
Cuando el usuario tiene la pestaña abierta, las alertas en tiempo real dentro de la interfaz pasan a ser el canal principal. La discusión suele ser la misma: ¿SSE, WebSockets, long polling? La elección afecta a latencia, consumo y operación, así que conviene tener criterio.
Server-Sent Events (SSE). Una conexión HTTP unidireccional servidor a cliente. El servidor la mantiene abierta y empuja eventos según hay novedades. El cliente recibe cada alerta como un evento con un campo data en JSON. SSE gestiona la reconexión automáticamente y permite retransmitir mensajes perdidos usando el identificador del último evento recibido. Para notificaciones, donde el flujo dominante es servidor a cliente, SSE es casi siempre la opción sensata: menos código, menos infraestructura y se lleva bien con balanceadores HTTP estándar.
WebSockets. Si tu aplicación ya necesita comunicación bidireccional (editor colaborativo, dashboard interactivo, chat), aprovecha el canal WebSockets que ya tienes y mete las notificaciones por ahí. Si lo único que necesitas es entregar mensajes del servidor al cliente, montar WebSockets solo para esto es matar moscas a cañonazos: más recursos, balanceo más complicado y te toca manejar pings/pongs y reconexiones tú.
Estrategia de recuperación. Al reconectar, el cliente manda un cursor (timestamp o id secuencial de la última notificación recibida) y pide todas las posteriores. Sin esto, un corte de red de cinco segundos deja al usuario con notificaciones que no aparecen nunca. En móviles con red intermitente es crítico.
Presentación en la interfaz. Tres piezas que se complementan:
- Un badge numérico sobre el icono de notificaciones con el contador de no leídas.
- Un toast que aparece unos segundos en una esquina para las de prioridad alta.
- Un centro de notificaciones, panel desplegable o página, donde el usuario ve el histórico completo.
Priorización inteligente y agrupación para evitar la fatiga
El problema serio de un sistema de notificaciones no es técnico, es de producto: notificar demasiado. Una app que satura acaba ignorada o desinstalada. Los usuarios revocan el permiso push, mandan tus correos al spam y dejan de abrir la pestaña. A partir de ahí, cualquier mensaje legítimo tiene la batalla perdida.
Niveles de prioridad. Tres o cinco niveles, no más, con reglas escritas:
- Crítica. Requiere acción inmediata. Fallo de seguridad, pago rechazado, servicio caído. Va por todos los canales activos y se muestra como alerta prominente.
- Alta. Importante pero no urgente. Tarea asignada, aprobación pendiente. Push e in-app, sin interrumpir lo que el usuario hace.
- Normal. Útil sin más. Comentario en un hilo seguido, actualización de estado. Aparece en el centro de notificaciones y, si el usuario lo activó, también push.
- Baja. Contexto que enriquece pero cuya ausencia no duele. Sugerencias, resúmenes semanales. Centro de notificaciones o resumen agrupado por correo.
Si todo es prioridad alta, nada es prioridad alta. Es la trampa típica: cada equipo defiende que sus eventos son importantes y al final el badge marca 47 cosas.
Agrupación temporal. El enrutador acumula eventos del mismo tipo y mismo destinatario durante una ventana (5 minutos para prioridad normal funciona bien) y manda un resumen. Si cae un evento superior, se entrega al instante y se cierra la ventana.
Agrupación contextual. Eventos sobre el mismo recurso (comentarios en el mismo documento, cambios sobre la misma incidencia) se colapsan bajo una única notificación con el contador de novedades. Recibir cinco mensajes seguidos "Fulano comentó", "Fulano comentó", "Fulano comentó" deja claro que el sistema no piensa por ti.
Horarios de entrega. Respeta el horario del usuario. Fuera de su jornada, prioridades normal y baja se retienen y se entregan como digest al arranque del día siguiente. Solo lo crítico salta esa ventana. Si despiertas a alguien un domingo a las 3 de la madrugada por un cambio de estado normal, has perdido un usuario.
Preferencias del usuario y centro de control de notificaciones
Un sistema maduro deja al usuario controlar qué recibe y por qué canal con granularidad real, no con un switch maestro. Esta pantalla es donde el usuario decide cuánta confianza te tiene; trátala con el mismo cuidado que la de seguridad.
Estructura de preferencias. Una matriz: tipos de notificación en filas, canales en columnas. Cada celda activa o desactiva la entrega de ese tipo por ese canal, con los tipos agrupados por categoría funcional (equipo, sistema, proyectos, seguridad). Olvídate de listas planas con 40 toggles: el usuario abandona.
Defaults conservadores. Los valores por defecto deben asumir que el usuario no toca nada y aun así dar una experiencia equilibrada. Si tu default manda push para todo, lo estás programando para que revoque permisos en una semana.
Silenciamiento temporal. Botón claro: silenciar todo lo no crítico durante una hora, hasta mañana, hasta una fecha. Sin obligarle a desactivar canales uno a uno. Para reuniones o concentración profunda es indispensable.
Historial completo. Mostrar todo lo enviado, incluido lo agrupado o retenido por horario, para que el usuario verifique que no se perdió nada. Sin esto, cualquier confusión se traduce en ticket de soporte.
Si estás planificando el sistema de notificaciones de tu aplicación web a medida y quieres que la arquitectura escale sin destrozar la experiencia, consulta con nuestro equipo técnico para diseñar una solución adaptada a tu volumen y tus requisitos de latencia.
Métricas, observación y evolución del sistema
Lo que no se mide se degrada en silencio. Desde el día uno conviene instrumentar estas métricas.
Tasa de entrega. Porcentaje de notificaciones que llegan al destinatario por cada canal, incluyendo suscripciones push activas frente a expiradas y tasa de rebote en correo. Cuando una suscripción push devuelve 410, bórrala; arrastrar suscripciones muertas distorsiona métricas y consume capacidad.
Tasa de interacción. Porcentaje de notificaciones sobre las que el usuario actúa. Si baja del 2 por ciento para un tipo concreto, ese tipo no aporta nada o se manda con demasiada frecuencia. Apágalo o replantéalo.
Tasa de revocación. Porcentaje de usuarios que desactivan un canal o un tipo en un periodo. Un pico aquí es la señal temprana más fiable de fatiga, mucho antes de que aparezca en usuarios activos.
Latencia de entrega. Tiempo entre la generación del evento y su recepción. Para alertas críticas, por debajo de 3 segundos; si superas eso, revisa la cola del enrutador y los reintentos del canal.
Volumen por usuario. Notificaciones medias por usuario y día. En una app de productividad, pasar de 20-30 al día por usuario es señal clara de que falta agrupación o sobra prioridad alta.
Con estos números arriba, el sistema entra en un ciclo trimestral honesto: revisas datos, ajustas reglas, mides impacto. Ni la intuición del PM ni los focus groups sustituyen esa lectura.
Toda esta arquitectura sirve para una cosa: que cada mensaje entregado se haya ganado el derecho a ocupar la atención del usuario. Un sistema de notificaciones no es un megáfono; es una conversación asimétrica donde tú interrumpes y la otra parte decide si te sigue prestando oído. Cada aviso que no aporta nada erosiona la credibilidad de los que vendrán detrás, y esa credibilidad cuesta meses recuperarla.