Un usuario toca tu enlace —un producto compartido, una invitación, un restablecimiento de contraseña— y la app todavía no está instalada. Aterriza en la App Store o en Google Play, instala la app, la abre y… acaba en una pantalla de inicio genérica. El contexto de lo que tocó ha desaparecido. Ese momento roto es justo lo que el pretende arreglar, y durante años la mayoría de los equipos lo resolvía con Firebase Dynamic Links. Esa opción ya no existe.

Este artículo explica cómo construimos un sistema de deep linking diferido que sobrevive a una instalación —y que opcionalmente puede esperar a un evento de negocio como el login antes de enrutar al usuario— usando de iOS y la API de Google Play en lugar de un servicio de terceros.

Ideas clave

  • El deep linking diferido conserva el destino de un enlace a través de la instalación de la app, de modo que el primer arranque aterriza en la pantalla correcta en vez de en la de inicio.
  • Firebase Dynamic Links quedó obsoleto y cerró el 25 de agosto de 2025: la solución más común ya no existe, y los enlaces existentes han dejado de resolverse.
  • Las alternativas caseras populares —fingerprinting de dispositivo y emparejamiento por portapapeles— son poco fiables, frágiles en privacidad y desaconsejadas por Apple.
  • En iOS, un App Clip ligero captura el enlace antes de que exista la app completa y lo traspasa mediante un contenedor App Group compartido tras la instalación.
  • En Android, la API oficial Play Install Referrer entrega la carga del enlace de forma determinista en el primer arranque.
  • Una cola de enlaces pendientes te permite posponer la navegación hasta que se complete la instalación y se haya disparado un evento de negocio opcional (como un login correcto).

¿Qué es el deep linking diferido?

Un deep link abre una pantalla concreta dentro de una app, por ejemplo myapp://product/42. Un deep link solo funciona si la app ya está instalada. El deep linking diferido elimina esa condición previa: cuando la app no está instalada, el destino se recuerda a través de la visita a la tienda y de la instalación, y la app navega hasta él en el primer arranque.

Lo difícil es el hueco. Entre el toque y el primer arranque, el sistema operativo instala una app nueva que no tiene memoria de lo que tocó el usuario. Llevar una carga útil a través de ese hueco, de forma fiable y sin invadir la privacidad, es el problema entero.

Durante buena parte de la última década, la respuesta por defecto era Firebase Dynamic Links. Se encargaba de la redirección a la tienda, de la carga diferida y de la resolución en el primer arranque en ambas plataformas tras un único SDK.

Google marcó Dynamic Links como obsoleto y cerró el servicio por completo el 25 de agosto de 2025. Los enlaces dejaron de resolverse, y no hay un reemplazo directo de Google. Plataformas de atribución de pago como Branch y AppsFlyer cubren el hueco comercialmente, pero muchos equipos quieren ser dueños del flujo sin una factura por evento ni enviar los clics de sus usuarios a un tercero.

Firebase Dynamic Links ya no es una opción

Si tu deep linking diferido todavía depende de Firebase Dynamic Links, dejó de funcionar el 25 de agosto de 2025. Migrar a Universal Links y Android App Links resuelve el caso de la app instalada, pero no el caso diferido (aún no instalada). Ese hueco es el que cierra este enfoque.

Las alternativas caseras habituales, y sus trampas

Una vez descartado Dynamic Links, la mayoría de las guías recurren a una de dos técnicas caseras. Vale la pena entender ambas precisamente porque son frágiles.

Fingerprinting de dispositivo. La página web registra una «huella» (dirección IP, tamaño de pantalla, versión del sistema, idioma) en el momento del toque. En el primer arranque, la app envía su propia huella a un servidor que intenta emparejar ambas dentro de una ventana corta. Las trampas son serias: las IP compartidas y de operador provocan desajustes, la ventana de emparejamiento es corta, la precisión cae en redes concurridas y el emparejamiento probabilístico de usuarios es exactamente el patrón contra el que empujan las reglas de privacidad de Apple.

Portapapeles. La página web copia la carga útil al portapapeles; la app la lee al arrancar. Desde iOS 14 esto dispara un aviso visible de «pegado desde Safari», los usuarios pueden vaciar el portapapeles y cualquier otra copia por medio destruye la carga.

EnfoquePlataformaFiabilidadPrivacidadEstado
Firebase Dynamic LinksiOS + AndroidAltaAceptableCerrado en ago. 2025
Fingerprinting de dispositivoiOS + AndroidBaja-mediaMalaDesaconsejado
Emparejamiento por portapapelesiOSMediaMuestra aviso de pegadoFrágil
App Clip + App Group (el nuestro)iOSAltaBuenaRecomendado
API Play Install ReferrerAndroidAltaBuenaOficial

Nuestro enfoque: App Clips en iOS, Install Referrer en Android

En lugar de adivinar quién es el usuario después de la instalación, capturamos el enlace de forma determinista en cada plataforma usando un mecanismo de primera parte, y luego convergemos en un único paso de resolución dentro de la app.

iOS: capturar el enlace con un App Clip

Un App Clip es una porción diminuta de tu app (menos de 15 MB) que se lanza casi al instante desde un enlace, un App Clip Code o un código QR, sin una instalación completa. Esa propiedad es exactamente lo que necesitamos: el App Clip se ejecuta antes de que exista la app completa, así que puede ver el enlace original.

El flujo:

  1. El enlace abre el App Clip. iOS entrega la URL de invocación mediante un NSUserActivity.
  2. El App Clip escribe esa URL (más una marca de tiempo) en un contenedor App Group compartido que la app completa también puede leer.
  3. El App Clip muestra un panel de la App Store invitando al usuario a instalar la app completa.
  4. Tras la instalación, la app completa lee el enlace pendiente del mismo contenedor App Group en el primer arranque.
// App Clip — capture the invocation URL into the shared App Group
func scene(_ scene: UIScene, continue activity: NSUserActivity) {
    guard activity.activityType == NSUserActivityTypeBrowsingWeb,
          let url = activity.webpageURL else { return }

    let shared = UserDefaults(suiteName: "group.pro.nerdy.deeplink")
    shared?.set(url.absoluteString, forKey: "pendingDeepLink")
    shared?.set(Date(), forKey: "pendingDeepLinkAt")
}
// Full app — read it once, on first launch after install
let shared = UserDefaults(suiteName: "group.pro.nerdy.deeplink")
if let link = shared?.string(forKey: "pendingDeepLink") {
    DeepLinkQueue.shared.enqueue(link)
    shared?.removeObject(forKey: "pendingDeepLink")
}

Como el App Clip y la app completa comparten el mismo App Group, la carga se traspasa exactamente: sin emparejar huellas, sin avisos de portapapeles, sin conjeturas probabilísticas.

Android: la API Install Referrer de Google Play

Android tiene una respuesta limpia y oficial: la API Play Install Referrer. Adjunta tu carga útil a la URL de Play Store como parámetro referrer, y Google entrega esa cadena exacta a la app en el primer arranque.

https://play.google.com/store/apps/details?id=pro.nerdy.app&referrer=deeplink%3D%2Fproduct%2F42
val client = InstallReferrerClient.newBuilder(context).build()
client.startConnection(object : InstallReferrerStateListener {
    override fun onInstallReferrerSetupFinished(responseCode: Int) {
        if (responseCode == InstallReferrerClient.InstallReferrerResponse.OK) {
            val referrer = client.installReferrer.installReferrer // "deeplink=/product/42"
            DeepLinkQueue.enqueue(referrer)
            client.endConnection()
        }
    }
    override fun onInstallReferrerServiceDisconnected() {}
})

Esto es determinista: la cadena del referrer sobrevive intacta a la visita a la tienda y a la instalación, sin necesidad de emparejamiento en servidor.

Converger en un solo sitio, y esperar al login

Ambas plataformas alimentan ahora la misma cola de enlaces pendientes dentro de la app. Construimos exactamente esto para nuestra plataforma de cashback y fidelización, y lo hacemos en nuestro trabajo de desarrollo de apps con Flutter con un pequeño platform channel que expone la carga nativa a Dart, y después un único resolutor decide cuándo actuar.

El «cuándo» importa. Un deep link a una pantalla autenticada (/orders/42) fallará en un arranque en frío si el usuario aún no ha iniciado sesión. Así que el resolutor no navega de inmediato: retiene el destino hasta que la app está lista y cualquier evento de negocio requerido se ha disparado.

class DeepLinkQueue {
  Uri? _pending;
  bool _authReady = false;

  void enqueue(Uri link) { _pending = link; _tryResolve(); }

  // Called by the business layer, e.g. after a successful login
  void onEvent(AppEvent event) {
    if (event == AppEvent.loggedIn) _authReady = true;
    _tryResolve();
  }

  void _tryResolve() {
    final link = _pending;
    if (link == null || !_authReady) return; // wait for both
    _pending = null;
    router.go(link.path); // safe: app is installed AND the user is logged in
  }
}

El resultado es un deep link diferido robusto frente a los dos modos de fallo que rompen la mayoría de las implementaciones: que la app no esté instalada y que la pantalla de destino no esté lista.

Cuándo encaja este enfoque

Este patrón brilla cuando controlas tanto el origen del enlace como la app, quieres fiabilidad de primera parte y te importan la privacidad o el coste de un proveedor. Si solo necesitas el caso de la app instalada, bastan los Universal Links y los App Links a secas. Si necesitas atribución de marketing multicanal con cuadros de mando, una plataforma de pago como Branch puede merecer el gasto. Pero para flujos de producto —invitaciones, contenido compartido, onboarding, restablecimiento de contraseñas—, los App Clips más la API Install Referrer te dan un deep link diferido determinista y completamente tuyo.

Si estás migrando desde Firebase Dynamic Links o construyéndolo desde cero, podemos ayudarte a sacarlo adelante.

Preguntas frecuentes

El deep linking diferido conserva el destino de un enlace a través de la instalación de la app. Cuando un usuario toca un enlace sin tener la app instalada, el destino se recuerda, el usuario instala la app y en el primer arranque la app le lleva al destino original en lugar de a una pantalla de inicio genérica.
Google marcó Firebase Dynamic Links como obsoleto y cerró el servicio el 25 de agosto de 2025. Los enlaces existentes dejaron de resolverse, así que cualquier producto que dependiera de él necesita un reemplazo para el deep linking diferido.
Un App Clip se lanza al instante desde un enlace sin una instalación completa, captura la URL de invocación y la escribe en un contenedor App Group compartido. Después de que el usuario instale la app completa, esta lee ese enlace guardado en el primer arranque y lleva al usuario al destino original.
Sí. La API Install Referrer es una API oficial de Google que entrega a la app, en el primer arranque, la cadena de referrer adjunta a un enlace de Play Store. Es determinista, a diferencia del fingerprinting de dispositivo, así que la carga del deep link llega intacta.
Sí. Guarda el enlace resuelto en una cola de pendientes y ejecuta la navegación solo después de que se dispare el evento de negocio requerido, como un login correcto. Eso te permite llevar a los usuarios a pantallas autenticadas que de otro modo fallarían en un arranque en frío.