> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.onesignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Notificaciones duplicadas

> Solucione notificaciones push duplicadas causadas por conflictos de SDK, reintentos del servidor, entornos multi-app y bugs específicos de plataforma.

Las notificaciones duplicadas ocurren cuando el mismo dispositivo recibe el mismo contenido de mensaje más de una vez. Esta guía cubre las causas más comunes y cómo resolverlas.

Si el mismo usuario ve la notificación en múltiples dispositivos (teléfono, tablet, escritorio), ese es el comportamiento esperado según su configuración de segmentación (segmentos, ID externos, etc.). Para mensajes in-app duplicados, consulte la guía de [solución de problemas de mensajes in-app](./in-app-message-troubleshooting#duplicated-in-app-messages).

<Info>
  Apple reconoció un error en iOS 17 que causaba duplicados. Esto se corrigió en iOS 17.3. [Leer más](https://forums.developer.apple.com/forums/thread/747044).
</Info>

## Comience aquí

Seleccione la sección que mejor se ajuste a su situación:

* Su servidor reintenta llamadas API fallidas o su pipeline de backend puede enviar duplicados → [El mismo mensaje enviado varias veces](#el-mismo-mensaje-enviado-varias-veces)
* Su aplicación usa Firebase u otro SDK de push junto con OneSignal → [Manejadores de notificaciones de terceros](#manejadores-de-notificaciones-de-terceros)
* Su aplicación Android personaliza notificaciones en código (extensión de servicio o listener en primer plano) → [Manejadores de notificaciones Android](#manejadores-de-notificaciones-android)
* Su aplicación iOS implementa su propio `UNUserNotificationCenterDelegate` → [Manejador en primer plano de iOS](#manejador-en-primer-plano-de-ios)
* Solo ve duplicados en compilaciones de desarrollo o con múltiples instalaciones → [Múltiples instancias de aplicación](#múltiples-instancias-de-aplicación)

## El mismo mensaje enviado varias veces

La causa más común es enviar la misma carga útil de notificación más de una vez a través de la API de OneSignal. Razones comunes:

* Su servidor reintenta solicitudes sin verificar si la primera tuvo éxito.
* Duplicación de lógica en su pipeline de backend que envía la misma notificación dos veces.
* Está migrando a OneSignal pero todavía envía notificaciones desde un proveedor anterior. Evite enviar desde ambos sistemas al mismo tiempo.

<Card title="Solicitudes de API idempotentes" icon="rotate" href="/reference/idempotent-notification-requests">
  Evite mensajes duplicados reutilizando claves de idempotencia en los reintentos.
</Card>

## Manejadores de notificaciones de terceros

Los duplicados pueden ocurrir cuando otro código en su aplicación procesa la carga útil push de OneSignal y muestra su propia notificación además de la de OneSignal. Esto incluye:

* Otros SDKs de push remoto (por ejemplo, Firebase Cloud Messaging) que reciben la misma carga útil.
* Manejadores de mensajes personalizados como un `FirebaseMessagingService` en Android o un `UNUserNotificationCenterDelegate` en iOS que leen la carga útil entrante y construyen una notificación local a partir de ella.

El SDK de OneSignal filtra automáticamente las cargas útiles de OneSignal cuando es el único manejador. El código de terceros no sabe que debe filtrarlas a menos que se le indique.

### Identificación de notificaciones de OneSignal

Cada notificación de OneSignal incluye un objeto `custom` con una clave `i` que contiene el UUID de la notificación de OneSignal:

```json JSON theme={null}
{
  "custom": {
    "i": "the-notification-id"
  }
}
```

Para la referencia completa de la carga útil, consulte [Estructura de carga útil personalizada de OneSignal](./osnotification-payload#custom-onesignal-payload-structure).

### Filtrar notificaciones de OneSignal en manejadores de terceros

En cualquier manejador que no sea de OneSignal, verifique la clave `custom.i` y retorne anticipadamente cuando esté presente. OneSignal entonces maneja sus propias cargas útiles mientras su otro código continúa procesando las suyas.

<Tabs>
  <Tab title="Android">
    En un `FirebaseMessagingService` personalizado u otro manejador de mensajes remotos:

    ```kotlin Kotlin theme={null}
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        val customJson = remoteMessage.data["custom"]
        if (customJson != null) {
            try {
                val custom = JSONObject(customJson)
                if (custom.has("i")) {
                    // Notificación de OneSignal — dejar que el SDK de OneSignal la maneje
                    return
                }
            } catch (e: JSONException) {
                // No es una carga útil de OneSignal, continuar
            }
        }

        // Manejar su propia notificación aquí
    }
    ```
  </Tab>

  <Tab title="iOS">
    En su `UNUserNotificationCenterDelegate` o un manejador de notificaciones personalizado:

    ```swift Swift theme={null}
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo

        if let custom = userInfo["custom"] as? [String: Any], custom["i"] != nil {
            // Notificación de OneSignal — dejar que el SDK de OneSignal la maneje
            completionHandler([])
            return
        }

        // Manejar su propia notificación aquí
    }
    ```
  </Tab>
</Tabs>

<Tip>
  Si controla la estructura de la carga útil enviada desde su otro proveedor, agregue una clave marcadora distinta (por ejemplo, `my_app_notification: true`) y filtre en ambas direcciones — solo maneje notificaciones que contengan su marcador en su propio código, y deje que OneSignal maneje las notificaciones que contengan la clave `custom.i`.
</Tip>

## Manejadores de notificaciones Android

OneSignal expone dos callbacks de Android que le permiten interceptar y personalizar una notificación antes de que se muestre:

* `onNotificationReceived` en una [extensión de servicio de notificaciones](./service-extensions) — se ejecuta para cada push, incluso cuando la aplicación está en segundo plano.
* `onWillDisplay` en un [listener de ciclo de vida en primer plano](./mobile-sdk-reference#addforegroundlifecyclelistener-push) — se ejecuta solo cuando la aplicación está en primer plano.

Los duplicados ocurren cuando estos callbacks muestran la notificación además de la visualización automática de OneSignal.

### La regla de `preventDefault()` y `display()`

OneSignal muestra cada notificación automáticamente a menos que la suprima con `event.preventDefault()`. Dos errores comunes causan duplicados:

* Llamar a `event.getNotification().display()` sin llamar primero a `event.preventDefault()` — muestra la notificación dos veces.
* Publicar una notificación separada con [`NotificationManagerCompat.notify()`](https://developer.android.com/reference/androidx/core/app/NotificationManagerCompat) mientras OneSignal también muestra la original.

Solo una ruta de visualización debe estar activa: el `display()` de OneSignal o su propio `NotificationManagerCompat.notify()`, nunca ambos.

<CodeGroup>
  ```kotlin Kotlin theme={null}
  override fun onNotificationReceived(event: INotificationReceivedEvent) {
      event.preventDefault()

      val notification = event.notification
      notification.setExtender { builder ->
          builder.setColor(0xFF0000FF.toInt())
      }
      notification.display()
  }
  ```

  ```java Java theme={null}
  @Override
  public void onNotificationReceived(INotificationReceivedEvent event) {
      event.preventDefault();

      IDisplayableMutableNotification notification = event.getNotification();
      notification.setExtender(builder ->
          builder.setColor(0xFF0000FF)
      );
      notification.display();
  }
  ```
</CodeGroup>

La misma regla aplica dentro de `onWillDisplay` en un listener de ciclo de vida en primer plano:

```kotlin Kotlin theme={null}
OneSignal.Notifications.addForegroundLifecycleListener(object : INotificationLifecycleListener {
    override fun onWillDisplay(event: INotificationWillDisplayEvent) {
        event.preventDefault()

        // Renderice su propia UI o llame a event.notification.display() para mostrar la notificación de OneSignal
    }
})
```

<Warning>
  Si llama a `preventDefault()` pero nunca llama a `display()`, la notificación se descarta silenciosamente y el usuario no la ve. Cada ruta de código debe llamar a `display()` una vez o suprimir intencionalmente la notificación.
</Warning>

<Warning>
  Si usa tanto una extensión de servicio de notificaciones como un listener de ciclo de vida en primer plano, asegúrese de que solo un manejador muestre la notificación para un estado de aplicación determinado. Llamar a `display()` desde ambos produce duplicados.
</Warning>

### Trabajo asíncrono dentro de callbacks

Cuando realice trabajo en segundo plano (llamadas de red, consultas a base de datos) antes de mostrar, llame a `preventDefault()` de forma síncrona en el callback y llame a `display()` solo después de que el trabajo asíncrono se complete. Retornar del callback sin `preventDefault()` permite que OneSignal muestre la notificación, y una llamada posterior a `display()` produce un duplicado.

## Manejador en primer plano de iOS

OneSignal se establece como el `UNUserNotificationCenterDelegate` durante la inicialización del SDK. Si su aplicación también implementa el manejo de notificaciones en primer plano, la notificación puede mostrarse dos veces: una vez desde OneSignal y una vez desde su código.

Patrones comunes que causan duplicados:

* Implementar su propio `UNUserNotificationCenterDelegate` sin reenviar llamadas a OneSignal, luego llamar a `completionHandler([.banner, .sound])` y mostrar una alerta in-app personalizada desde el mismo método.
* Programar una notificación local (`UNUserNotificationCenter.current().add(...)`) en respuesta a un push entrante que OneSignal también está mostrando.

Para controlar la visualización en primer plano sin causar duplicados, use el [listener de ciclo de vida en primer plano](./mobile-sdk-reference#addforegroundlifecyclelistener-push) de OneSignal y llame a `event.preventDefault()` cuando desee renderizar la notificación usted mismo:

```swift Swift theme={null}
OneSignal.Notifications.addForegroundLifecycleListener(self)

func onWillDisplay(event: OSNotificationWillDisplayEvent) {
    event.preventDefault()

    // Renderice su propia UI o llame a event.notification.display() para mostrar la notificación de OneSignal
}
```

## Múltiples instancias de aplicación

<Tabs>
  <Tab title="Android">
    Los duplicados pueden ocurrir cuando tiene instaladas las versiones de producción y desarrollo de su aplicación. Cada aplicación tiene un nombre de paquete único y recibe su propio token push.

    Mantenga presionada la notificación para confirmar qué instancia de aplicación la envió.
  </Tab>

  <Tab title="iOS">
    Si dos registros de dispositivo en OneSignal comparten el mismo token push, el dispositivo puede recibir dos notificaciones. Esto puede suceder cuando el mismo token se importa o registra varias veces. OneSignal incluye verificaciones para prevenir esto, pero los casos extremos pueden eludirlas.
  </Tab>

  <Tab title="Web">
    Los duplicados de web push son causados por suscribirse a múltiples orígenes usando el mismo ID de aplicación de OneSignal. Un [origen](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy) es la combinación de esquema, host y puerto que el navegador usa para delimitar las suscripciones push.

    Por ejemplo, un usuario que se suscribe a `https://example.com` y `https://sub.example.com` cuenta como dos suscripciones, y un envío usando el mismo ID de aplicación llega a ambas.

    Para solucionar esto:

    1. [Restablecer datos del navegador y permisos push](./troubleshooting-web-push) por origen.
    2. Si esto está afectando a muchos usuarios, cree una nueva aplicación de OneSignal y use el nuevo ID de aplicación en el código de inicialización de su sitio.
    3. Haga que los usuarios vuelvan a visitar el sitio y se vuelvan a suscribir.

    Suscribirse en múltiples navegadores o perfiles de navegador también lleva a múltiples notificaciones.
  </Tab>
</Tabs>

## Consejos de diagnóstico

Para depurar duplicados más rápido, recopile y envíe lo siguiente al soporte de OneSignal:

* ID de suscripción de OneSignal del dispositivo que recibió los duplicados
* ID del mensaje de OneSignal o un enlace al mensaje en el panel de control
* Lista de otras bibliotecas o plugins en su aplicación
* [Registro de depuración que reproduzca el problema](./capturing-a-debug-log)
* Pasos de reproducción detallados

## Preguntas frecuentes

### ¿Qué sucede si tengo dos SDKs de notificación en mi aplicación?

Ambos SDKs pueden procesar y mostrar independientemente la misma notificación. OneSignal filtra sus propias notificaciones automáticamente, pero otros SDKs no lo hacen. Filtre las cargas útiles de OneSignal de los manejadores de su otro SDK verificando la clave `custom.i`. Consulte [Manejadores de notificaciones de terceros](#manejadores-de-notificaciones-de-terceros) para ver ejemplos de código.

### ¿Cómo enviar push desde un proveedor anterior y OneSignal al mismo tiempo?

Puede hacer la transición gradualmente, pero evite enviar el mismo mensaje desde ambos proveedores.

* **Android**: Elimine el código de manejo de notificaciones del SDK antiguo al integrar OneSignal y lanzar la aplicación. A medida que los usuarios actualicen, dejarán de recibir push del proveedor antiguo.
* **iOS**: Puede continuar enviando desde el proveedor antiguo temporalmente mientras los usuarios actualizan. Una vez que haya completado la transición, envíe solo desde OneSignal para evitar duplicados.

### ¿Cómo evitar múltiples notificaciones para actualizaciones que cambian rápidamente?

Use un [`collapse_id`](/reference/push-notification#body-parameters) en la API [Crear notificación](/reference/push-notification) para reemplazar notificaciones anteriores en lugar de apilarlas. Cuando varias notificaciones comparten el mismo `collapse_id`, cada nueva reemplaza a la anterior en la bandeja. Esto es útil para actualizaciones de precios de acciones, marcadores en vivo, ETAs de entrega y actualizaciones frecuentes similares.

## Páginas relacionadas

<Columns cols={2}>
  <Card title="Solución de problemas del SDK móvil" icon="mobile" href="./mobile-troubleshooting">
    Resuelva problemas comunes con la entrega de notificaciones push en iOS y Android.
  </Card>

  <Card title="Solución de problemas de web push" icon="browser" href="./troubleshooting-web-push">
    Depure problemas de suscripción, service worker y entrega de web push.
  </Card>

  <Card title="Solución de problemas de mensajes in-app" icon="message" href="./in-app-message-troubleshooting">
    Corrija problemas con la visualización, los disparadores y los duplicados de mensajes in-app.
  </Card>

  <Card title="Extensiones de servicio móvil" icon="gear" href="./service-extensions">
    Intercepte y personalice notificaciones push antes de mostrarlas en iOS y Android.
  </Card>

  <Card title="Notificaciones no mostradas (web)" icon="bell-slash" href="./notifications-not-shown-web-push">
    Solucione notificaciones web push que se envían pero no se muestran.
  </Card>
</Columns>
