### Durante el login/registro \{#during-loginsignup\}
Si identificas a los usuarios después del arranque de la app (por ejemplo, tras iniciar sesión o registrarse), usa el método `identify` para establecer su customer user ID.
- Si **no has usado este customer user ID antes**, Adapty lo vinculará automáticamente al perfil actual.
- Si **ya has usado este customer user ID para identificar al usuario antes**, Adapty pasará a trabajar con el perfil asociado a ese customer user ID.
:::important
Los customer user IDs deben ser únicos para cada usuario. Si escribes el valor del parámetro directamente en el código, todos los usuarios se considerarán como uno solo.
:::
Espera a que se ejecute el callback de finalización de `identify` antes de llamar a otros métodos del SDK. Las llamadas concurrentes pueden acabar en el perfil anónimo en lugar del identificado. Consulta [Orden de llamadas en el SDK de Android](android-sdk-call-order).
Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo intermitente que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los flows y paywalls localmente en dos capas: la caché actualizada regularmente descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtenerlos más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para asegurarse de que siempre obtengas la versión más reciente, garantizando la fiabilidad incluso cuando la conexión a internet es limitada.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo límite especificado en `loadTimeout`, ya que la operación puede estar compuesta por diferentes solicitudes internamente.
Para Android: puedes crear un `TimeInterval` con funciones de extensión (como `5.seconds`, donde `.seconds` proviene de `import com.adapty.utils.seconds`), o `TimeInterval.seconds(5)`. Para no establecer ningún límite, usa `TimeInterval.INFINITE`.
| | Parámetro | Descripción | | :-------- | :---------- | | Flow | Un objeto `AdaptyFlow` que contiene el placement, los identificadores (`id`, `variationId`), el nombre, los Remote Configs y un flag `hasViewConfiguration` que indica si el flow incluye una configuración de vista. Para obtener los productos reales con fines de precarga, UI personalizada o comprobaciones programáticas, llama a `getPaywallProducts(flow)`. | ## Obtener la configuración de vista \{#fetch-the-view-configuration\} Tras obtener el flow o el paywall, comprueba si incluye una configuración de vista mediante `flow.hasViewConfiguration`. Este indicador distingue cómo se diseñó el placement en el Adapty Dashboard: - **`true`** — el placement fue diseñado en el **Flow Builder** (un flow) o en el **Paywall Builder** (un paywall). Adapty renderiza la interfaz por ti. Sigue los pasos a continuación para obtener la configuración de la vista y [presentar el flow o el paywall](android-present-paywalls). - **`false`** — el placement es un paywall personalizado sin interfaz del Builder. [Gestiónalo como un paywall de Remote Config](present-remote-config-paywalls-android). :::important Asegúrate de activar el interruptor **Show on device** en el Flow Builder. Si esta opción no está activada, la configuración de la vista no estará disponible para recuperar. :::opcional
predeterminado: idioma del dispositivo
| El identificador de la [localización](add-paywall-locale-in-adapty-paywall-builder), como código de idioma con una o dos subetiquetas separadas por `-` (p. ej., `en`, `pt-br`). Consulta [Localizaciones y códigos de idioma](android-localizations-and-locale-codes). | | **loadTimeout** | predeterminado: 5 seg | Este valor limita el tiempo de espera del método. Si se alcanza el límite, se devolverán los datos en caché o el fallback local. Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo indicado en `loadTimeout`, ya que la operación puede estar compuesta de varias solicitudes internas. |opcional
por defecto: idioma del dispositivo
| El identificador de la [localización](add-paywall-locale-in-adapty-paywall-builder), como código de idioma con una o dos subetiquetas separadas por `-` (p. ej., `en`, `pt-br`). Consulta [Localizaciones y códigos de idioma](android-localizations-and-locale-codes). | | **loadTimeout** | por defecto: 5 seg | Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local. Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo indicado en `loadTimeout`, ya que la operación puede incluir varias solicitudes internas. |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo intermitente que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| ## Personalizar assets \{#customize-assets\} Para personalizar imágenes y vídeos en tu flow o paywall, implementa los assets personalizados. Las imágenes hero y los vídeos tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de assets personalizado, te refieres a estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. Aquí tienes un ejemplo de cómo puedes proporcionar recursos personalizados mediante un diccionario sencillo: ```kotlin showLineNumbers val customAssets = AdaptyCustomAssets.of( "hero_image" to AdaptyCustomImageAsset.remote( url = "https://example.com/image.jpg", preview = AdaptyCustomImageAsset.file( FileLocation.fromAsset("images/hero_image_preview.png"), ) ), "hero_video" to AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), ), ) val flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, ) ``` :::note Si no se encuentra un asset, el flow utilizará su apariencia predeterminada. ::: Para vídeos, puedes pasar opcionalmente una `resolution` para reservar espacio en el layout y establecer la relación de aspecto (`width / height`) antes de que el vídeo cargue: ```kotlin showLineNumbers AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), resolution = AdaptyCustomVideoAsset.Resolution(width = 1080, height = 1920), ) ```opcional
predeterminado: `en`
|El identificador de la [localización del paywall](add-paywall-locale-in-adapty-paywall-builder). Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos utilizarlos.
| | **fetchPolicy** | predeterminado: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En ese caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché de actualización regular descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| | **loadTimeout** | predeterminado: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que, en casos excepcionales, este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede estar compuesta por distintas solicitudes internamente.
Para Android: puedes crear `TimeInterval` con funciones de extensión (como `5.seconds`, donde `.seconds` proviene de `import com.adapty.utils.seconds`), o `TimeInterval.seconds(5)`. Para no establecer ningún límite, usa `TimeInterval.INFINITE`.
| Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Un objeto [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) con una lista de IDs de productos, el identificador del paywall, el Remote Config y otras propiedades. | ## Obtener la configuración de vista de un paywall diseñado con Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Asegúrate de activar el interruptor **Show on device** en el Paywall Builder. Si esta opción no está activada, la configuración de vista no estará disponible para recuperar. ::: Tras obtener el paywall, comprueba si incluye un `ViewConfiguration`, lo que indica que fue creado con Paywall Builder. Esto te guiará sobre cómo mostrar el paywall. Si el `ViewConfiguration` está presente, trátalo como un paywall de Paywall Builder; si no, [trátalo como un paywall de Remote Config](present-remote-config-paywalls).opcional
predeterminado: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de locale](localizations-and-locale-codes) para más información sobre los códigos de locale y cómo recomendamos utilizarlos.
| | **fetchPolicy** | predeterminado: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché cuando existan. En este caso, puede que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la aplicación o mediante una limpieza manual.
| ## Personaliza los recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu paywall, implementa los recursos personalizados. Las imágenes y vídeos hero tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizados, apuntas a estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga una imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. :::important Para usar esta función, actualiza el SDK de Adapty para Android a la versión 3.7.0 o superior. ::: Aquí tienes un ejemplo de cómo proporcionar assets personalizados mediante un diccionario simple: ```kotlin showLineNumbers val customAssets = AdaptyCustomAssets.of( "hero_image" to AdaptyCustomImageAsset.remote( url = "https://example.com/image.jpg", preview = AdaptyCustomImageAsset.file( FileLocation.fromAsset("images/hero_image_preview.png"), ) ), "hero_video" to AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), ), ) val paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, insets, customAssets, ) ``` :::note Si no se encuentra un recurso, el paywall usará su apariencia predeterminada. :::Los insets son los espacios alrededor del flow que evitan que los elementos interactivos queden ocultos tras las barras del sistema.
Por defecto: `Unspecified`, lo que significa que Adapty ajustará los insets automáticamente, lo cual funciona bien para flows edge-to-edge.
Si tu flow no es edge-to-edge, puede que quieras definir insets personalizados. Consulta la sección [Change flow insets](android-present-paywalls#change-flow-insets) a continuación.
| | **customAssets** | opcional | Pasa un objeto `AdaptyCustomAssets` para reemplazar imágenes y vídeos en tu flow o paywall en tiempo de ejecución. Consulta [Customize assets](android-get-pb-paywalls#customize-assets) para más detalles. | | **tagResolver** | opcional | Usa `AdaptyUiTagResolver` para resolver etiquetas personalizadas dentro del texto del flow. Este resolver recibe un parámetro de etiqueta y lo resuelve en la cadena correspondiente. Consulta el tema Custom tags in Paywall Builder para más detalles. | | **timerResolver** | opcional | Pasa el resolver aquí si vas a utilizar funcionalidad de temporizador personalizado. | :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ## Cambiar los márgenes del flow \{#change-flow-insets\} Los márgenes son los espacios alrededor del flow que evitan que los elementos interactivos queden ocultos detrás de las barras del sistema. Por defecto, Adapty ajusta automáticamente estos márgenes, lo que funciona muy bien para flows edge-to-edge. Si tu flow no es edge-to-edge, puede que quieras definir márgenes personalizados: - Si ni la barra de estado ni la barra de navegación se superponen con el `AdaptyFlowView`, usa `AdaptyFlowInsets.None`. - Para configuraciones más personalizadas, por ejemplo si tu flow se superpone con la barra de estado superior pero no con la inferior, puedes establecer solo el `bottomInset` a `0`, como se muestra en el ejemplo siguiente:Los insets son los espacios alrededor del paywall que evitan que los elementos interactivos queden ocultos detrás de las barras del sistema.
Por defecto: `UNSPECIFIED`, lo que significa que Adapty ajustará los insets automáticamente, algo que funciona muy bien para paywalls edge-to-edge.
Si tu paywall no es edge-to-edge, puede que quieras definir insets personalizados. Puedes ver cómo hacerlo en la sección [Change paywall insets](android-present-paywalls#change-paywall-insets) más abajo.
| | **personalizedOfferResolver** | opcional | Para indicar precios personalizados ([más información](https://developer.android.com/google/play/billing/integrate#personalized-price)), implementa `AdaptyUiPersonalizedOfferResolver` y añade tu propia lógica que devuelva `true` para los `AdaptyPaywallProduct` cuyo precio sea personalizado, y `false` en caso contrario. | | **tagResolver** | opcional | Usa `AdaptyUiTagResolver` para resolver etiquetas personalizadas dentro del texto del paywall. Este resolver recibe un parámetro de etiqueta y lo resuelve a la cadena correspondiente. Consulta el tema Custom tags in Paywall Builder para más detalles. | | **timerResolver** | opcional | Pasa el resolver aquí si vas a usar la funcionalidad de temporizador personalizado. | :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ## Cambiar los márgenes del paywall \{#change-paywall-insets\} Los márgenes son los espacios alrededor del paywall que evitan que los elementos interactivos queden ocultos detrás de las barras del sistema. Por defecto, Adapty ajusta automáticamente estos márgenes, lo que funciona perfectamente para paywalls de borde a borde. Si tu paywall no es de borde a borde, puede que quieras definir márgenes personalizados: - Si ni la barra de estado ni la barra de navegación se superponen con `AdaptyPaywallView`, usa `AdaptyPaywallInsets.NONE`. - Para configuraciones más personalizadas, como cuando tu paywall se superpone con la barra de estado superior pero no con la inferior, puedes establecer solo el `bottomInset` a `0`, como se muestra en el ejemplo a continuación:
## El número de vistas del paywall es demasiado alto \{#the-paywall-view-number-is-too-big\}
**Problema**: El contador de vistas del paywall muestra el doble del número esperado.
**Motivo**: Es posible que estés llamando a `logShowFlow` (Android SDK v4+) / `logShowPaywall` en tu código, lo que duplica el recuento de vistas si estás usando el Paywall Builder o el Flow Builder. Para flows y paywalls creados con estas herramientas, el seguimiento de análisis se realiza automáticamente, por lo que no es necesario utilizar este método.
**Solución**: Asegúrate de no llamar a `logShowFlow` (Android SDK v4+) / `logShowPaywall` en tu código si estás usando el Paywall Builder o el Flow Builder.
## Otros problemas \{#other-issues\}
**Problema**: Experimentas otros problemas relacionados con el Paywall Builder que no se cubren aquí.
**Solución**: Si es necesario, migra el SDK a la versión más reciente siguiendo las [guías de migración](android-sdk-migration-guides). Muchos problemas se resuelven en versiones más recientes del SDK.
---
# File: android-quickstart-manual
---
---
title: "Habilitar compras en tu paywall personalizado en Android SDK"
description: "Integra el SDK de Adapty en tus paywalls personalizados de Android para habilitar compras in-app."
---
Esta guía describe cómo integrar Adapty en tus paywalls personalizados. Mantén el control total sobre la implementación del paywall, mientras el SDK de Adapty obtiene los productos, gestiona las nuevas compras y restaura las anteriores.
:::important
**Esta guía es para desarrolladores que implementan paywalls personalizados.** Si buscas la forma más sencilla de habilitar compras, usa el [Adapty Flow Builder](android-quickstart-paywalls). Con Flow Builder, creas flows en un editor visual sin código, Adapty gestiona toda la lógica de compra automáticamente y puedes probar distintos diseños sin volver a publicar tu app.
:::
## Antes de empezar \{#before-you-start\}
### Configurar productos \{#set-up-products\}
Para habilitar las compras in-app, necesitas entender tres conceptos clave:
- [**Products**](product) – todo lo que los usuarios pueden comprar (suscripciones, consumibles, acceso de por vida)
- [**Paywalls**](paywalls) – configuraciones que definen qué productos ofrecer. En Adapty, los paywalls son la única forma de recuperar productos, pero este diseño te permite modificar productos, precios y ofertas sin tocar el código de tu app.
- [**Placements**](placements) – dónde y cuándo muestras paywalls en tu app (como `main`, `onboarding`, `settings`). Configuras los paywalls para los placements en el dashboard y luego los solicitas por ID de placement en tu código. Esto facilita ejecutar pruebas A/B y mostrar diferentes paywalls a diferentes usuarios.
Asegúrate de entender estos conceptos aunque uses un paywall personalizado. En esencia, son simplemente la forma en que gestionas los productos que vendes en tu aplicación.
Para implementar tu paywall personalizado, necesitarás crear un **paywall** y añadirlo a un **placement**. Esta configuración te permite recuperar tus productos. Para entender qué debes hacer en el dashboard, sigue la guía de inicio rápido [aquí](quickstart).
### Gestionar usuarios \{#manage-users\}
Puedes trabajar con o sin autenticación de backend en tu lado.
Sin embargo, el SDK de Adapty gestiona de forma diferente a los usuarios anónimos e identificados. Lee la [guía de inicio rápido de identificación](android-quickstart-identify) para entender las particularidades y asegurarte de trabajar correctamente con los usuarios.
## Paso 1. Obtener productos \{#step-1-get-products\}
Para recuperar los productos de tu paywall personalizado, necesitas:
1. Obtener el objeto `flow` pasando el ID del [placement](placements) al método `getFlow`.
2. Obtener el array de productos para este flow usando el método `getPaywallProducts`.
Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los flows y paywalls en dos capas: la caché actualizada periódicamente descrita anteriormente y los [paywalls de respaldo](android-use-fallback-paywalls). También usamos CDN para obtener flows y paywalls más rápido, y un servidor de respaldo independiente en caso de que el CDN no esté disponible.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el respaldo local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo de espera especificado en `loadTimeout`, ya que la operación puede consistir en diferentes solicitudes internamente.
| ¡No codifiques los IDs de producto de forma fija! Como los flows se configuran de forma remota, los productos disponibles, el número de productos y las ofertas especiales (como las pruebas gratuitas) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si inicialmente obtienes 2 productos, tu app debería mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, tu app debería mostrar los 3 sin necesidad de cambios en el código. Lo único que tienes que codificar de forma fija es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objeto `AdaptyFlow` que contiene el placement, los identificadores (`id`, `variationId`), el nombre, un array `remoteConfigs` (una entrada por cada locale configurado) y un indicador `hasViewConfiguration`. Para obtener los productos del flow, llama a `getPaywallProducts(flow)`. | :::note En la v4, el parámetro `locale` ha pasado de `getFlow` a `getFlowConfiguration` (que solo se usa al renderizar con AdaptyUI). Para paywalls personalizados, todos los idiomas disponibles se devuelven juntos en `flow.remoteConfigs`; elige el que coincida con el idioma del dispositivo del usuario o con la configuración de tu app. ::: ## Obtener productos \{#fetch-products\} Una vez que tienes el flow, puedes consultar el array de productos que le corresponde:Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo intermitente que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro utilizarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
|opcional
predeterminado: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` indica inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](android-localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos utilizarlos.
| | **fetchPolicy** | predeterminado: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen conexiones inestables, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché cuando existan. En ese caso, puede que los usuarios no reciban los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la aplicación y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls en dos capas: la caché de actualización regular descrita anteriormente y los [paywalls de respaldo](android-use-fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| | **loadTimeout** | predeterminado: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede estar compuesta de distintas peticiones internamente.
| ¡No codifiques los IDs de producto de forma fija! Dado que los paywalls se configuran de forma remota, los productos disponibles, su número y las ofertas especiales (como las pruebas gratuitas) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si inicialmente obtienes 2 productos, tu app debería mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, tu app debería mostrarlos todos sin necesidad de modificar el código. Lo único que debes codificar de forma fija es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) con: una lista de IDs de producto, el identificador del paywall, Remote Config y otras propiedades. | ## Obtener productos \{#fetch-products\} Una vez que tienes el paywall, puedes consultar el array de productos que le corresponde:opcional
predeterminado: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](android-localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | predeterminado: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché cuando existan. En este caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.
|Si la solicitud se ha completado correctamente, la respuesta contiene este objeto. Un objeto [AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/) proporciona información completa sobre los niveles de acceso, suscripciones y compras únicas de un usuario dentro de la app.
Comprueba el estado del nivel de acceso para determinar si el usuario tiene el acceso requerido a la app.
| :::warning **Nota:** si todavía usas una versión de StoreKit de Apple inferior a v2.0 y una versión del SDK de Adapty inferior a v2.9.0, debes proporcionar el [secreto compartido de Apple App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret) en su lugar. Apple ha declarado este método como obsoleto. ::: ## Cambiar suscripción al realizar una compra \{#change-subscription-when-making-a-purchase\} Cuando un usuario elige una nueva suscripción en lugar de renovar la actual, el funcionamiento depende del store. En Google Play, la suscripción no se actualiza automáticamente: tienes que gestionar el cambio en el código de tu app como se describe a continuación. Para reemplazar la suscripción por otra en Android, llama al método `.makePurchase()` con el parámetro adicional:Un objeto [`AdaptyProfile`](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/). Este modelo contiene información sobre los niveles de acceso, suscripciones y compras únicas.
Comprueba el **estado del nivel de acceso** para determinar si el usuario tiene acceso a la app.
| :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: --- # File: implement-observer-mode-android --- --- title: "Implementar el modo Observer en el SDK de Android" description: "Implementa el modo Observer en Adapty para rastrear eventos de suscripción de usuarios en el SDK de Android." --- Si ya tienes tu propia infraestructura de compras y no estás listo para migrar completamente a Adapty, puedes explorar el [modo Observer](observer-vs-full-mode). En su forma básica, el modo Observer ofrece analíticas avanzadas e integración fluida con sistemas de atribución y analíticas. Si esto cubre tus necesidades, solo tienes que: 1. Activarlo al configurar el SDK de Adapty estableciendo el parámetro `observerMode` en `true`. Sigue las instrucciones de configuración para [Android](sdk-installation-android#activate-adapty-module-of-adapty-sdk). 2. [Reportar transacciones](report-transactions-observer-mode-android) desde tu infraestructura de compras existente a Adapty. ## Configuración del modo Observer \{#observer-mode-setup\} Activa el modo Observer si gestionas las compras y el estado de la suscripción por tu cuenta y usas Adapty para enviar eventos de suscripción y analíticas. :::important Cuando se ejecuta en modo Observer, el SDK de Adapty no cerrará ninguna transacción, así que asegúrate de gestionarlas tú mismo. :::1. Implementa el `AdaptyUiObserverModeHandler`. El evento `onPurchaseInitiated` te informará de que el usuario ha iniciado una compra. Puedes activar tu flujo de compra personalizado en respuesta a este callback:
1. Implementa el `AdaptyUiObserverModeHandler`. El evento `onPurchaseInitiated` te informará de que el usuario ha iniciado una compra. Puedes activar tu flujo de compra personalizado en respuesta a este callback:
Para iOS, StoreKit 1: un objeto [`SKPaymentTransaction`](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Para iOS, StoreKit 2: un objeto [Transaction](https://developer.apple.com/documentation/storekit/transaction).
Para Android: el identificador de cadena (`purchase.getOrderId()`) de la compra, donde la compra es una instancia de la clase [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la biblioteca de facturación.
|Para iOS, StoreKit 1: un objeto [`SKPaymentTransaction`](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Para iOS, StoreKit 2: objeto [Transaction](https://developer.apple.com/documentation/storekit/transaction).
Para Android: identificador de cadena (`purchase.getOrderId()`) de la compra, donde la compra es una instancia de la clase [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la biblioteca de facturación.
| Para el modo de pantalla completa, donde las barras del sistema se superponen a parte de tu interfaz, obtén los insets de la siguiente manera:phoneNumber
firstName
lastName
| String | | gender | Enum, los valores permitidos son: `female`, `male`, `other` | | birthday | Date | ### Atributos personalizados de usuario \{#custom-user-attributes\} Puedes definir tus propios atributos personalizados, que normalmente están relacionados con el uso de tu app. Por ejemplo, en aplicaciones de fitness pueden ser el número de ejercicios por semana; en apps de aprendizaje de idiomas, el nivel de conocimiento del usuario, etc. Puedes usarlos en segmentos para crear paywalls y ofertas segmentadas, y también en analíticas para identificar qué métricas de producto influyen más en los ingresos.Un objeto [AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/). En general, solo necesitas comprobar el estado del nivel de acceso del perfil para determinar si el usuario tiene acceso premium a la app.
El método `.getProfile` devuelve el resultado más actualizado posible, ya que siempre intenta consultar la API. Si por algún motivo (p. ej., sin conexión a internet) el SDK de Adapty no puede obtener información del servidor, se devolverán los datos de la caché. También es importante tener en cuenta que el SDK de Adapty actualiza la caché de `AdaptyProfile` con regularidad para mantener esta información lo más actualizada posible.
| El método `.getProfile()` te proporciona el perfil del usuario, a partir del cual puedes obtener el estado del nivel de acceso. Puedes tener varios niveles de acceso por app. Por ejemplo, si tienes una app de periódico y vendes suscripciones a distintos temas de forma independiente, puedes crear los niveles de acceso "sports" y "science". Sin embargo, la mayoría de las veces solo necesitarás un nivel de acceso; en ese caso, puedes utilizar simplemente el nivel de acceso "premium" predeterminado. A continuación se muestra un ejemplo para comprobar el nivel de acceso "premium" predeterminado:opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués brasileño.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios trabajan con una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo intermitente que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la app y solo se borra cuando se desinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché actualizada periódicamente descrita anteriormente y los onboardings de respaldo. También utilizamos CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la última versión de tus onboardings y asegurar la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos poco frecuentes este método puede agotar el tiempo de espera ligeramente después del valor especificado en `loadTimeout`, ya que la operación puede consistir en diferentes peticiones internamente.
Para Android: puedes crear un `TimeInterval` con funciones de extensión (como `5.seconds`, donde `.seconds` proviene de `import com.adapty.utils.seconds`), o `TimeInterval.seconds(5)`. Para no establecer ningún límite, usa `TimeInterval.INFINITE`.
| Parámetros de respuesta: | Parámetro | Descripción | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objeto [`AdaptyOnboarding`](https://android.adapty.io/adapty/com.adapty.models/-adapty-onboarding/) con: el identificador y la configuración del onboarding, Remote Config y otras propiedades. | ## Acelera la obtención del onboarding con el onboarding de audiencia predeterminada \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Normalmente, los onboardings se obtienen casi al instante, por lo que no necesitas preocuparte por acelerar este proceso. Sin embargo, cuando tienes muchas audiencias y onboardings, y tus usuarios tienen una conexión a internet lenta, obtener un onboarding puede tardar más de lo deseable. En esas situaciones, puede que quieras mostrar un onboarding predeterminado para garantizar una experiencia fluida en lugar de no mostrar ninguno. Para solucionar esto, puedes usar el método `getOnboardingForDefaultAudience`, que obtiene el onboarding del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el onboarding mediante el método `getOnboarding`, tal como se detalla en la sección [Obtener onboarding](#fetch-onboarding) anterior. :::warning Considera usar `getOnboarding` en lugar de `getOnboardingForDefaultAudience`, ya que este último tiene limitaciones importantes: - **Problemas de compatibilidad**: Puede causar problemas al dar soporte a varias versiones de la app, lo que obliga a diseños retrocompatibles o a asumir que las versiones anteriores podrían mostrarse incorrectamente. - **Sin personalización**: Solo muestra contenido para la audiencia "All Users", eliminando la segmentación por país, atribución o atributos personalizados. Si una obtención más rápida compensa estos inconvenientes en tu caso de uso, utiliza `getOnboardingForDefaultAudience` como se muestra a continuación. De lo contrario, usa `getOnboarding` como se describe [más arriba](#fetch-onboarding). ::: ```kotlin Adapty.getOnboardingForDefaultAudience("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val onboarding = result.value // Handle successful onboarding retrieval } is AdaptyResult.Error -> { val error = result.error // Handle error case } } } ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché si falla. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché cuando existan. En ese caso, puede que los usuarios no reciban los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos sin importar la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché se conserva al reiniciar la app y solo se borra cuando se desinstala la aplicación o mediante una limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché de actualización periódica descrita anteriormente y los onboardings de respaldo. También usamos CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la última versión de tus onboardings y asegurar la fiabilidad incluso cuando la conexión a internet es limitada.
| --- # File: android-present-onboardings --- --- title: "Presentar onboardings en Android SDK" description: "Aprende a presentar onboardings en Android para una mejor captación de usuarios." --- :::tip **A partir del SDK v4**, puedes crear [flows](android-get-pb-paywalls) como una alternativa más potente a los onboardings. A diferencia de los onboardings, que se ejecutan dentro de un WebView, los flows se renderizan de forma nativa en el dispositivo, lo que ofrece animaciones más fluidas, un aspecto coherente con Android, tiempos de carga más rápidos y sin dependencia del runtime de WebView. Consulta [Obtener flows y paywalls](android-get-pb-paywalls) y [Mostrar flows y paywalls](android-present-paywalls) para empezar. ::: Antes de comenzar, asegúrate de que: 1. Has instalado el [SDK de Adapty para Android](sdk-installation-android) 3.8.0 o posterior. 2. Has [creado un onboarding](create-onboarding). 3. Has añadido el onboarding a un [placement](placements). Si has personalizado un onboarding con el Onboarding Builder, no necesitas preocuparte por renderizarlo en el código de tu app para mostrárselo al usuario. Ese onboarding ya contiene tanto qué mostrar como cómo mostrarlo. Para mostrar el onboarding visual en la pantalla del dispositivo, primero debes configurarlo. Para ello, llama al método `AdaptyUI.getOnboardingView()` o crea el `OnboardingView` directamente:
Por ejemplo, si un usuario pulsa un botón personalizado, como **Login** o **Allow notifications**, el método delegado `onCustomAction` se activará con el ID de acción del builder. Puedes crear tus propios IDs, como "allowNotifications".
```kotlin showLineNumbers
class YourActivity : AppCompatActivity() {
private val eventListener = object : AdaptyOnboardingEventListener {
override fun onCustomAction(action: AdaptyOnboardingCustomAction, context: Context) {
when (action.actionId) {
"allowNotifications" -> {
// Request notification permissions
}
}
}
override fun onError(error: AdaptyOnboardingError, context: Context) {
// Handle errors
}
// ... other required delegate methods
}
}
```
El JSON del paywall de respaldo local no es válido.
Corrige tu paywall en inglés predeterminado y luego reemplaza los paywalls locales no válidos. Consulta el tema [Personalizar el paywall con Remote Config](customize-paywall-with-remote-config) para saber cómo corregir un paywall, y [Definir paywalls de respaldo locales](fallback-paywalls) para saber cómo reemplazar los paywalls locales.
| |CURRENT_SUBSCRIPTION_TO_UPDATE
\_NOT_FOUND_IN_HISTORY
| La suscripción original que debe reemplazarse no se encontró en las suscripciones activas. | | [BILLING_SERVICE_TIMEOUT](https://developer.android.com/google/play/billing/errors#service_timeout_error_code_-3) | Este error indica que la solicitud alcanzó el tiempo de espera máximo antes de que Google Play pudiera responder. Puede deberse, por ejemplo, a un retraso en la ejecución de la acción solicitada por la llamada a la Play Billing Library. | | [FEATURE_NOT_SUPPORTED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#FEATURE_NOT_SUPPORTED()) | La función solicitada no es compatible con la Play Store en el dispositivo actual. | | [BILLING_SERVICE_DISCONNECTED](https://developer.android.com/google/play/billing/errors#service_disconnected_error_code_-1) | Este error indica que la conexión de la app cliente con el servicio de Google Play Store a través del `BillingClient` se ha interrumpido. | | [BILLING_SERVICE_UNAVAILABLE](https://developer.android.com/google/play/billing/errors#service_unavailable_error_code_2) | Este error indica que el servicio de facturación de Google Play no está disponible en este momento. En la mayoría de los casos significa que hay un problema de conexión de red entre el dispositivo cliente y los servicios de Google Play Billing. | | [BILLING_UNAVAILABLE](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) |Este error indica que ocurrió un problema de facturación durante el proceso de compra. Las posibles causas son:
1. La app de Play Store en el dispositivo del usuario no está instalada o está desactualizada.
2. El usuario se encuentra en un país no compatible.
3. El usuario forma parte de una cuenta empresarial cuyo administrador ha desactivado las compras.
4. Google Play no pudo cargar el método de pago del usuario (por ejemplo, una tarjeta de crédito caducada).
5. El usuario no ha iniciado sesión en la app de Play Store.
| | [DEVELOPER_ERROR](https://developer.android.com/google/play/billing/errors#developer_error) | Este error indica que estás usando una API de forma incorrecta. | | [BILLING_ERROR](https://developer.android.com/google/play/billing/errors#error_error_code_6) | Este error indica un problema interno del propio Google Play. | | [ITEM_ALREADY_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_ALREADY_OWNED()) | El producto ya fue comprado anteriormente. | | [ITEM_NOT_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_NOT_OWNED()) | Este error indica que la acción solicitada sobre el ítem falló porque el usuario no es su propietario. | | [BILLING_NETWORK_ERROR](https://developer.android.com/google/play/billing/errors#network_error_error_code_12) | Este error indica que hubo un problema con la conexión de red entre el dispositivo y los sistemas de Play. | | NO_PRODUCT_IDS_FOUND |Este error indica que ninguno de los productos del paywall está disponible en el store.
Si encuentras este error, sigue los pasos a continuación para resolverlo:
Si el código expira antes de que autorices, o si haces clic en **Deny**, ejecuta el siguiente comando de nuevo para reiniciar el proceso:
```bash
adapty auth login
```
## Gestionar la autenticación \{#manage-authentication\}
### Comprobar el estado de autenticación \{#check-authentication-status\}
Para ver tu estado de autenticación actual, ejecuta:
```bash
adapty auth status
```
Cuando estás autenticado, la salida muestra tu correo electrónico, un prefijo de token enmascarado y la ruta al archivo de configuración local:
```
Email: you@example.com
Token: abcd1234****
Config: ~/.config/adapty/config.json
```
Cuando no estás autenticado:
```
Not authenticated. Run `adapty auth login`.
```
### Verificar tu token \{#verify-your-token\}
Para confirmar que tu token es válido y ver los detalles de tu cuenta, ejecuta:
```bash
adapty auth whoami
```
A diferencia de `adapty auth status`, este comando realiza una solicitud en tiempo real al servidor para verificar el token.
### Cerrar sesión \{#log-out\}
Para eliminar tus credenciales almacenadas localmente, ejecuta:
```bash
adapty auth logout
```
Esto borra `~/.config/adapty/config.json`. El token sigue siendo válido en el servidor hasta que expira; si necesitas invalidarlo de inmediato, usa `adapty auth revoke` en su lugar.
### Revocar tu token \{#revoke-your-token\}
Para invalidar el token en el servidor y eliminarlo localmente, ejecuta:
```bash
adapty auth revoke
```
Úsalo cuando quieras invalidar un token por completo, por ejemplo, si crees que tus credenciales pueden haberse visto comprometidas. Tras revocarlo, ejecuta `adapty auth login` para volver a autenticarte.
## Errores de token \{#token-errors\}
Si un token se revoca o deja de ser válido, los comandos del CLI devuelven un error 401. Para volver a autenticarte, ejecuta:
```bash
adapty auth login
```
---
# File: developer-cli-reference
---
---
title: "Referencia completa de la CLI para desarrolladores de Adapty"
description: "Referencia completa de todos los comandos de la CLI para desarrolladores de Adapty."
---
:::link
¿Usas un asistente de IA? Hay disponible una [skill de Adapty CLI](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) para ayudar a los LLMs a trabajar con la CLI.
:::
Este artículo lista todos los comandos de la CLI de Adapty con sus argumentos, flags y valores aceptados.
:::link
Para configurar la autenticación y gestionar tokens, consulta [Autenticación](developer-cli-authentication).
:::
## Flags globales \{#global-flags\}
Estos flags están disponibles en todos los comandos.
| Flag | Descripción |
|---|---|
| `--json` | Mostrar la salida en JSON en lugar de texto formateado |
| `--help` | Mostrar la ayuda del comando |
Todos los comandos `list` también aceptan flags de paginación:
| Flag | Por defecto | Descripción |
|---|---|---|
| `--page` | `1` | Número de página |
| `--page-size` | `20` | Elementos por página (máx.: 100) |
## Apps \{#apps\}
Gestiona las apps de tu cuenta de Adapty. Para la configuración desde el dashboard, consulta [App settings](general).
### adapty apps list \{#adapty-apps-list\}
Lista todas las apps de tu cuenta de Adapty.
```bash
adapty apps list
```
Acepta [flags de paginación](#global-flags).
### adapty apps get \{#adapty-apps-get\}
Obtén los detalles de una app específica.
```bash
adapty apps get
:::note Para registrar eventos de suscripción, usa la integración [Webhook](webhook) en Adapty o intégrala directamente con tu servicio existente. ::: ## Caso 1: Sincronizar suscriptores entre web y móvil \{#case-1-sync-subscribers-between-web-and-mobile\} Si utilizas proveedores de pago web como Stripe, ChargeBee u otros, puedes sincronizar a tus suscriptores fácilmente. Así es como funciona: 1.
El ID de perfil de Adapty del usuario. Visible en el campo **Adapty ID** en [Adapty Dashboard -> **Profiles**](https://app.adapty.io/profiles/users) -> página del perfil específico.
Es intercambiable con **adapty-customer-user-id**; usa cualquiera de los dos.
| | **adapty-customer-user-id** |El ID del usuario en tu sistema. Visible en el campo **Customer user ID** en [Adapty Dashboard -> **Profiles**](https://app.adapty.io/profiles/users) -> página del perfil específico.
Es intercambiable con **adapty-profile-id**; usa cualquiera de los dos.
⚠️ Solo funciona si
### Durante el inicio de sesión/registro \{#during-loginsignup\}
Si identificas a los usuarios después de que se inicie la app (por ejemplo, después de que inicien sesión o se registren), usa el método `identify` para establecer su customer user ID.
- Si **no has utilizado este customer user ID antes**, Adapty lo vinculará automáticamente al perfil actual.
- Si **ya has utilizado este customer user ID para identificar al usuario**, Adapty cambiará al perfil asociado a ese customer user ID.
:::tip
Al crear un ID de usuario personalizado, guárdalo junto con los datos del usuario para poder enviar el mismo ID cuando inicie sesión desde nuevos dispositivos o reinstale la app.
:::
Usa siempre `await` con `identify` antes de llamar a otros métodos del SDK. Las llamadas concurrentes generan `#3006 profileWasChanged` o aterrizan en el perfil anónimo. Consulta [Orden de llamadas en el SDK de Capacitor](capacitor-sdk-call-order).
```typescript showLineNumbers
try {
await adapty.identify({ customerUserId: "YOUR_USER_ID" });
// successfully identified
} catch (error) {
// handle the error
}
```
### Durante la activación del SDK \{#during-the-sdk-activation\}
Si ya conoces el customer user ID en el momento de activar el SDK, puedes enviarlo directamente en el método `activate` en lugar de llamar a `identify` por separado.
Si conoces el customer user ID pero lo asignas después de la activación, al activarse el SDK, Adapty creará un nuevo perfil vacío y cambiará al perfil existente solo cuando llames a `identify`.
Puedes pasar un customer user ID existente (el que hayas usado antes) o uno nuevo. Si pasas uno nuevo, el perfil creado en la activación se vinculará automáticamente a ese customer user ID.
:::tip
Para excluir los perfiles vacíos creados de las analíticas del dashboard, ve a **App settings** y configura [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```typescript showLineNumbers
await adapty.activate({
apiKey: "YOUR_PUBLIC_SDK_KEY",
params: {
customerUserId: "YOUR_USER_ID"
}
});
```
### Cerrar sesión de usuarios \{#log-users-out\}
Si tienes un botón para cerrar la sesión de los usuarios, usa el método `logout`. Esto crea un nuevo ID de perfil anónimo para el usuario.
```typescript showLineNumbers
try {
await adapty.logout();
// successful logout
} catch (error) {
// handle the error
}
```
:::info
Para volver a iniciar sesión en la app, usa el método `identify`.
:::
### Permitir compras sin inicio de sesión \{#allow-purchases-without-login\}
Si tus usuarios pueden realizar compras tanto antes como después de iniciar sesión en tu aplicación, no necesitas ninguna configuración adicional:
Así es como funciona:
1. Cuando un usuario sin sesión iniciada realiza una compra, Adapty la vincula a su ID de perfil anónimo.
2. Cuando el usuario inicia sesión en su cuenta, Adapty pasa a trabajar con su perfil identificado.
- Si el customer user ID ya existe (ya está vinculado a un perfil), Adapty sincroniza sus transacciones automáticamente.
- Si es un customer user ID nuevo (por ejemplo, la compra se realizó antes del registro), Adapty asigna el customer user ID al perfil actual, por lo que todo el historial de compras se conserva.
---
# File: adapty-sdk-integration-skill-capacitor
---
---
title: "Integra Adapty en tu app de Capacitor con la habilidad de integración del SDK"
description: "Usa la habilidad adapty-sdk-integration para integrar el SDK de Adapty en tu app de Capacitor de principio a fin con tu herramienta de codificación con IA."
---
La [skill adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatiza la integración de Adapty de extremo a extremo: configuración del dashboard, instalación del SDK, paywall y verificación por etapas. Detecta tu plataforma automáticamente y obtiene la documentación de Adapty relevante en cada etapa.
**Herramientas compatibles**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Para instalarla, elige el formulario para tu herramienta. La lista completa está en el [README de la skill](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex u otra herramienta** — usa la [CLI de skills](https://skills.sh) (ten en cuenta que las skills instaladas de esta forma no se actualizan automáticamente):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
También puedes clonar el repositorio y copiar `skills/adapty-sdk-integration/` en el directorio de skills de tu herramienta.
Tras la instalación, ejecuta la skill en tu proyecto:
```
/adapty-sdk-integration
```
La skill hace algunas preguntas de configuración y luego te guía por la configuración del dashboard, la instalación del SDK, el paywall y la verificación.
:::important
La skill está en beta. Si se detiene o se comporta de forma inesperada, sigue la [guía de integración paso a paso](adapty-cursor-capacitor) en su lugar: lleva a tu herramienta de IA por cada etapa con la documentación correcta.
:::
La [skill adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatiza la integración de Adapty de extremo a extremo: configuración del dashboard, instalación del SDK, paywall y verificación por etapas. Detecta tu plataforma automáticamente y obtiene la documentación de Adapty relevante en cada etapa.
**Herramientas compatibles**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Para instalarla, elige el formulario para tu herramienta. La lista completa está en el [README de la skill](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex u otra herramienta** — usa la [CLI de skills](https://skills.sh) (ten en cuenta que las skills instaladas de esta forma no se actualizan automáticamente):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
También puedes clonar el repositorio y copiar `skills/adapty-sdk-integration/` en el directorio de skills de tu herramienta.
Tras la instalación, ejecuta la skill en tu proyecto:
```
/adapty-sdk-integration
```
La skill hace algunas preguntas de configuración y luego te guía por la configuración del dashboard, la instalación del SDK, el paywall y la verificación.
---
# File: adapty-cursor-capacitor
---
---
title: "Integra Adapty en tu app de Capacitor con ayuda de IA"
description: "Guía paso a paso para integrar Adapty en tu app de Capacitor usando Cursor, Context7, ChatGPT, Claude u otras herramientas de IA."
---
Esta guía te lleva paso a paso por la integración de Adapty en tu app de Capacitor con una herramienta de codificación con IA — tú le proporcionas la documentación correcta de Adapty en el orden correcto.
For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command.
## Antes de empezar: configuración en el dashboard \{#before-you-start-dashboard-setup\}
Adapty requiere cierta configuración en el dashboard antes de escribir código con el SDK. Puedes hacerlo con una skill LLM interactiva o manualmente desde el Dashboard.
### Enfoque con skill (recomendado) \{#skill-approach-recommended\}
El skill de Adapty CLI permite que tu LLM configure tu app, productos, niveles de acceso, paywalls y placements directamente — sin necesidad de abrir el Dashboard en cada paso. Solo tienes que [conectar tus stores](integrate-payments) en el Dashboard.
```
npx skills add adaptyteam/adapty-cli --skill adapty-cli
```
Una vez añadido el skill, ejecuta `/adapty-cli` en tu agente. Te guiará por cada paso — incluyendo cuándo abrir el Dashboard para conectar tus stores.
### Enfoque desde el dashboard \{#dashboard-approach\}
Si prefieres configurarlo todo manualmente, esto es lo que necesitas antes de escribir código. Tu LLM no puede buscar valores del dashboard por ti — tendrás que proporcionárselos.
1. **Conecta tus stores**: En el Adapty Dashboard, ve a **App settings → General**. Conecta tanto App Store como Google Play si tu app de Capacitor es compatible con ambas plataformas. Esto es necesario para que las compras funcionen.
[Conectar stores](integrate-payments)
2. **Copia tu clave pública del SDK**: En el Adapty Dashboard, ve a **App settings → General** y busca la sección **API keys**. En el código, es la cadena que pasas a `adapty.activate()`.
3. **Crea al menos un producto**: En el Adapty Dashboard, ve a la página **Products**. No haces referencia a los productos directamente en el código — Adapty los entrega a través de paywalls.
[Añadir productos](quickstart-products)
4. **Crea un paywall y un placement**: En el Adapty Dashboard, crea un paywall en la página **Paywalls**, luego asígnalo a un placement en la página **Placements**. En el código, el ID del placement es la cadena que pasas a `adapty.getFlow()`.
[Crear paywall](quickstart-paywalls)
5. **Configura los niveles de acceso**: En el Adapty Dashboard, configúralos por producto en la página **Products**. En el código, la cadena que se comprueba es `profile.accessLevels['premium']?.isActive`. El nivel de acceso `premium` predeterminado funciona para la mayoría de las apps. Si los usuarios de pago acceden a funciones distintas según el producto (por ejemplo, un plan `basic` frente a un plan `pro`), [crea niveles de acceso adicionales](assigning-access-level-to-a-product) antes de empezar a programar.
:::tip
Una vez que tengas los cinco, estás listo para escribir código. Dile a tu LLM: "Mi clave SDK pública es X, mi ID de placement es Y" para que pueda generar el código correcto de inicialización y obtención de flows.
:::
### Configura cuando estés listo \{#set-up-when-ready\}
No son obligatorias para empezar a programar, pero las necesitarás a medida que tu integración madure:
- **Pruebas A/B**: Configúralas en la página **Placements**. No se necesitan cambios de código.
[Pruebas A/B](ab-tests)
- **Paywalls y placements adicionales**: Añade más llamadas `getPaywall` con diferentes IDs de placement.
- **Integraciones de analíticas**: Configúralas en la página **Integrations**. La configuración varía según la integración. Consulta [integraciones de analíticas](analytics-integration) e [integraciones de atribución](attribution-integration).
## Proporciona la documentación de Adapty a tu LLM \{#feed-adapty-docs-to-your-llm\}
### Usa Context7 (recomendado)
[Context7](https://context7.com) es un servidor MCP que da a tu LLM acceso directo a la documentación actualizada de Adapty. Tu LLM obtiene automáticamente la documentación adecuada según lo que preguntes, sin necesidad de pegar URLs manualmente.
Context7 funciona con **Cursor**, **Claude Code**, **Windsurf** y otras herramientas compatibles con MCP. Para configurarlo, ejecuta:
```
npx ctx7 setup
```
Esto detecta tu editor y configura el servidor de Context7. Para una configuración manual, consulta el [repositorio de Context7 en GitHub](https://github.com/upstash/context7).
Una vez configurado, haz referencia a la biblioteca de Adapty en tus prompts:
```
Use the adaptyteam/adapty-docs library to look up how to install the Capacitor SDK
```
:::warning
Aunque Context7 elimina la necesidad de pegar enlaces a la documentación manualmente, el orden de implementación es importante. Sigue el [recorrido de implementación](#implementation-walkthrough) paso a paso para asegurarte de que todo funciona correctamente.
:::
### Usa documentos en texto plano
Puedes acceder a cualquier documento de Adapty en texto plano Markdown. Añade `.md` al final de su URL, o haz clic en **Copy for LLM** bajo el título del artículo. Por ejemplo: [adapty-cursor-capacitor.md](https://adapty.io/docs/es/adapty-cursor-capacitor.md).
Cada etapa del [recorrido de implementación](#implementation-walkthrough) incluye un bloque "Send this to your LLM" con enlaces `.md` para pegar.
Para obtener más documentación a la vez, consulta los [archivos de índice y subconjuntos por plataforma](#plain-text-doc-index-files) más abajo.
## Guía de implementación paso a paso \{#implementation-walkthrough\}
El resto de esta guía recorre la integración de Adapty en el orden en que debes implementarla. Cada etapa incluye la documentación que debes enviar a tu LLM, qué deberías ver al terminar y los problemas más comunes.
### Planifica tu integración \{#plan-your-integration\}
Antes de escribir código, pide a tu LLM que analice tu proyecto y cree un plan de implementación. Si tu herramienta de IA admite un modo de planificación (como el modo plan de Cursor o Claude Code), úsalo para que el LLM pueda leer tanto la estructura de tu proyecto como la documentación de Adapty antes de escribir nada.
Indica a tu LLM qué enfoque usas para las compras, ya que esto determina las guías que debe seguir:
- [**Adapty Flow Builder**](adapty-flow-builder): Creas flows en el editor no-code de Adapty y el SDK los renderiza automáticamente.
- [**Paywalls creados manualmente**](capacitor-making-purchases): Creas tu propia interfaz de paywall en código, pero sigues usando Adapty para obtener productos y gestionar compras.
- [**Modo observador**](observer-vs-full-mode): Mantienes tu infraestructura de compras existente y usas Adapty solo para análisis e integraciones.
¿No sabes cuál elegir? Lee la [tabla comparativa en la guía de inicio rápido](capacitor-quickstart-paywalls).
### Instala y configura el SDK \{#install-and-configure-the-sdk\}
Añade la dependencia del SDK de Adapty con npm y actívalo con tu clave pública. Esta es la base — sin esto, nada más funciona.
**Guía:** [Instala y configura el SDK de Adapty](sdk-installation-capacitor)
:::info
Este tutorial está orientado al SDK de Adapty para Capacitor v4 (beta) — la API que enseña el [quickstart](capacitor-quickstart-paywalls). v4 es una versión preliminar, así que asegúrate de que tu LLM fije la versión exacta (`npm install @adapty/capacitor@4.0.0-beta.2`) en lugar de instalar la última versión estable 3.x. Consulta la [sección de instalación del SDK 4.0](sdk-installation-capacitor#adapty-sdk-40-beta) y la [guía de migración](migration-to-capacitor-sdk-v4).
:::
Envía esto a tu LLM:
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/es/sdk-installation-capacitor.md
```
:::tip[Checkpoint]
- **Esperado:** La app compila y se ejecuta en iOS y Android. La consola muestra el log de activación de Adapty.
- **Problema frecuente:** "Public API key is missing" → verifica que hayas reemplazado el marcador de posición con tu clave real de **App settings**.
:::
### Mostrar paywalls y gestionar compras \{#show-paywalls-and-handle-purchases\}
Obtén un paywall por ID de placement, muéstralo y gestiona los eventos de compra. Las guías que necesitas dependen de cómo gestiones las compras.
Prueba cada compra en el sandbox a medida que avances — no esperes al final. Consulta [Probar compras en sandbox](test-purchases-in-sandbox) para ver las instrucciones de configuración.
Se pasa dentro del objeto opcional `params`. Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `'return_cache_data_else_load'` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la app y solo se borra cuando la app se reinstala o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché de actualización periódica descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| | **loadTimeoutMs** | por defecto: 5 seg |Se pasa dentro del objeto opcional `params`. Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede agotar el tiempo de espera ligeramente después de lo especificado en `loadTimeoutMs`, ya que la operación puede componerse de diferentes solicitudes internamente.
| **No codifiques los IDs de productos.** El único ID que debes codificar es el del placement. Los flows y los paywalls se configuran de forma remota, por lo que el número de productos y las ofertas disponibles pueden cambiar en cualquier momento. Tu app debe gestionar estos cambios de forma dinámica: si un paywall devuelve dos productos hoy y tres mañana, muéstralos todos sin necesidad de modificar el código. Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | Un objeto `AdaptyFlow` con los identificadores del flow (`id`, `variationId`), nombre, placement, sus variaciones de paywall (`paywalls`) y los Remote Configs (`remoteConfigs`). | ## Obtener la configuración de la vista \{#fetch-the-view-configuration\} :::important Asegúrate de activar el botón **Show on device** en el builder. Si esta opción no está activada, la configuración de la vista no estará disponible para recuperar. ::: Si el placement se diseñó en el **Flow Builder** o en el **Paywall Builder**, Adapty renderiza la interfaz de usuario por ti. Crea la vista con `createFlowView` y luego [presenta el flow o el paywall](capacitor-present-paywalls). Si el placement es un paywall personalizado sin interfaz del Builder, [trátalo como un paywall de Remote Config](present-remote-config-paywalls-capacitor). En el SDK de Capacitor, llama a `createFlowView` directamente; no es necesario obtener primero la configuración de la vista. :::warning El resultado del método `createFlowView` solo puede usarse una vez. Si necesitas usarlo de nuevo, llama de nuevo al método `createFlowView`. Llamarlo dos veces sin recrearlo puede producir un error. ::: ```typescript showLineNumbers try { const view = await createFlowView(flow); } catch (error) { // handle the error } ``` Parámetros: | Parámetro | Presencia | Descripción | | :------------------- | :------- | :----------------------------------------------------------- | | **flow** | obligatorio | Un objeto `AdaptyFlow` para obtener un controlador para el flow/paywall deseado. | | **customTags** | opcional | Define un diccionario de etiquetas personalizadas y sus valores resueltos. Las etiquetas personalizadas actúan como marcadores de posición en el contenido, reemplazados dinámicamente con cadenas específicas para personalizar el contenido dentro del flow/paywall. Consulta el tema Etiquetas personalizadas en Paywall Builder para más detalles. | | **prefetchProducts** | opcional | Actívalo para optimizar el tiempo de visualización de los productos en pantalla. Cuando es `true`, AdaptyUI obtendrá automáticamente los productos necesarios. Valor por defecto: `true`. | | **android.enableSafeArea** | opcional | Solo para Android (ignorado en iOS). Anidado bajo la clave `android`. Cuando es `true`, la vista del flow aplica los márgenes de área segura. Valor por defecto: `true`. El valor por defecto es adecuado para la mayoría de los casos. | :::note Si utilizas varios idiomas, aprende cómo añadir una [localización de flow](add-paywall-locale-in-adapty-paywall-builder) y cómo usar los códigos de idioma correctamente [aquí](capacitor-localizations-and-locale-codes). ::: Una vez que tengas la vista, [presenta el flow/paywall](capacitor-present-paywalls). ## Obtén un flow o paywall para la audiencia predeterminada y acelera la carga \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} En general, los flows y paywalls se obtienen casi de forma instantánea, así que no necesitas preocuparte por optimizar este proceso. Sin embargo, cuando tienes muchas audiencias y placements, y tus usuarios tienen una conexión a internet lenta, la carga de un flow o paywall puede tardar más de lo deseable. En esos casos, puede que quieras mostrar un flow o paywall predeterminado para garantizar una experiencia fluida, en lugar de no mostrar nada. Para solucionar esto, puedes usar el método `getFlowForDefaultAudience`, que obtiene el flow o paywall del placement especificado para la audiencia **All Users**. Sin embargo, es importante entender que el enfoque recomendado es obtener el flow o paywall con el método `getFlow`, tal como se describe en la sección [Obtener flow/paywall](#fetch-flowpaywall) anterior. :::warning Por qué recomendamos usar `getFlow` El método `getFlowForDefaultAudience` tiene algunos inconvenientes importantes: - **Posibles problemas de compatibilidad con versiones anteriores**: Si necesitas mostrar distintos paywalls para diferentes versiones de la app (la actual y las futuras), pueden surgir dificultades. Tendrás que diseñar paywalls que sean compatibles con la versión actual (heredada) o asumir que los usuarios con esa versión podrían encontrarse con paywalls que no se renderizan correctamente. - **Pérdida de targeting**: Todos los usuarios verán el mismo paywall diseñado para la audiencia **All Users**, lo que significa que pierdes la personalización del targeting (incluyendo segmentación por país, atribución de marketing o tus propios atributos personalizados). Si estás dispuesto a aceptar estas desventajas a cambio de una obtención más rápida del flow o paywall, usa el método `getFlowForDefaultAudience` de la siguiente manera. De lo contrario, quédate con `getFlow` descrito [arriba](#fetch-flowpaywall). ::: ```typescript showLineNumbers try { const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', }); // the requested flow/paywall } catch (error) { // handle the error } ``` | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **fetchPolicy** | predeterminado: `'reload_revalidating_cache_data'` |Se pasa dentro del objeto opcional `params`. Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `'return_cache_data_else_load'` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la aplicación y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| ## Personalizar recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu flow/paywall, implementa los recursos personalizados. Las imágenes hero y los vídeos tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizados, identificas estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. Aquí tienes un ejemplo de cómo proporcionar recursos personalizados mediante un diccionario simple: ```typescript showLineNumbers const customAssets: Recordopcional
por defecto: `en`
|El identificador de la [localización del paywall](add-paywall-locale-in-adapty-paywall-builder). Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **params** | opcional | Parámetros adicionales para obtener el paywall. | **No escribas los IDs de producto en el código.** El único ID que debes incluir directamente en el código es el del placement. Los paywalls se configuran de forma remota, por lo que el número de productos y las ofertas disponibles pueden cambiar en cualquier momento. Tu app debe gestionar estos cambios de forma dinámica: si un paywall devuelve dos productos hoy y tres mañana, muéstralos todos sin necesidad de modificar el código. Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Un objeto [`AdaptyPaywall`](https://capacitor.adapty.io/interfaces/adaptypaywall) con una lista de IDs de producto, el identificador del paywall, el Remote Config y otras propiedades adicionales. | ## Obtener la configuración de vista del paywall diseñado con Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Asegúrate de activar el botón **Show on device** en el Paywall Builder. Si esta opción no está activada, la configuración de vista no estará disponible para recuperar. ::: Después de obtener el paywall, comprueba si incluye un `ViewConfiguration`, lo que indica que fue creado con Paywall Builder. Esto te indicará cómo mostrar el paywall. Si el `ViewConfiguration` está presente, trátalo como un paywall de Paywall Builder; si no, [trátalo como un paywall de Remote Config](present-remote-config-paywalls-capacitor). En el SDK de Capacitor, llama directamente al método `createPaywallView` sin necesidad de obtener primero la configuración de la vista manualmente. :::warning El resultado del método `createPaywallView` solo puede utilizarse una vez. Si necesitas usarlo de nuevo, llama al método `createPaywallView` otra vez. ::: ```typescript showLineNumbers if (paywall.hasViewConfiguration) { try { const view = await createPaywallView(paywall); } catch (error) { // handle the error } } else { // use your custom logic } ``` Parámetros: | Parámetro | Presencia | Descripción | | :------------------- | :-------- | :----------------------------------------------------------- | | **paywall** | obligatorio | Un objeto `AdaptyPaywall` para obtener un controlador del paywall deseado. | | **customTags** | opcional | Define un diccionario de etiquetas personalizadas y sus valores resueltos. Las etiquetas personalizadas actúan como marcadores de posición en el contenido del paywall y se reemplazan dinámicamente con cadenas específicas para personalizar el contenido. Consulta el tema Custom tags in paywall builder para más detalles. | | **prefetchProducts** | opcional | Actívalo para optimizar el momento en que se muestran los productos en pantalla. Si es `true`, AdaptyUI obtendrá automáticamente los productos necesarios. Valor predeterminado: `false`. | :::note Si utilizas varios idiomas, aprende cómo añadir una [localización en el Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) y cómo usar los códigos de idioma correctamente [aquí](capacitor-localizations-and-locale-codes). ::: Una vez que tengas la vista, [muestra el paywall](capacitor-present-paywalls). ## Obtén un paywall para la audiencia por defecto y acelera su carga \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} Normalmente, los paywalls se obtienen casi de inmediato, por lo que no es necesario preocuparse por acelerar este proceso. Sin embargo, cuando tienes numerosas audiencias y paywalls, y tus usuarios tienen una conexión a internet débil, obtener un paywall puede tardar más de lo deseable. En esas situaciones, puede que quieras mostrar un paywall por defecto para garantizar una experiencia de usuario fluida en lugar de no mostrar ningún paywall. Para abordar esto, puedes usar el método `getPaywallForDefaultAudience`, que obtiene el paywall del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el paywall mediante el método `getPaywall`, tal como se detalla en la sección [Obtener información del paywall](#fetch-paywall-designed-with-paywall-builder) anterior. :::warning Por qué recomendamos usar `getPaywall` El método `getPaywallForDefaultAudience` tiene algunos inconvenientes importantes: - **Posibles problemas de compatibilidad con versiones anteriores**: Si necesitas mostrar distintos paywalls para diferentes versiones de la app (la actual y futuras), tendrás que diseñar paywalls compatibles con la versión actual (legacy) o aceptar que los usuarios de esa versión puedan encontrarse con paywalls que no se renderizan correctamente. - **Pérdida de targeting**: Todos los usuarios verán el mismo paywall diseñado para la audiencia **All Users**, lo que significa que perderás la segmentación personalizada (incluida la basada en países, atribución de marketing o tus propios atributos personalizados). Si estás dispuesto a aceptar estos inconvenientes a cambio de una obtención más rápida del paywall, usa el método `getPaywallForDefaultAudience` de la siguiente manera. De lo contrario, utiliza `getPaywall` descrito [anteriormente](#fetch-paywall-designed-with-paywall-builder). ::: ```typescript showLineNumbers try { const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', }); // the requested paywall } catch (error) { // handle the error } ``` | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requerido | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **locale** |opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` indica inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](capacitor-localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **params** | opcional | Parámetros adicionales para obtener el paywall. | ## Personalizar recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu paywall, implementa los recursos personalizados. Las imágenes de héroe y los vídeos tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizado, seleccionas estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. A continuación se muestra un ejemplo de cómo puedes proporcionar recursos personalizados mediante un diccionario simple: ```typescript showLineNumbers const customAssets: Recordopcional
predeterminado: `'reload_revalidating_cache_data'`
|Por defecto, el SDK intentará cargar datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `'return_cache_data_else_load'` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando la app se reinstala o mediante una limpieza manual.
El SDK de Adapty almacena flows y paywalls en dos capas: la caché de actualización regular descrita anteriormente y los [paywalls de respaldo](capacitor-use-fallback-paywalls). También usamos CDN para obtener flows y paywalls más rápido, y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus flows, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **params.loadTimeoutMs** |opcional
predeterminado: 5000 ms
|Este valor limita el tiempo de espera (en milisegundos) para este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo de espera especificado en `loadTimeoutMs`, ya que la operación puede estar compuesta de diferentes solicitudes internamente.
| :::note En la v4, `getFlow` ya no acepta un parámetro `locale`. En el caso de paywalls personalizados, todos los idiomas disponibles se devuelven en el Remote Config del flow (`flow.remoteConfigs`); elige el que coincida con el dispositivo o la configuración del usuario. ::: ¡No pongas IDs de productos en el código! Como los flows se configuran de forma remota, los productos disponibles, el número de productos y las ofertas especiales (como períodos de prueba gratuitos) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si inicialmente obtienes 2 productos, tu app debería mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, tu app debería mostrar los 3 sin necesidad de ningún cambio en el código. Lo único que tienes que poner en el código es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objeto `AdaptyFlow` que contiene el placement, los identificadores (`id`, `variationId`), el nombre, sus variaciones de paywall (`paywalls`) y un array `remoteConfigs` (una entrada por cada idioma configurado). Para obtener los productos del flow, llama a `getPaywallProducts({ flow })`. | ## Obtener productos \{#fetch-products\} Una vez que tienes el flow, puedes consultar el array de productos que le corresponde: ```typescript showLineNumbers try { const products = await adapty.getPaywallProducts({ flow }); // the requested products list } catch (error) { console.error('Failed to fetch products:', error); } ``` Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Lista de objetos [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) con: identificador del producto, nombre del producto, precio, moneda, duración de la suscripción y otras propiedades adicionales. | Al implementar tu propio diseño de paywall, probablemente necesitarás acceder a estas propiedades del objeto [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct). A continuación se ilustran las propiedades más utilizadas, pero consulta el documento enlazado para ver todos los detalles sobre las propiedades disponibles. | Propiedad | Descripción | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Para mostrar el título del producto, usa `product.localizedTitle`. Ten en cuenta que la localización se basa en el país de la store seleccionado por el usuario, no en el idioma del dispositivo. | | **Price** | Para mostrar el precio localizado, usa `product.price?.localizedString`. Esta localización se basa en la configuración regional del dispositivo. También puedes acceder al precio como número con `product.price?.amount`. El valor se devuelve en la moneda local. Para obtener el símbolo de moneda correspondiente, usa `product.price?.currencySymbol`. | | **Subscription Period** | Para mostrar el período (p. ej., semana, mes, año, etc.), usa `product.subscription?.localizedSubscriptionPeriod`. Esta localización se basa en el idioma del dispositivo. Para obtener el período de suscripción de forma programática, usa `product.subscription?.subscriptionPeriod`. Desde ahí puedes acceder a la propiedad `unit` para conocer la unidad (es decir, `'day'`, `'week'`, `'month'`, `'year'` o `'unknown'`). El valor `numberOfUnits` indica el número de unidades del período. Por ejemplo, en una suscripción trimestral verás `'month'` en la propiedad `unit` y `3` en `numberOfUnits`. | | **Introductory Offer** | Para mostrar un badge u otro indicador de que una suscripción incluye una oferta introductoria, consulta la propiedad `product.subscription?.offer?.phases`. Es una lista que puede contener hasta dos fases de descuento: la fase de prueba gratuita y la fase de precio introductorio. Dentro de cada objeto de fase encontrarás las siguientes propiedades útiles:opcional
por defecto: `'reload_revalidating_cache_data'`
|Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `'return_cache_data_else_load'` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo intermitente que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
|opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](capacitor-localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **params.fetchPolicy** |opcional
por defecto: `'reload_revalidating_cache_data'`
|Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `'return_cache_data_else_load'` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo irregular que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la aplicación y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| | **params.loadTimeoutMs** |opcional
por defecto: 5000 ms
|Este valor limita el tiempo de espera (en milisegundos) de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeoutMs`, ya que la operación puede estar compuesta por distintas peticiones internamente.
| **No incluyas product IDs en el código.** El único ID que debes incluir en el código es el del placement. Los paywalls se configuran de forma remota, por lo que el número de productos y las ofertas disponibles pueden cambiar en cualquier momento. Tu app debe gestionar estos cambios de forma dinámica: si un paywall devuelve dos productos hoy y tres mañana, muéstralos todos sin necesidad de cambiar el código. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://capacitor.adapty.io/interfaces/adaptypaywall) con: una lista de IDs de productos, el identificador del paywall, Remote Config y otras propiedades. | ## Obtener productos \{#fetch-products\} Una vez que tienes el paywall, puedes consultar el array de productos que le corresponde: ```typescript showLineNumbers try { const products = await adapty.getPaywallProducts({ paywall }); // the requested products list } catch (error) { console.error('Failed to fetch products:', error); } ``` Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Lista de objetos [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) con: identificador de producto, nombre del producto, precio, moneda, duración de la suscripción y otras propiedades. | Al implementar tu propio diseño de paywall, probablemente necesitarás acceder a estas propiedades del objeto [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct). A continuación se muestran las propiedades más utilizadas, pero consulta el documento enlazado para obtener detalles completos sobre todas las propiedades disponibles. | Propiedad | Descripción | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Para mostrar el título del producto, usa `product.localizedTitle`. Ten en cuenta que la localización se basa en el país del store seleccionado por el usuario, no en el idioma del dispositivo. | | **Price** | Para mostrar el precio localizado, usa `product.price?.localizedString`. Esta localización se basa en la información de idioma del dispositivo. También puedes acceder al precio como número mediante `product.price?.amount`. El valor se expresará en la moneda local. Para obtener el símbolo de moneda correspondiente, usa `product.price?.currencySymbol`. | | **Subscription Period** | Para mostrar el período (p. ej., semana, mes, año, etc.), usa `product.subscription?.localizedSubscriptionPeriod`. Esta localización se basa en el idioma del dispositivo. Para obtener el período de suscripción de forma programática, usa `product.subscription?.subscriptionPeriod`. Desde ahí puedes acceder a la propiedad `unit` para conocer la unidad (es decir, `'day'`, `'week'`, `'month'`, `'year'` o `'unknown'`). El valor `numberOfUnits` te dará el número de unidades del período. Por ejemplo, en una suscripción trimestral verás `'month'` en la propiedad `unit` y `3` en la propiedad `numberOfUnits`. | | **Introductory Offer** | Para mostrar un badge u otro indicador de que una suscripción incluye una oferta introductoria, consulta la propiedad `product.subscription?.offer?.phases`. Es una lista que puede contener hasta dos fases de descuento: la fase de prueba gratuita y la fase de precio introductorio. Dentro de cada objeto de fase encontrarás las siguientes propiedades útiles:opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` representa el inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](capacitor-localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **params.fetchPolicy** |opcional
por defecto: `'reload_revalidating_cache_data'`
|Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que los usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `'return_cache_data_else_load'` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la aplicación y solo se borra al desinstalarla o mediante una limpieza manual.
|opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto de una o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos utilizarlos.
| | **params.fetchPolicy** |opcional
por defecto: `'reload_revalidating_cache_data'`
|Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `'return_cache_data_else_load'` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro utilizarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| | **params.loadTimeoutMs** |opcional
por defecto: 5000 ms
|Este valor limita el tiempo de espera (en milisegundos) para este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo de espera especificado en `loadTimeoutMs`, ya que la operación puede estar compuesta por diferentes peticiones internamente.
| Parámetros de respuesta: | Parámetro | Descripción | |:----------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onboarding** | Un objeto [`AdaptyOnboarding`](https://capacitor.adapty.io/interfaces/adaptyonboarding) con: el identificador y la configuración del onboarding, Remote Config y otras propiedades. | ## Acelerar la obtención del onboarding con el onboarding de audiencia predeterminada \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Por lo general, los onboardings se obtienen casi al instante, por lo que no necesitas preocuparte por acelerar este proceso. Sin embargo, si tienes muchas audiencias y onboardings, y tus usuarios tienen una conexión a internet lenta, obtener un onboarding puede tardar más de lo que quisieras. En esas situaciones, puede que prefieras mostrar un onboarding predeterminado para garantizar una experiencia de usuario fluida en lugar de no mostrar ninguno. Para solucionar esto, puedes usar el método `getOnboardingForDefaultAudience`, que obtiene el onboarding del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el onboarding mediante el método `getOnboarding`, tal como se detalla en la sección [Obtener el onboarding](#fetch-onboarding) anterior. :::warning Considera usar `getOnboarding` en lugar de `getOnboardingForDefaultAudience`, ya que este último tiene limitaciones importantes: - **Problemas de compatibilidad**: Puede generar conflictos al dar soporte a varias versiones de la app, lo que obliga a diseños compatibles con versiones anteriores o a asumir que las versiones antiguas podrían mostrarse incorrectamente. - **Sin personalización**: Solo muestra contenido para la audiencia "All Users", eliminando la segmentación por país, atribución o atributos personalizados. Si una obtención más rápida compensa estos inconvenientes en tu caso de uso, utiliza `getOnboardingForDefaultAudience` tal como se muestra a continuación. De lo contrario, usa `getOnboarding` como se describe [arriba](#fetch-onboarding). ::: ```typescript showLineNumbers try { const onboarding = await adapty.getOnboardingForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', params: { fetchPolicy: 'reload_revalidating_cache_data' // Load from server, fallback to cache } }); console.log('Default audience onboarding fetched successfully'); } catch (error) { console.error('Failed to fetch default audience onboarding:', error); } ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|-----------| | **placementId** | obligatorio | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |opcional
predeterminado: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto de uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **params.fetchPolicy** |opcional
predeterminado: `'reload_revalidating_cache_data'`
|Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que los usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `'return_cache_data_else_load'` para devolver los datos en caché si existen. En este caso, los usuarios puede que no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| --- # File: capacitor-present-onboardings --- --- title: "Mostrar onboardings en Capacitor SDK" description: "Descubre cómo mostrar onboardings en Capacitor para aumentar las conversiones y los ingresos." --- :::warning **Los onboardings están obsoletos en el SDK v4 y se eliminarán en una versión futura.** Ya no reciben correcciones ni mejoras. Usa [flows](capacitor-get-pb-paywalls) en su lugar: a diferencia de los onboardings, que se ejecutan dentro de un WebView, los flows se renderizan de forma nativa en el dispositivo, lo que proporciona animaciones más fluidas, un aspecto nativo coherente, tiempos de carga más rápidos y sin dependencia del entorno de ejecución de WebView. Consulta [Obtener flows y paywalls](capacitor-get-pb-paywalls) y [Mostrar flows y paywalls](capacitor-present-paywalls) para empezar. ::: Si has personalizado un onboarding usando el builder, no tienes que preocuparte por renderizarlo en el código de tu app para mostrárselo al usuario. Ese onboarding ya incluye tanto lo que debe mostrarse como la forma en que debe mostrarse. Antes de empezar, asegúrate de que: 1. Has [creado un onboarding](create-onboarding). 2. Has añadido el onboarding a un [placement](placements). ## Presentar el onboarding \{#present-onboarding\} Para mostrar un onboarding, usa el método `view.present()` en el `view` creado por el método `createOnboardingView`. Cada `view` solo se puede usar una vez. Si necesitas mostrar el onboarding de nuevo, llama a `createOnboardingView` otra vez para crear una nueva instancia de `view`. :::warning Reutilizar el mismo `view` sin recrearlo puede producir un error. ::: ```typescript showLineNumbers try { const view = await createOnboardingView(onboarding); view.setEventHandlers({ onClose: (actionId, meta) => { console.log('Onboarding closed:', actionId); return true; // Allow the onboarding to close }, onCustom: (actionId, meta) => { console.log('Custom action:', actionId); return false; // Don't close the onboarding } }); await view.present(); console.log('Onboarding presented successfully'); } catch (error) { console.error('Failed to present onboarding:', error); } ``` ## Configurar el estilo de presentación en iOS \{#configure-ios-presentation-style\} Configura cómo se presenta el onboarding en iOS pasando el parámetro `iosPresentationStyle` al método `present()`. El parámetro acepta los valores `'full_screen'` (predeterminado) o `'page_sheet'`. ```typescript showLineNumbers await view.present({ iosPresentationStyle: 'page_sheet' }); ``` ## Personaliza cómo se abren los enlaces en los onboardings \{#customize-how-links-open-in-onboardings\} :::important La personalización de cómo se abren los enlaces en los onboardings está disponible a partir del SDK de Adapty v3.15. ::: Por defecto, los enlaces en los onboardings se abren en un navegador integrado en la app. Esto proporciona una experiencia de usuario fluida al mostrar las páginas web dentro de tu aplicación, permitiendo a los usuarios verlas sin cambiar de app. Si prefieres abrir los enlaces en un navegador externo, puedes personalizar este comportamiento estableciendo el parámetro `openIn` con el valor `browser_out_app`: ```typescript showLineNumbers await view.present({ openIn: 'browser_out_app' }); // default — browser_in_app ``` ## Próximos pasos \{#next-steps\} Una vez que hayas mostrado tu onboarding, querrás [gestionar las interacciones y eventos del usuario](capacitor-handling-onboarding-events). Aprende a manejar los eventos del onboarding para responder a las acciones del usuario y hacer seguimiento de los datos analíticos. --- # File: capacitor-handling-onboarding-events --- --- title: "Manejar eventos de onboarding en el SDK de Capacitor" description: "Maneja eventos relacionados con el onboarding en Capacitor usando Adapty." --- :::warning **Los onboardings están obsoletos en el SDK v4 y se eliminarán en una versión futura.** Ya no reciben correcciones ni mejoras. Usa [flows](capacitor-get-pb-paywalls) en su lugar: a diferencia de los onboardings, que se ejecutan dentro de un WebView, los flows se renderizan de forma nativa en el dispositivo, lo que ofrece animaciones más fluidas, una apariencia nativa consistente, tiempos de carga más rápidos y sin dependencia del entorno WebView. Consulta [Obtener flows y paywalls](capacitor-get-pb-paywalls) y [Mostrar flows y paywalls](capacitor-present-paywalls) para empezar. ::: Los onboardings configurados con el builder generan eventos a los que tu app puede responder. Usa el método `setEventHandlers` para gestionar estos eventos en la presentación de pantallas independientes. Antes de empezar, asegúrate de: 1. Haber [creado un onboarding](create-onboarding). 2. Haber añadido el onboarding a un [placement](placements). ## Configurar manejadores de eventos \{#set-up-event-handlers\} Para gestionar los eventos de los onboardings, usa el método `view.setEventHandlers`: ```typescript showLineNumbers try { const view = await createOnboardingView(onboarding); view.setEventHandlers({ onAnalytics(event, meta) { console.log('Analytics event:', event); }, onClose(actionId, meta) { console.log('Onboarding closed:', actionId); return true; // Allow the onboarding to close }, onCustom(actionId, meta) { console.log('Custom action:', actionId); return false; // Don't close the onboarding }, onPaywall(actionId, meta) { console.log('Paywall action:', actionId); view.dismiss().then(() => { openPaywall(actionId); }); }, onStateUpdated(action, meta) { console.log('State updated:', action); }, onFinishedLoading(meta) { console.log('Onboarding finished loading'); }, onError(error) { console.error('Onboarding error:', error); }, }); await view.present(); } catch (error) { console.error('Failed to present onboarding:', error); } ``` ## Tipos de eventos \{#event-types\} Las siguientes secciones describen los distintos tipos de eventos que puedes gestionar. ### Gestionar acciones personalizadas \{#handle-custom-actions\} En el builder, puedes añadir una acción **custom** a un botón y asignarle un ID.
Luego, puedes usar este ID en tu código y gestionarlo como una acción personalizada. Por ejemplo, si el usuario pulsa un botón personalizado, como **Login** o **Allow notifications**, el manejador de eventos se activará con el parámetro `actionId` que coincide con el **Action ID** del builder. Puedes crear tus propios IDs, como "allowNotifications".
```typescript showLineNumbers
view.setEventHandlers({
onCustom(actionId, meta) {
switch (actionId) {
case 'login':
console.log('Login action triggered');
break;
case 'allow_notifications':
console.log('Allow notifications action triggered');
break;
}
return false; // Don't close the onboarding
},
});
```
:::important
Ten en cuenta que debes gestionar qué ocurre cuando el usuario cierra el onboarding. Por ejemplo, debes dejar de mostrar el propio onboarding.
:::
```typescript showLineNumbers
view.setEventHandlers({
onClose(actionId, meta) {
console.log('Onboarding closed:', actionId);
return true; // Allow the onboarding to close
},
});
```
Este código de error indica que el usuario canceló una solicitud de pago.
No se requiere ninguna acción, pero en términos de lógica de negocio, puedes ofrecer un descuento al usuario o recordárselo más adelante.
| | paymentInvalid | 3 | Este error indica que uno de los parámetros de pago no fue reconocido por la store. | | paymentNotAllowed | 4 |Este código de error indica que el usuario no tiene permiso para autorizar pagos. Posibles razones:
- Los pagos no están disponibles en el país del usuario.
- El usuario es menor de edad.
| | storeProductNotAvailable | 5 | Este código de error indica que el producto solicitado no está disponible en la App Store. Asegúrate de que el producto esté disponible en el país correspondiente. | | cloudServicePermissionDenied | 6 | Este código de error indica que el usuario no ha permitido el acceso a la información del servicio en la nube. | | cloudServiceNetworkConnectionFailed | 7 | Este código de error indica que el dispositivo no pudo conectarse a la red. | | cloudServiceRevoked | 8 | Este código de error indica que el usuario ha revocado el permiso para usar este servicio en la nube. | | privacyAcknowledgementRequired | 9 | Este código de error indica que el usuario aún no ha aceptado la política de privacidad de la store. | | unauthorizedRequestData | 10 | Este código de error indica que la solicitud está construida de forma incorrecta. | | invalidOfferIdentifier | 11 |El identificador de oferta no es válido. Posibles razones:
- No has configurado una oferta con ese identificador en la App Store.
- Has revocado la oferta.
- Hay un error tipográfico en el ID de la oferta.
| | invalidSignature | 12 | Este código de error indica que la firma en un descuento de pago no es válida. Asegúrate de haber rellenado el campo **In-app purchase Key ID** y de haber subido el archivo **In-App Purchase Private Key**. Consulta el tema [Configure App Store integration](app-store-connection-configuration) para más detalles. | | missingOfferParams | 13 |Este error indica problemas con la integración de Adapty o con las ofertas.
Consulta [Configure App Store integration](app-store-connection-configuration) y [Offers](offers) para más detalles sobre cómo configurarlas.
| | invalidOfferPrice | 14 | Este código de error indica que el precio que especificaste en la store ya no es válido. Las ofertas siempre deben representar un precio con descuento. | ## Códigos personalizados de Android \{#custom-android-codes\} | Error | Código | Descripción | |-----|----|-----------| | adaptyNotInitialized | 20 | Necesitas configurar correctamente el SDK de Adapty mediante el método `Adapty.activate`. Aprende cómo hacerlo [para React Native](sdk-installation-reactnative). | | productNotFound | 22 | Este error indica que el producto solicitado para la compra no está disponible en la store. | | invalidJson | 23 | El JSON del paywall no es válido. Corrígelo en el Adapty Dashboard. Consulta el tema [Customize paywall with remote config](customize-paywall-with-remote-config) para más detalles sobre cómo corregirlo. | | currentSubscriptionToUpdateNotFoundInHistory | 24 | No se encontró la suscripción original que debe renovarse. | | pendingPurchase | 25 | Este error indica que el estado de la compra está pendiente en lugar de completado. Consulta la página [Handling pending transactions](https://developer.android.com/google/play/billing/integrate#pending) en la documentación para desarrolladores de Android para más detalles. | | billingServiceTimeout | 97 | Este error indica que la solicitud alcanzó el tiempo de espera máximo antes de que Google Play pudiera responder. Esto puede deberse, por ejemplo, a un retraso en la ejecución de la acción solicitada por la llamada a la Play Billing Library. | | featureNotSupported | 98 | La función solicitada no es compatible con la Play Store en el dispositivo actual. | | billingServiceDisconnected | 99 | Este error fatal indica que la conexión de la app cliente al servicio de Google Play Store a través del `BillingClient` se ha interrumpido. | | billingServiceUnavailable | 102 | Este error transitorio indica que el servicio de facturación de Google Play no está disponible en este momento. En la mayoría de los casos, significa que hay un problema de conexión de red entre el dispositivo cliente y los servicios de facturación de Google Play. | | billingUnavailable | 103 |Este error indica que ocurrió un error de facturación del usuario durante el proceso de compra. Algunos ejemplos de cuándo puede ocurrir:
1\. La app de Play Store en el dispositivo del usuario está desactualizada.
2. El usuario está en un país no compatible.
3. El usuario es un empleado de empresa y su administrador ha deshabilitado las compras.
4. Google Play no puede cargar el método de pago del usuario. Por ejemplo, la tarjeta de crédito del usuario puede haber caducado.
5. El usuario no ha iniciado sesión en la app de Play Store.
| | developerError | 105 | Este es un error fatal que indica que estás usando una API de forma incorrecta. | | billingError | 106 | Este es un error fatal que indica un problema interno en Google Play. | | itemAlreadyOwned | 107 | El producto consumible ya ha sido comprado. | | itemNotOwned | 108 | Este error indica que la acción solicitada sobre el artículo falló. | ## Códigos personalizados de StoreKit \{#custom-storekit-codes\} | Error | Código | Descripción | |-----|----|-----------| | noProductIDsFound | 1000 |Este error indica que ninguno de los productos del paywall está disponible en la store.
Si encuentras este error, sigue los pasos a continuación para resolverlo:
1. Comprueba que todos los productos se han añadido al Adapty Dashboard.
2. Asegúrate de que el Bundle ID de tu app coincide con el de Apple Connect.
3. Verifica que los identificadores de producto de las app stores coincidan con los que has añadido al Dashboard. Ten en cuenta que los identificadores no deben contener el Bundle ID, a menos que ya esté incluido en la store.
4. Confirma que el estado de pago de la app está activo en tu configuración fiscal de Apple. Asegúrate de que tu información fiscal está actualizada y que tus certificados son válidos.
5. Comprueba que hay una cuenta bancaria vinculada a la app para que pueda ser elegible para la monetización.
6. Verifica que los productos estén disponibles en todas las regiones. Además, asegúrate de que tus productos estén en estado **"Ready to Submit"**.
| | productRequestFailed | 1002 |No se pueden obtener los productos disponibles en este momento. Posible razón:
- Aún no se ha creado ninguna caché y no hay conexión a internet al mismo tiempo.
| | cantMakePayments | 1003 | Las compras in-app no están permitidas en este dispositivo. | | noPurchasesToRestore | 1004 | Este error indica que Google Play no encontró ninguna compra que restaurar. | | cantReadReceipt | 1005 |No hay ningún recibo válido disponible en el dispositivo. Esto puede ser un problema durante las pruebas en sandbox.
No se requiere ninguna acción, pero en términos de lógica de negocio, puedes ofrecer un descuento al usuario o recordárselo más adelante.
| | productPurchaseFailed | 1006 | La compra del producto falló. Esto envuelve un error subyacente de StoreKit: lee el error interno (o activa los registros detallados para verlo en la consola) para conocer la razón exacta. El error interno suele ser uno de los códigos de StoreKit 0–14 de la tabla anterior, siendo los más comunes `paymentCancelled`, `paymentInvalid`, `paymentNotAllowed` o `invalidOfferPrice`. Si no puedes identificar una razón concreta, prueba con un nuevo [perfil de sandbox](test-purchases-in-sandbox); si sigue fallando, contacta con el soporte de Apple. | | refreshReceiptFailed | 1010 | Este error indica que no se recibió el recibo. Solo aplica a StoreKit 1. | | receiveRestoredTransactionsFailed | 1011 | La restauración de la compra falló. | ## Códigos de red personalizados \{#custom-network-codes\} | Error | Código | Descripción | | :------------------- | :----- | :----------------------------------------------------------- | | notActivated | 2002 | Necesitas configurar correctamente el SDK de Adapty mediante el método `Adapty.activate`. Aprende cómo hacerlo [para React Native](sdk-installation-reactnative). | | badRequest | 2003 | Solicitud incorrecta. | | serverError | 2004 | Error del servidor. | | networkFailed | 2005 | La solicitud de red falló. | | decodingFailed | 2006 | Este error indica que falló la decodificación de la respuesta. | | encodingFailed | 2009 | Este error indica que falló la codificación de la solicitud. | | analyticsDisabled | 3000 | No podemos gestionar eventos de análisis porque los has desactivado. Consulta el tema [Analytics integration](analytics-integration) para más detalles. | | wrongParam | 3001 | Este error indica que alguno de tus parámetros no es correcto: está en blanco cuando no puede estarlo, tiene un tipo incorrecto, etc. | | activateOnceError | 3005 | No es posible llamar al método `.activate` más de una vez. | | profileWasChanged | 3006 | El perfil de usuario cambió durante la operación. | | fetchTimeoutError | 3101 | Este error significa que el paywall no se pudo obtener dentro del límite establecido. Para evitar esta situación, [configura los fallbacks locales](fetch-paywalls-and-products). | | operationInterrupted | 9000 | Esta operación fue interrumpida por el sistema. | --- # File: capacitor-sdk-migration-guides --- --- title: "Guías de migración del SDK de Capacitor" description: "Guías de migración para las versiones del SDK de Adapty para Capacitor." --- Esta página contiene todas las guías de migración para el SDK de Adapty para Capacitor. Elige la versión a la que quieres migrar para obtener instrucciones detalladas: - **[Migrar a v4.0 (beta)](migration-to-capacitor-sdk-v4)** - [**Migrar a v3.16**](migration-to-capacitor-316) --- # File: migration-to-capacitor-sdk-v4 --- --- title: "Migrar el SDK de Adapty Capacitor a v. 4.0" description: "Migra al SDK de Adapty Capacitor v4.0 (beta) reemplazando las APIs de paywall por APIs de flow, compatibles tanto con Flow Builder como con Paywall Builder." --- El SDK de Adapty Capacitor 4.0 (beta) introduce flows y renombra las APIs de paywall en consecuencia. Las nuevas APIs funcionan tanto con el nuevo Flow Builder como con el Paywall Builder existente; no se requieren cambios de configuración en el Adapty Dashboard. ## Referencia rápida \{#quick-reference\} | v3 | v4 | |---|---| | `adapty.getPaywall({ placementId, locale?, params? })` | `adapty.getFlow({ placementId, params? })` | | `adapty.getPaywallForDefaultAudience({ placementId, locale?, params? })` | `adapty.getFlowForDefaultAudience({ placementId, params? })` | | `adapty.getPaywallProducts({ paywall })` | `adapty.getPaywallProducts({ flow })` | | `adapty.logShowPaywall({ paywall })` | `adapty.logShowFlow({ flow })` | | `AdaptyPaywall` (tipo) | `AdaptyFlow` + `AdaptyFlowPaywall` | | `createPaywallView(paywall, params?)` | `createFlowView(flow, params?)` | | `PaywallViewController` | `FlowViewController` | | `EventHandlers` (tipo) | `FlowEventHandlers` | | `CreatePaywallViewParamsInput` | `CreateFlowViewParamsInput` | | `onRenderingFailed` | `onError` | `AdaptyPaywallProduct` mantiene su nombre — los productos siguen perteneciendo a un flow, y `getPaywallProducts` también mantiene su nombre, ahora aceptando un `AdaptyFlow`. Los métodos `getFlow` y `getFlowForDefaultAudience` ya no reciben un parámetro `locale`. Las APIs de compra y perfil (`makePurchase`, `restorePurchases`, `getProfile`, `identify`, `updateProfile`) y los respaldos mediante `setFallback` no han cambiado. Los métodos de vista `present`, `dismiss`, `setEventHandlers` y `showDialog`, y los manejadores de eventos `onCloseButtonPress`, `onUrlPress`, `onCustomAction`, `onProductSelected`, `onPurchaseStarted`, `onPurchaseCompleted`, `onPurchaseFailed`, `onRestoreStarted`, `onRestoreCompleted`, `onRestoreFailed`, `onLoadingProductsFailed`, `onWebPaymentNavigationFinished` y `onAndroidSystemBack` mantienen los mismos nombres que en v3. Los métodos de onboarding siguen funcionando pero están obsoletos — consulta [Deprecación de la API de Onboarding](#onboarding-api-deprecation). Algunos comportamientos predeterminados han cambiado — consulta [Cambios en el comportamiento predeterminado](#default-behavior-changes). ## Versiones mínimas \{#minimum-versions\} Los requisitos de ejecución no han cambiado desde v3.16+: **iOS 15.0**, **Android minSdk 24** y **Capacitor 8**. No es necesario modificar el deployment target. Hay un nuevo requisito de compilación: **Xcode 26 o posterior** — el SDK nativo de Adapty para iOS 4.0.0-beta.2 incluido en esta versión usa Swift tools 6.2. v4 incluye los SDKs nativos de Adapty iOS 4.0.0-beta.2 y Android BOM 4.0.0-beta.1. ## Instalación \{#installation\} ### Actualizar el paquete \{#update-the-package\} La v4.0 es una versión preliminar, así que fija la versión exacta; npm no selecciona versiones preliminares mediante rangos con acento circunflejo o tilde: ```bash showLineNumbers npm install @adapty/capacitor@4.0.0-beta.2 ``` Luego sincroniza los proyectos nativos: ```bash showLineNumbers npx cap sync ``` ### iOS: solo Swift Package Manager [El repositorio de specs de CocoaPods pasará a ser de solo lectura en diciembre de 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/), por lo que a partir de la v4 se elimina el `AdaptyCapacitor.podspec` y el SDK se instala en iOS **únicamente a través de Swift Package Manager (SPM)**. El proyecto iOS de tu app debe utilizar la integración SPM de Capacitor: - Aplicaciones nuevas: añade la plataforma iOS con el gestor de paquetes SPM: ```bash showLineNumbers npx cap add ios --packagemanager SPM ``` - Aplicaciones existentes basadas en CocoaPods: migra el proyecto iOS siguiendo la [guía de Capacitor para usar SPM en un proyecto existente](https://capacitorjs.com/docs/ios/spm#using-spm-in-an-existing-capacitor-project). Consulta [Instalar el SDK de Adapty](sdk-installation-capacitor) para ver la configuración completa. ## Obtener flows \{#fetching-flows\} ### getPaywall → getFlow El tipo retornado cambia de `AdaptyPaywall` a `AdaptyFlow`, y la opción `locale` se elimina — cuando renderizas un flow, el idioma se resuelve automáticamente; para paywalls personalizados, todos los idiomas se devuelven en `flow.remoteConfigs`: ```diff showLineNumbers - const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en' }); + const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); ``` `getPaywallForDefaultAudience` se renombra de la misma forma: ```diff showLineNumbers - const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en' }); + const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID' }); ``` ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` mantiene su nombre pero ahora recibe un `AdaptyFlow`: ```diff showLineNumbers - const products = await adapty.getPaywallProducts({ paywall }); + const products = await adapty.getPaywallProducts({ flow }); ``` ## Modelo de datos \{#data-model\} `getFlow` devuelve un `AdaptyFlow` en lugar de un `AdaptyPaywall`, y la forma del objeto ha cambiado: | Campo v3 `AdaptyPaywall` | Campo v4 `AdaptyFlow` | Acción | |---|---|---| | `remoteConfig?` (único) | `remoteConfigs?: AdaptyRemoteConfig[]` (array) | Un flow lleva un Remote Config por idioma configurado. Lee el que coincida con el usuario: `flow.remoteConfigs?.find((c) => c.lang === 'en')`. | | `products` | `flow.paywalls[i].productIdentifiers` | Los identificadores de producto ahora están en cada variación del flow, no en el flow. | | `webPurchaseUrl?` | `flow.paywalls[i].webPurchaseUrl` | Movido del flow a cada variación de paywall. | | `version?: number` | `flowVersionId?: string` | Renombrado, y el tipo cambió de `number` a `string`. | | `hasViewConfiguration` | eliminado | Elimina cualquier comprobación de `hasViewConfiguration` en tu código — `createFlowView` ahora lanza un error en su lugar (ver [Mostrar flows](#displaying-flows)). | | `requestLocale` | eliminado | El locale ya no forma parte del modelo. | | _(nuevo)_ | `paywalls: AdaptyFlowPaywall[]` | Cada entrada es una variación de paywall en el flow. | | _(nuevo)_ | `responseCreatedAt: number` | Marca de tiempo de la respuesta del servidor, en milisegundos. | `hasViewConfiguration` y `requestLocale` permanecen en `AdaptyOnboarding` — solo el modelo de flow los elimina. Los identificadores de producto se han movido del flow a cada variación: ```diff showLineNumbers - const ids = paywall.products; + const ids = flow.paywalls[0].productIdentifiers; ``` ## Métodos de paywall web \{#web-paywall-methods\} `openWebPaywall` y `createWebPaywallUrl` mantienen sus nombres, pero la opción `paywallOrProduct` ahora acepta un `AdaptyFlowPaywall` (una variante de flow) en lugar de un `AdaptyPaywall`. Todavía puedes pasar un `AdaptyPaywallProduct`. Asegúrate de que `flow.paywalls` no esté vacío antes de leer la primera entrada: ```diff showLineNumbers const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); - await adapty.openWebPaywall({ paywallOrProduct: paywall }); + await adapty.openWebPaywall({ paywallOrProduct: flow.paywalls[0] }); ``` ## Seguimiento de vistas de flow \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` ha pasado a llamarse `logShowFlow` y ahora recibe un `AdaptyFlow`. El evento se sigue registrando contra la misma variación, por lo que las métricas de funnel y prueba A/B existentes siguen funcionando sin cambios en el dashboard. ```diff showLineNumbers - await adapty.logShowPaywall({ paywall }); + await adapty.logShowFlow({ flow }); ``` Al igual que en v3, no es necesario llamar a este método al mostrar flows o paywalls renderizados por el [Flow Builder](adapty-flow-builder) o el [Paywall Builder](adapty-paywall-builder) — Adapty registra esas vistas automáticamente. ## Mostrar flows \{#displaying-flows\} ### createPaywallView → createFlowView \{#createpaywallview--createflowview\} Renombra la función factory y pasa el `AdaptyFlow`. El controlador devuelto pasa de llamarse `PaywallViewController` a `FlowViewController`, pero sus métodos (`present`, `dismiss`, `setEventHandlers`, `showDialog`) no cambian. El tipo de parámetros se renombra de `CreatePaywallViewParamsInput` a `CreateFlowViewParamsInput`: ```diff showLineNumbers - import { createPaywallView } from '@adapty/capacitor'; + import { createFlowView } from '@adapty/capacitor'; - const view = await createPaywallView(paywall); + const view = await createFlowView(flow); await view.present(); ``` `createFlowView` lanza un `AdaptyError` si el flow no tiene ninguna vista configurada; esto reemplaza la comprobación `hasViewConfiguration` de la v3: ```diff showLineNumbers - if (paywall.hasViewConfiguration) { - const view = await createPaywallView(paywall); - await view.present(); - } + try { + const view = await createFlowView(flow); + await view.present(); + } catch (error) { + // the flow has no view configured, or view creation failed + } ``` :::note Una vista de flow es de un solo uso: después de llamar a `dismiss()`, la vista se destruye y sus manejadores de eventos se eliminan, así que llama a `createFlowView` de nuevo para mostrar el flow otra vez. ::: ### Rellenos de área segura en Android \{#android-safe-area-paddings\} `CreateFlowViewParamsInput` añade un nuevo parámetro: `enableSafeArea`, que controla los rellenos de área segura en Android en tiempo de ejecución. Se anida bajo la clave `android` y tiene el valor predeterminado `true`: ```typescript showLineNumbers const view = await createFlowView(flow, { android: { enableSafeArea: true }, }); ``` ## Manejo de eventos \{#handling-events\} La interfaz del manejador de eventos pasa de llamarse `EventHandlers` a `FlowEventHandlers`, y un callback también cambia de nombre. El cuerpo de los manejadores existentes no necesita modificaciones — solo renombra: ```diff showLineNumbers - onRenderingFailed: (error) => { /* … */ }, + onError: (error) => { /* … */ }, ``` Todos los demás manejadores de eventos conservan sus nombres. Dos de ellos también reciben un segundo argumento: `onPurchaseCompleted` pasa a ser `(purchaseResult, product)` y `onPurchaseFailed` pasa a ser `(error, product)`, donde `product` es el `AdaptyPaywallProduct` involucrado. Consulta [Gestión de eventos de flow y paywall](capacitor-handling-events) para ver la lista completa. La v4 también añade algunas funcionalidades opcionales que puedes activar: - Los métodos `adapty.openWebUrl({ url, openIn })` y `adapty.requestAppReview()` respaldan los manejadores predeterminados `onUrlPress` y `onRequestAppReview`, de modo que las URLs y las solicitudes de reseña de la app se gestionan de forma nativa sin configuración adicional. Llámalos directamente solo si sustituyes esos manejadores. - Gestión de compras en modo Observer dentro de flows mediante los nuevos manejadores `onObserverPurchaseInitiated` / `onObserverRestoreInitiated`. Consulta [Presentar flows en modo Observer](capacitor-present-flows-in-observer-mode). ## Cambios en el comportamiento predeterminado \{#default-behavior-changes\} Estos cambios no generan errores de compilación, así que pruébalos en tiempo de ejecución: - **`onAndroidSystemBack`**: El comportamiento predeterminado cambió de cerrar la vista a mantenerla abierta. Para restaurar el comportamiento anterior, devuelve `true` desde el handler. - **`onPurchaseCompleted`**: El comportamiento predeterminado cambió de cerrar la vista (salvo que el usuario cancelara la compra) a mantenerla siempre abierta. Para restaurar el comportamiento anterior, devuelve `purchaseResult.type !== 'user_cancelled'` desde el handler. - **`onRestoreCompleted`**: El comportamiento predeterminado cambió de cerrar la vista tras una restauración exitosa a mantenerla abierta. Para restaurar el comportamiento anterior, devuelve `true` desde el handler. - **`onUrlPress`**: Ahora el comportamiento predeterminado abre la URL a través de la capa nativa, respetando la configuración de navegador integrado o externo del dashboard. Reemplaza el handler para abrir URLs tú mismo. - **Las vistas son de un solo uso**: Después de `dismiss()`, la vista se destruye. Llama a `createFlowView` de nuevo para mostrar el flow otra vez. ## APIs eliminadas \{#removed-apis\} ### Exportaciones eliminadas \{#removed-exports\} Estos símbolos ya no se exportan desde `@adapty/capacitor`. Elimina sus importaciones: - **`AdaptyPaywall`**: Usa `AdaptyFlow` y `AdaptyFlowPaywall` en su lugar. - **`ProductReference`**: Usa `AdaptyProductIdentifier`, léelo desde `flow.paywalls[i].productIdentifiers`. - **`AdaptyPaywallBuilder`**: Eliminado. Los flows y paywalls se renderizan de forma nativa. - **`AdaptyAndroidSubscriptionUpdateParameters`**: Usa la forma anidada de parámetros de compra `android` (ver más abajo). ### activate: lockMethodsUntilReady `lockMethodsUntilReady` (ya obsoleto y sin efecto en v3) ha sido eliminado. Quítalo de tu llamada a `activate` — mantenerlo ya no compila: ```diff showLineNumbers - await adapty.activate({ apiKey: 'PUBLIC_SDK_KEY', params: { lockMethodsUntilReady: true } }); + await adapty.activate({ apiKey: 'PUBLIC_SDK_KEY' }); ``` ### makePurchase: parámetros de Android \{#makepurchase-android-parameters\} La forma plana obsoleta de `MakePurchaseParamsInput` para Android ha sido eliminada; solo queda la forma anidada. Mueve los parámetros de compra de Android a `params: { android: { ... } }`. Consulta [Realizar compras](capacitor-making-purchases) para ver el ejemplo completo. ## Deprecación de la API de onboarding \{#onboarding-api-deprecation\} La API de onboarding heredada está deprecada en la v4.0 a favor del [Flow Builder](adapty-flow-builder). Sigue funcionando, pero se eliminará en una versión futura, así que planifica la migración de tus onboardings al Flow Builder. Símbolos deprecados: `getOnboarding`, `getOnboardingForDefaultAudience`, `createOnboardingView` y `OnboardingViewController`. --- # File: migration-to-capacitor-316 --- --- title: "Migrar el SDK de Adapty para Capacitor a v3.16" description: "Migra al SDK de Adapty para Capacitor v3.16 para obtener mejor rendimiento y nuevas funciones de monetización." --- A partir de Adapty SDK v3.16.0, se requiere Capacitor 8. Si necesitas Capacitor 7, usa Adapty SDK v3.15. Para actualizar al SDK de Capacitor v3.16, asegúrate de que tu proyecto use Capacitor 8. Si todavía usas Capacitor 7, tienes dos opciones: 1. **Actualiza a Capacitor 8**: Sigue la [guía oficial de migración de Capacitor](https://capacitorjs.com/docs/updating/8-0) para actualizar tu proyecto y luego instala Adapty SDK v3.16. 2. **Quédate en Adapty SDK v3.15**: Si actualizar a Capacitor 8 no es viable, continúa usando Adapty SDK v3.15, que es compatible con Capacitor 7. --- # End of Documentation _Generated on: 2026-07-24T13:01:55.649Z_ _Successfully processed: 45/45 files_ # FLUTTER - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: es Generated on: 2026-07-24T13:01:55.651Z Total files: 44 --- # File: sdk-installation-flutter --- --- title: "Instalar y configurar el SDK de Flutter" description: "Guía paso a paso para instalar el SDK de Adapty en Flutter para aplicaciones con suscripciones." --- El SDK de Adapty incluye dos módulos clave para una integración fluida en tu app Flutter: - **Core Adapty**: Este SDK esencial es necesario para que Adapty funcione correctamente en tu app. - **AdaptyUI**: Este módulo es necesario si usas el [Adapty Paywall Builder](adapty-paywall-builder), una herramienta visual sin código para crear paywalls multiplataforma fácilmente. :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Consulta nuestra [app de ejemplo](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example), que muestra la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funciones básicas. ::: ## Requisitos \{#requirements\} El SDK de Adapty es compatible con iOS 13.0+, pero requiere iOS 15.0+ para funcionar correctamente con paywalls creados en el Paywall Builder. Adapty Flutter SDK 4.0 — que añade soporte para [Flow Builder](adapty-flow-builder) — eleva los requisitos mínimos a **iOS 15.0+**, **Xcode 26+** y **Flutter 3.32.0+** (Dart 3.8.0+). Consulta [Adapty SDK 4.0](#adapty-sdk-40-swift-package-manager) más abajo para ver los detalles de instalación. :::info Adapty es compatible con Google Play Billing Library hasta la versión 8.x. Por defecto, Adapty funciona con Google Play Billing Library v7.0.0, pero si quieres forzar una versión posterior, puedes añadir la dependencia manualmente siguiendo [este enlace](https://developer.android.com/google/play/billing/integrate#dependency). ::: :::info Instalar el SDK es el paso 5 de la configuración de Adapty. Para que las compras funcionen en tu app, también necesitas conectar tu app a los stores, y luego crear productos, un paywall y un placement en el Adapty Dashboard. La [guía de inicio rápido](quickstart) explica todos los pasos necesarios. ::: ## Instalar el SDK de Adapty \{#install-adapty-sdk\} [](https://github.com/adaptyteam/AdaptySDK-Flutter/releases) :::important Los pasos a continuación instalan la última versión estable del SDK (3.x). Si necesitas la v4 — necesaria para el [Flow Builder](adapty-flow-builder) y utilizada en la [guía de inicio rápido](flutter-quickstart-paywalls) — sigue en su lugar [Adapty SDK 4.0: Swift Package Manager](#adapty-sdk-40-swift-package-manager) más abajo. ::: 1. Añade Adapty a tu archivo `pubspec.yaml`: ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter: ^
### Durante el login/registro \{#during-loginsignup\}
Si identificas a los usuarios después del lanzamiento de la app (por ejemplo, después de que inicien sesión o se registren), usa el método `identify` para establecer su customer user ID.
- Si **no has usado este customer user ID antes**, Adapty lo vinculará automáticamente al perfil actual.
- Si **ya has usado este customer user ID para identificar al usuario**, Adapty cambiará al perfil asociado a ese customer user ID.
:::important
Los customer user IDs deben ser únicos para cada usuario. Si defines el valor del parámetro de forma fija en el código, todos los usuarios se considerarán como uno solo.
:::
Siempre usa `await` con `identify` antes de llamar a otros métodos del SDK. Las llamadas concurrentes generan `#3006 profileWasChanged` o se aplican al perfil anónimo. Consulta [Orden de llamadas en el SDK de Flutter](flutter-sdk-call-order).
```dart showLineNumbers
try {
await Adapty().identify(customerUserId); // Unique for each user
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
}
```
### Durante la activación del SDK \{#during-the-sdk-activation\}
Si ya conoces el customer user ID cuando activas el SDK, puedes enviarlo en el método `activate` en lugar de llamar a `identify` por separado.
Si conoces el customer user ID pero lo defines solo después de la activación, Adapty creará un nuevo perfil anónimo al activarse y cambiará al existente solo después de que llames a `identify`.
Puedes pasar un customer user ID existente (uno que hayas usado antes) o uno nuevo. Si pasas uno nuevo, el perfil creado al activarse se vinculará automáticamente al customer user ID.
:::note
De forma predeterminada, la creación de perfiles anónimos no afecta a los dashboards de análisis, porque las instalaciones se cuentan según los IDs de dispositivo.
Un ID de dispositivo representa una única instalación de la app desde el store en un dispositivo y solo se regenera después de reinstalar la app.
No depende de si es una primera o posterior instalación, ni de si se usa un customer user ID existente.
Crear un perfil (al activar el SDK o al cerrar sesión), iniciar sesión o actualizar la app sin reinstalarla no genera eventos de instalación adicionales.
Si quieres contar las instalaciones por usuarios únicos en lugar de por dispositivos, ve a **App settings** y configura [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```dart showLineNumbers"
try {
await Adapty().activate(
configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY')
..withCustomerUserId(YOUR_CUSTOMER_USER_ID) // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one.
);
} catch (e) {
// handle the error
}
```
### Cerrar sesión de usuarios \{#log-users-out\}
Si tienes un botón para cerrar sesión de los usuarios, usa el método `logout`.
:::important
Cerrar la sesión de un usuario crea un nuevo perfil anónimo para ese usuario.
:::
```dart showLineNumbers
try {
await Adapty().logout();
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
// handle unknown error
}
```
:::info
Para volver a iniciar sesión en la app, usa el método `identify`.
:::
### Permitir compras sin inicio de sesión \{#allow-purchases-without-login\}
Si tus usuarios pueden realizar compras tanto antes como después de iniciar sesión en tu app, debes asegurarte de que conserven el acceso después de iniciar sesión:
1. Cuando un usuario sin sesión iniciada realiza una compra, Adapty la vincula a su ID de perfil anónimo.
2. Cuando el usuario inicia sesión en su cuenta, Adapty cambia a trabajar con su perfil identificado.
- Si es un nuevo customer user ID (por ejemplo, la compra se realizó antes del registro), Adapty asigna el customer user ID al perfil actual, por lo que se mantiene todo el historial de compras.
- Si es un customer user ID existente (el customer user ID ya está vinculado a un perfil), debes obtener el nivel de acceso actual después del cambio de perfil. Puedes llamar a [`getProfile`](flutter-check-subscription-status) justo después de la identificación, o [escuchar las actualizaciones del perfil](flutter-check-subscription-status) para que los datos se sincronicen automáticamente.
## Siguientes pasos \{#next-steps\}
¡Enhorabuena! Has implementado la lógica de pagos in-app en tu app. ¡Te deseamos mucho éxito con la monetización de tu app!
Para sacar aún más partido a Adapty, puedes explorar estos temas:
- [**Pruebas**](troubleshooting-test-purchases): Verifica que todo funciona como se espera
- [**Onboardings**](flutter-onboardings): Engancha a los usuarios con onboardings y mejora la retención
- [**Integraciones**](configuration): Integra con servicios de atribución de marketing y análisis con una sola línea de código
- [**Establecer atributos de perfil personalizados**](flutter-setting-user-attributes): Añade atributos personalizados a los perfiles de usuario y crea segmentos para lanzar pruebas A/B o mostrar diferentes paywalls a distintos usuarios
---
# File: adapty-sdk-integration-skill-flutter
---
---
title: "Integra Adapty en tu app Flutter con la skill de integración del SDK"
description: "Usa la skill adapty-sdk-integration para integrar el SDK de Adapty en tu app Flutter de principio a fin con tu herramienta de codificación con IA."
---
Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché de actualización periódica descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| | **loadTimeout** | por defecto: 5 seg |Un `Duration` que limita el tiempo de espera de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede agotar el tiempo ligeramente más tarde de lo especificado en `loadTimeout`, ya que la operación puede estar compuesta de diferentes peticiones internamente.
| ## Parámetros de respuesta \{#response-parameters\} | Parámetro | Descripción | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | Un objeto `AdaptyFlow` con los identificadores del flow (`instanceIdentity`, `variationId`), el nombre, el placement, sus variaciones de paywall (`paywalls`) y cualquier Remote Config (`remoteConfigs`). | ## Obtén la configuración de la vista \{#fetch-the-view-configuration\} :::important Asegúrate de activar el interruptor **Show on device** en el builder. Si esta opción no está activada, la configuración de la vista no estará disponible para recuperar. ::: Si el placement fue diseñado en el **Flow Builder** o en el **Paywall Builder**, Adapty renderiza la interfaz por ti — la propiedad `hasViewConfiguration` del flow obtenido es `true`. Crea la vista con `createFlowView` y luego [presenta el flow o paywall](flutter-present-paywalls). Si el placement es un paywall personalizado sin interfaz de Builder (`hasViewConfiguration` es `false`), [gestiónalo como un paywall de Remote Config](present-remote-config-paywalls-flutter). :::warning El resultado del método `createFlowView` solo se puede presentar una vez. Si necesitas presentarlo de nuevo, llama al método `createFlowView` otra vez. ::: ```dart showLineNumbers try { final view = await AdaptyUI().createFlowView(flow: flow); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` Parámetros: | Parámetro | Presencia | Descripción | | :------------------- | :-------- | :----------------------------------------------------------- | | **flow** | obligatorio | Un objeto `AdaptyFlow` para obtener una vista del flow/paywall deseado. | | **customTags** | opcional | Define un mapa de etiquetas personalizadas y sus valores resueltos. Las etiquetas personalizadas actúan como marcadores de posición en el contenido, reemplazados dinámicamente por cadenas específicas para personalizar el contenido dentro del flow/paywall. Consulta el tema [Custom tags in paywall builder](custom-tags-in-paywall-builder) para más detalles. | | **preloadProducts** | opcional | Actívalo para optimizar el tiempo de visualización de los productos en pantalla. Cuando es `true`, AdaptyUI obtendrá automáticamente los productos necesarios. Por defecto: `false`. | | **loadTimeout** | opcional | Una `Duration` que limita el tiempo de carga de la configuración de la vista. Si se alcanza el tiempo límite, se usarán los datos en caché o el fallback local. | :::note Si utilizas varios idiomas, aprende cómo añadir una [localización de flow](add-paywall-locale-in-adapty-paywall-builder) y cómo usar los códigos de idioma correctamente [aquí](flutter-localizations-and-locale-codes). ::: Una vez que tengas la vista, [presenta el flow/paywall](flutter-present-paywalls). ## Obtén un flow o paywall para la audiencia predeterminada y cárgalo más rápido \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} Por lo general, los flows y paywalls se cargan casi de inmediato, así que no necesitas preocuparte por acelerar este proceso. Sin embargo, si tienes muchas audiencias y placements, y tus usuarios tienen una conexión a internet lenta, la carga de un flow o paywall puede tardar más de lo deseado. En esos casos, puede que quieras mostrar un flow o paywall predeterminado para garantizar una experiencia fluida, en lugar de no mostrar nada. Para abordar esto, puedes usar el método `getFlowForDefaultAudience`, que obtiene el flow o paywall del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el flow o paywall mediante el método `getFlow`, tal como se detalla en la sección [Obtener flow/paywall](#fetch-flowpaywall) anterior. :::warning Por qué recomendamos usar `getFlow` El método `getFlowForDefaultAudience` tiene algunos inconvenientes importantes: - **Posibles problemas de compatibilidad con versiones anteriores**: Si necesitas mostrar diferentes paywalls para distintas versiones de la app (la actual y las futuras), puedes encontrarte con dificultades. Tendrás que diseñar paywalls que sean compatibles con la versión actual (heredada) o aceptar que los usuarios con esa versión puedan tener problemas con paywalls que no se renderizan correctamente. - **Pérdida de targeting**: Todos los usuarios verán el mismo paywall diseñado para la audiencia **All Users**, lo que significa que pierdes la personalización del targeting (incluyendo por países, atribución de marketing o tus propios atributos personalizados). Si estás dispuesto a aceptar estos inconvenientes para beneficiarte de una obtención más rápida del flow o paywall, usa el método `getFlowForDefaultAudience` de la siguiente manera. De lo contrario, quédate con `getFlow` descrito [arriba](#fetch-flowpaywall). ::: ```dart showLineNumbers try { final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); // the requested flow/paywall } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` | Parámetro | Presencia | Descripción | |---------|--------|-----------| | **placementId** | obligatorio | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro utilizarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| ## Personalizar recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu flow/paywall, implementa los recursos personalizados. Las imágenes y vídeos principales tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizados, apuntas a estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. Aquí tienes un ejemplo de cómo puedes proporcionar assets personalizados mediante un diccionario sencillo: ```dart final customAssets = { // Show a local image using a custom ID 'custom_image': AdaptyCustomAsset.localImageAsset( assetId: 'assets/images/image_name.png', ), // Show a local video with a preview image 'hero_video': AdaptyCustomAsset.localVideoAsset( assetId: 'assets/videos/custom_video.mp4', ), }; try { final view = await AdaptyUI().createFlowView( flow: flow, customAssets: customAssets, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::note Si no se encuentra un recurso, el flow/paywall volverá a su apariencia predeterminada. ::: ## Configurar temporizadores definidos por el desarrollador \{#set-up-developer-defined-timers\} Para usar temporizadores personalizados en tu app, pasa un mapa `customTimers` al método `createFlowView`. Cada clave del mapa es un ID de temporizador, y su valor es un objeto `DateTime` que define cuándo termina el temporizador. Aquí tienes un ejemplo: ```dart showLineNumbers try { final view = await AdaptyUI().createFlowView( flow: flow, customTimers: { 'CUSTOM_TIMER_6H': DateTime.now().add(const Duration(seconds: 3600 * 6)), 'CUSTOM_TIMER_NY': DateTime(2027, 1, 1), // New Year 2027 }, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` En este ejemplo, `CUSTOM_TIMER_NY` y `CUSTOM_TIMER_6H` son los **Timer ID**s de los temporizadores definidos por el desarrollador que configuraste en el Adapty Dashboard. El mapa `customTimers` garantiza que tu app actualice dinámicamente cada temporizador con el valor correcto. Por ejemplo: - `CUSTOM_TIMER_NY`: El tiempo restante hasta el final del temporizador, como el día de Año Nuevo. - `CUSTOM_TIMER_6H`: El tiempo restante en un período de 6 horas que comenzó cuando el usuario abrió el flow.opcional
predeterminado: `en`
|El identificador de la [localización del paywall](add-paywall-locale-in-adapty-paywall-builder). Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](flutter-localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | predeterminado: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché de actualización regular descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| | **loadTimeout** | predeterminado: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos raros este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede estar compuesta por diferentes solicitudes internamente.
Para Android: puedes crear `TimeInterval` con funciones de extensión (como `5.seconds`, donde `.seconds` proviene de `import com.adapty.utils.seconds`), o `TimeInterval.seconds(5)`. Para no establecer ningún límite, usa `TimeInterval.INFINITE`.
| Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) con una lista de IDs de productos, el identificador del paywall, Remote Config y otras propiedades. | ## Obtener la configuración de vista de un paywall diseñado con Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Asegúrate de activar el interruptor **Show on device** en el Paywall Builder. Si esta opción no está activada, la configuración de vista no estará disponible para recuperar. ::: Después de obtener el paywall, comprueba si incluye un `ViewConfiguration`, lo que indica que fue creado con Paywall Builder. Esto te guiará sobre cómo mostrar el paywall. Si el `ViewConfiguration` está presente, trátalo como un paywall de Paywall Builder; si no, [trátalo como un paywall de Remote Config](present-remote-config-paywalls-flutter). ```dart showLineNumbers try { final view = await AdaptyUI().createPaywallView( paywall: paywall, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` Una vez que tengas la vista, [presenta el paywall](flutter-present-paywalls). ## Obtén un paywall para la audiencia predeterminada y cárgalo más rápido \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} Normalmente, los paywalls se cargan casi al instante, por lo que no necesitas preocuparte por optimizar este proceso. Sin embargo, cuando tienes muchas audiencias y paywalls, y tus usuarios tienen una conexión a internet lenta, la carga de un paywall puede tardar más de lo deseable. En esos casos, puede que quieras mostrar un paywall predeterminado para garantizar una experiencia de usuario fluida, en lugar de no mostrar ningún paywall. Para solucionar esto, puedes usar el método `getPaywallForDefaultAudience`, que obtiene el paywall del placement indicado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el paywall con el método `getPaywall`, tal como se describe en la sección [Obtener información del paywall](flutter-get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) anterior. :::warning Por qué recomendamos usar `getPaywall` El método `getPaywallForDefaultAudience` tiene algunos inconvenientes importantes: - **Posibles problemas de compatibilidad con versiones anteriores**: Si necesitas mostrar paywalls distintos para diferentes versiones de la app (la actual y las futuras), puede que te encuentres con dificultades. Tendrás que diseñar paywalls compatibles con la versión actual (legacy) o asumir que los usuarios con esa versión podrían tener problemas al no renderizarse los paywalls. - **Pérdida de segmentación**: Todos los usuarios verán el mismo paywall diseñado para la audiencia **All Users**, lo que significa que pierdes la segmentación personalizada (incluida la basada en países, atribución de marketing o tus propios atributos personalizados). Si estás dispuesto a aceptar estas desventajas para beneficiarte de una obtención más rápida del paywall, usa el método `getPaywallForDefaultAudience` de la siguiente manera. De lo contrario, utiliza `getPaywall` descrito [anteriormente](#fetch-paywall-designed-with-paywall-builder). ::: ```dart showLineNumbers try { final paywall = await Adapty().getPaywallForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` :::note El método `getPaywallForDefaultAudience` está disponible a partir de la versión 3.2.0 del SDK de Flutter. ::: | Parámetro | Presencia | Descripción | |---------|--------|-----------| | **placementId** | obligatorio | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **locale** |opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de configuración regional](localizations-and-locale-codes) para más información sobre los códigos de configuración regional y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no reciban los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala o mediante una limpieza manual.
| ## Personaliza los recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu paywall, implementa los recursos personalizados. Las imágenes y vídeos hero tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizado, apuntas a estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. :::important Para usar esta función, actualiza el SDK de Flutter de Adapty a la versión 3.8.0 o superior. ::: Aquí tienes un ejemplo de cómo puedes proporcionar assets personalizados mediante un diccionario simple: ```dart final customAssets = { // Show a local image using a custom ID 'custom_image': AdaptyCustomAsset.localImageAsset( assetId: 'assets/images/image_name.png', ), // Show a local video with a preview image 'hero_video': AdaptyCustomAsset.localVideoAsset( assetId: 'assets/videos/custom_video.mp4', ), }; try { final view = await AdaptyUI().createPaywallView( paywall: paywall, customAssets: customAssets, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::note Si no se encuentra un recurso, el paywall volverá a su apariencia predeterminada. ::: ## Configura los temporizadores definidos por el desarrollador \{#set-up-developer-defined-timers\} Para usar temporizadores personalizados en tu aplicación móvil, pasa un mapa `customTimers` al método `createPaywallView`. Cada clave del mapa es un ID de temporizador, y su valor es un objeto `DateTime` que define cuándo termina el temporizador. Aquí tienes un ejemplo: ```dart showLineNumbers try { final view = await AdaptyUI().createPaywallView( paywall: paywall, customTimers: { 'CUSTOM_TIMER_6H': DateTime.now().add(const Duration(seconds: 3600 * 6)), 'CUSTOM_TIMER_NY': DateTime(2025, 1, 1), // New Year 2025 }, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` En este ejemplo, `CUSTOM_TIMER_NY` y `CUSTOM_TIMER_6H` son los **Timer ID**s de los temporizadores definidos por el desarrollador que configuraste en el Adapty Dashboard. El mapa `customTimers` asegura que tu app actualice dinámicamente cada temporizador con el valor correcto. Por ejemplo: - `CUSTOM_TIMER_NY`: El tiempo restante hasta el final del temporizador, como el Año Nuevo. - `CUSTOM_TIMER_6H`: El tiempo restante en un período de 6 horas que comenzó cuando el usuario abrió el paywall.
## El número de visualizaciones del paywall es demasiado alto \{#the-paywall-view-number-is-too-big\}
**Problema**: El recuento de visualizaciones del paywall muestra el doble del número esperado.
**Motivo**: Es posible que estés llamando a `logShowFlow` (Flutter SDK v4+) / `logShowPaywall` en tu código, lo que duplica el recuento de visualizaciones si estás usando el Paywall Builder o el Flow Builder. En los flows y paywalls creados con estas herramientas, el seguimiento de análisis es automático, por lo que no necesitas usar este método.
**Solución**: Asegúrate de no llamar a `logShowFlow` (Flutter SDK v4+) / `logShowPaywall` en tu código si estás usando el Paywall Builder o el Flow Builder.
## Otros problemas \{#other-issues\}
**Problema**: Experimentas otros problemas relacionados con el Paywall Builder que no se tratan más arriba.
**Solución**: Migra el SDK a la versión más reciente siguiendo las [guías de migración](flutter-sdk-migration-guides) si es necesario. Muchos problemas se resuelven en versiones más recientes del SDK.
---
# File: flutter-present-flows-in-observer-mode
---
---
title: "Presentar flows en modo Observer en el SDK de Flutter"
description: "Presenta flows y paywalls del Paywall Builder en modo Observer en tu app de Flutter mientras gestionas las compras con tu propio código."
---
Si has personalizado un flow o paywall con el builder, no necesitas preocuparte por renderizarlo en el código de tu app móvil para mostrárselo al usuario. Ese flow o paywall ya contiene tanto qué mostrar como cómo mostrarlo.
:::warning
Esta sección hace referencia únicamente al [modo Observer](observer-vs-full-mode). Si no trabajas en modo Observer, consulta el tema [Mostrar flows y paywalls](flutter-present-paywalls).
:::
:::info
Esta funcionalidad requiere el SDK de Adapty para Flutter 4.0 o posterior; antes solo estaba disponible en los SDKs nativos de iOS y Android. Consulta la [guía de migración](migration-to-flutter-sdk-v4) para actualizar.
:::
Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.
El SDK de Adapty almacena los paywalls en dos capas: la caché actualizada regularmente descrita anteriormente y los [paywalls de respaldo](flutter-use-fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el respaldo local.
Ten en cuenta que en casos excepcionales este método puede agotar el tiempo de espera ligeramente después del valor especificado en `loadTimeout`, ya que la operación puede estar compuesta de diferentes solicitudes internamente.
| :::note En v4, `getFlow` no acepta el parámetro `locale`. Para paywalls personalizados, todas las localizaciones disponibles se devuelven en los Remote Configs del flow (`flow.remoteConfigs`): elige la que corresponda al idioma del dispositivo o a la configuración de la app. Consulta [Localizaciones y códigos de idioma](flutter-localizations-and-locale-codes). ::: Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objeto `AdaptyFlow` con los identificadores del flow (`instanceIdentity`, `variationId`), nombre, placement, sus variaciones de paywall (`paywalls`) y cualquier Remote Config (`remoteConfigs`). | ## Obtener productos \{#fetch-products\} Una vez que tengas el flow, puedes consultar el array de productos que le corresponde: ```dart showLineNumbers try { final products = await Adapty().getPaywallProducts(flow: flow); // the requested products array } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Lista de objetos [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html) con: identificador del producto, nombre del producto, precio, moneda, duración de la suscripción y otras propiedades. | Al implementar tu propio diseño de paywall, probablemente necesitarás acceder a estas propiedades del objeto [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html). A continuación se muestran las propiedades más utilizadas, pero consulta el documento enlazado para obtener información completa sobre todas las propiedades disponibles. | Propiedad | Descripción | |-----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Para mostrar el título del producto, usa `product.localizedTitle`. Ten en cuenta que la localización se basa en el país de la store seleccionado por el usuario, no en el idioma del dispositivo. | | **Price** | Para mostrar el precio localizado, usa `product.price.localizedString`. Esta localización se basa en la configuración regional del dispositivo. También puedes acceder al precio como número usando `product.price.amount`. El valor se proporcionará en la moneda local. Para obtener el símbolo de moneda correspondiente, usa `product.price.currencySymbol`. | | **Subscription Period** | Para mostrar el período (por ejemplo, semana, mes, año, etc.), usa `product.subscription?.localizedPeriod`. Esta localización se basa en el idioma del dispositivo. Para obtener el período de suscripción de forma programática, usa `product.subscription?.period`. Desde ahí puedes acceder al enum `unit` para conocer la duración (es decir, día, semana, mes, año o desconocido). El valor `numberOfUnits` te dará el número de unidades del período. Por ejemplo, para una suscripción trimestral, verás `AdaptyPeriodUnit.month` en la propiedad `unit` y `3` en la propiedad `numberOfUnits`. | | **Introductory Offer** | Para mostrar una insignia u otro indicador de que una suscripción incluye una oferta introductoria, consulta la propiedad `product.subscription?.offer?.phases`. Es una lista que puede contener hasta dos fases de descuento: la fase de prueba gratuita y la fase de precio introductorio. Dentro de cada objeto de fase se encuentran las siguientes propiedades útiles:Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En ese caso, es posible que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo irregular que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro utilizarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la aplicación y solo se borra cuando se reinstala la app o mediante una limpieza manual.
|opcional
valor por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](flutter-localizations-and-locale-codes) para obtener más información sobre los códigos de idioma y cómo recomendamos utilizarlos.
| | **fetchPolicy** | valor por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la aplicación y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls en dos capas: la caché de actualización regular descrita anteriormente y los [paywalls de respaldo](flutter-use-fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | valor por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que, en casos excepcionales, este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede estar compuesta por varias peticiones internas.
| ¡No escribas los IDs de productos en el código! Dado que los paywalls se configuran de forma remota, los productos disponibles, el número de productos y las ofertas especiales (como las pruebas gratuitas) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si inicialmente obtienes 2 productos, tu app debe mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, tu app debe mostrar los 3 sin necesidad de ningún cambio en el código. Lo único que tienes que escribir en el código es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) con: una lista de IDs de productos, el identificador del paywall, Remote Config y otras propiedades. | ## Obtener productos \{#fetch-products\} Una vez que tengas el paywall, puedes consultar el array de productos que le corresponde: ```dart showLineNumbers try { final products = await Adapty().getPaywallProducts(paywall: paywall); // the requested products array } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Lista de objetos [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html) con: identificador del producto, nombre del producto, precio, moneda, duración de la suscripción y otras propiedades. | Al implementar tu propio diseño de paywall, probablemente necesitarás acceder a estas propiedades del objeto [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html). A continuación se muestran las propiedades más utilizadas; consulta el documento enlazado para obtener todos los detalles sobre las propiedades disponibles. | Propiedad | Descripción | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Para mostrar el título del producto, usa `product.localizedTitle`. Ten en cuenta que la localización se basa en el país de la store seleccionado por el usuario, no en el idioma del dispositivo. | | **Price** | Para mostrar el precio en formato localizado, usa `product.price.localizedString`. Esta localización se basa en la configuración regional del dispositivo. También puedes acceder al precio como número mediante `product.price.amount`. El valor se proporcionará en la moneda local. Para obtener el símbolo de moneda correspondiente, usa `product.price.currencySymbol`. | | **Subscription Period** | Para mostrar el período (por ejemplo, semana, mes, año, etc.), usa `product.subscription?.localizedPeriod`. Esta localización se basa en la configuración regional del dispositivo. Para obtener el período de suscripción de forma programática, usa `product.subscription?.period`. Desde ahí puedes acceder al enum `unit` para obtener la duración (es decir, día, semana, mes, año o desconocido). El valor `numberOfUnits` te dará el número de unidades del período. Por ejemplo, para una suscripción trimestral verías `AdaptyPeriodUnit.month` en la propiedad unit y `3` en la propiedad numberOfUnits. | | **Introductory Offer** | Para mostrar un distintivo u otro indicador de que una suscripción incluye una oferta introductoria, consulta la propiedad `product.subscription?.offer?.phases`. Es una lista que puede contener hasta dos fases de descuento: la fase de prueba gratuita y la fase de precio introductorio. Dentro de cada objeto de fase encontrarás las siguientes propiedades útiles:opcional
predeterminado: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` representa el inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](flutter-localizations-and-locale-codes) para obtener más información sobre los códigos de idioma y cómo recomendamos utilizarlos.
| | **fetchPolicy** | predeterminado: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la aplicación y solo se borra cuando se reinstala la app o mediante una limpieza manual.
|Si la solicitud se ha completado correctamente, la respuesta contiene este objeto. Un objeto [AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html) proporciona información completa sobre los niveles de acceso, suscripciones y compras únicas de un usuario dentro de la app.
Comprueba el estado del nivel de acceso para determinar si el usuario tiene el acceso requerido a la app.
| :::warning **Nota:** si todavía usas una versión de StoreKit de Apple inferior a la v2.0 y una versión del SDK de Adapty inferior a la v2.9.0, debes proporcionar el [secreto compartido de Apple App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret) en su lugar. Apple ha deprecado este método. ::: ## Cambiar suscripción al realizar una compra \{#change-subscription-when-making-a-purchase\} Cuando un usuario elige una nueva suscripción en lugar de renovar la actual, el funcionamiento depende de la tienda: - En App Store, la suscripción se actualiza automáticamente dentro del grupo de suscripciones. Si un usuario compra una suscripción de un grupo mientras ya tiene activa una suscripción de otro grupo, ambas estarán activas al mismo tiempo. - En Google Play, la suscripción no se actualiza automáticamente. Tendrás que gestionar el cambio en el código de tu app, tal como se describe a continuación. Para reemplazar una suscripción por otra en Android, llama al método `.makePurchase()` con el parámetro adicional: ```dart showLineNumbers try { final subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters( 'OLD_PRODUCT_ID', AdaptyAndroidSubscriptionUpdateReplacementMode.immediateWithTimeProration, ); final result = await Adapty().makePurchase( product: product, parameters: AdaptyPurchaseParameters( subscriptionUpdateParams: subscriptionUpdateParams, ), ); // successful cross-grade } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } ``` Parámetro de solicitud adicional: | Parámetro | Presencia | Descripción | | :--------------------------- | :------- |:--------------------------------------------------------------------------------------------------------| | **parameters** | requerido | un objeto `AdaptyPurchaseParameters` con su campo `subscriptionUpdateParams` configurado como un objeto [`AdaptyAndroidSubscriptionUpdateParameters`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyAndroidSubscriptionUpdateParameters-class.html). | Puedes obtener más información sobre las suscripciones y los modos de reemplazo en la documentación de Google Developer: - [Acerca de los modos de reemplazo](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recomendaciones de Google para los modos de reemplazo](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Modo de reemplazo [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Nota: este método solo está disponible para actualizaciones de suscripción. No se admiten cambios a un plan inferior. - Modo de reemplazo [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Nota: el cambio de suscripción real solo se producirá cuando finalice el período de facturación actual. ## Canjear códigos de oferta en iOS \{#redeem-offer-codes-in-ios\}Un objeto [`AdaptyProfile`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html). Este modelo contiene información sobre niveles de acceso, suscripciones y compras únicas.
Comprueba el **estado del nivel de acceso** para determinar si el usuario tiene acceso a la app.
| :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: --- # File: implement-observer-mode-flutter --- --- title: "Implementar el modo Observer en Flutter SDK" description: "Implementa el modo Observer en Adapty para rastrear eventos de suscripción de usuarios en Flutter SDK." --- Si ya tienes tu propia infraestructura de compras y no estás listo para migrar completamente a Adapty, puedes explorar el [Modo observador](observer-vs-full-mode). En su forma básica, el Modo observador ofrece análisis avanzados e integración fluida con sistemas de atribución y análisis. Si esto se ajusta a tus necesidades, solo tienes que: 1. Activarlo al configurar el SDK estableciendo el parámetro `observerMode` en `true`. Sigue las instrucciones de configuración para [Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk). 2. [Informar las transacciones](report-transactions-observer-mode-flutter) desde tu infraestructura de compras existente a Adapty. ## Configuración del modo Observer \{#observer-mode-setup\} Activa el modo Observer si gestionas las compras y el estado de las suscripciones por tu cuenta y usas Adapty para enviar eventos de suscripción y analíticas. :::important Cuando se ejecuta en modo Observer, el SDK de Adapty no cerrará ninguna transacción, así que asegúrate de gestionarlas tú mismo. ::: ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withObserverMode(true) // Enable observer mode ..withLogLevel(AdaptyLogLevel.verbose), ); ``` Parámetros: | Parámetro | Descripción | | --------------------------- | ------------------------------------------------------------ | | observerMode | Un valor booleano que controla el [modo Observer](observer-vs-full-mode). El valor predeterminado es `false`. | ## Uso de los paywalls de Adapty en el modo Observer \{#using-adapty-paywalls-in-observer-mode\} Si también quieres usar los paywalls y las funciones de pruebas A/B de Adapty, puedes hacerlo, aunque requiere algo de configuración adicional en el modo Observer. Esto es lo que necesitas hacer además de los pasos anteriores: 1. Muestra los paywalls como de costumbre para los [paywalls de Remote Config](present-remote-config-paywalls-flutter). 3. [Asocia los paywalls](report-transactions-observer-mode-flutter) con las transacciones de compra. :::tip En el SDK v4, también puedes presentar flows y paywalls renderizados por Adapty en modo Observer: registra un `AdaptyUIObserverModeResolver` para realizar la compra o restauración con tu propio código cuando el usuario pulse el botón correspondiente. Consulta [Presentar flows en modo Observer](flutter-present-flows-in-observer-mode). ::: --- # File: report-transactions-observer-mode-flutter --- --- title: "Reportar transacciones en Observer Mode en Flutter SDK" description: "Reporta transacciones de compra en el Observer Mode de Adapty para obtener información sobre usuarios y seguimiento de ingresos en Flutter SDK." ---phoneNumber
firstName
lastName
| String | | gender | Enum, los valores permitidos son: `female`, `male`, `other` | | birthday | Date | ### Atributos de usuario personalizados \{#custom-user-attributes\} Puedes definir tus propios atributos personalizados, normalmente relacionados con el uso de tu app. Por ejemplo, en apps de fitness podrían ser el número de ejercicios por semana; en apps de aprendizaje de idiomas, el nivel de conocimiento del usuario, etc. Puedes usarlos en segmentos para crear paywalls y ofertas dirigidas, y también en análisis para descubrir qué métricas de producto influyen más en los ingresos. ```dart showLineNumbers try { final builder = AdaptyProfileParametersBuilder() ..setCustomStringAttribute('value1', 'key1') ..setCustomDoubleAttribute(1.0, 'key2'); await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` Para eliminar una clave existente, usa el método `.withRemoved(customAttributeForKey:)`: ```dart showLineNumbers try { final builder = AdaptyProfileParametersBuilder() ..removeCustomAttribute('key1') ..removeCustomAttribute('key2'); await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` A veces necesitas saber qué atributos personalizados ya se han instalado. Para ello, usa el campo `customAttributes` del objeto `AdaptyProfile`. :::warning Ten en cuenta que el valor de `customAttributes` puede estar desactualizado, ya que los atributos del usuario pueden enviarse desde distintos dispositivos en cualquier momento, por lo que los atributos en el servidor podrían haber cambiado desde la última sincronización. ::: ### Límites \{#limits\} - Hasta 30 atributos personalizados por usuario - Los nombres de clave pueden tener hasta 30 caracteres. El nombre de la clave puede incluir caracteres alfanuméricos y cualquiera de los siguientes: `_` `-` `.` - El valor puede ser una cadena de texto o un número decimal con un máximo de 50 caracteres. --- # File: flutter-listen-subscription-changes --- --- title: "Verificar el estado de la suscripción en el SDK de Flutter" description: "Consulta y gestiona el estado de la suscripción de los usuarios en Adapty para mejorar la retención de clientes en tu app de Flutter." --- Con Adapty, hacer seguimiento del estado de la suscripción es muy sencillo. No tienes que insertar manualmente los IDs de producto en tu código. En su lugar, puedes confirmar el estado de suscripción de un usuario fácilmente comprobando si tiene un [nivel de acceso](access-level) activo.Un objeto [AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html). En general, solo tienes que comprobar el estado del nivel de acceso del perfil para determinar si el usuario tiene acceso premium a la app.
El método `.getProfile` proporciona el resultado más actualizado, ya que siempre intenta consultar la API. Si por algún motivo (por ejemplo, sin conexión a internet), el SDK de Adapty no puede obtener información del servidor, se devolverán los datos de la caché. También es importante tener en cuenta que el SDK de Adapty actualiza la caché de `AdaptyProfile` de forma periódica para mantener esta información lo más actualizada posible.
| El método `.getProfile()` te proporciona el perfil del usuario a partir del cual puedes obtener el estado del nivel de acceso. Puedes tener múltiples niveles de acceso por app. Por ejemplo, si tienes una app de noticias y vendes suscripciones a diferentes temáticas de forma independiente, puedes crear niveles de acceso "sports" y "science". Pero en la mayoría de los casos solo necesitarás un nivel de acceso; en ese caso, puedes usar simplemente el nivel de acceso predeterminado "premium". A continuación se muestra un ejemplo para verificar el nivel de acceso predeterminado "premium": ```dart showLineNumbers try { final profile = await Adapty().getProfile(); if (profile?.accessLevels['premium']?.isActive ?? false) { // grant access to premium features } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ### Escuchar actualizaciones del estado de suscripción \{#listening-for-subscription-status-updates\} Cada vez que cambia la suscripción del usuario, Adapty lanza un evento. Para recibir mensajes de Adapty, necesitas realizar una configuración adicional: ```dart showLineNumbers Adapty().didUpdateProfileStream.listen((profile) { // handle any changes to subscription state }); ``` Adapty también lanza un evento al iniciar la aplicación. En ese caso, se pasará el estado de suscripción almacenado en caché. ### Caché del estado de suscripción \{#subscription-status-cache\} La caché implementada en el SDK de Adapty almacena el estado de suscripción del perfil. Esto significa que, aunque el servidor no esté disponible, se puede acceder a los datos en caché para obtener información sobre el estado de suscripción del perfil. Sin embargo, es importante tener en cuenta que no es posible realizar solicitudes de datos directamente desde la caché. El SDK consulta el servidor periódicamente cada minuto para comprobar si hay actualizaciones o cambios relacionados con el perfil. Si hay modificaciones, como nuevas transacciones u otras actualizaciones, se enviarán a los datos en caché para mantenerlos sincronizados con el servidor. --- # File: flutter-deal-with-att --- --- title: "Gestionar ATT en Flutter SDK" description: "Empieza con Adapty en Flutter para simplificar la configuración y gestión de suscripciones." --- Si tu aplicación utiliza el framework AppTrackingTransparency y muestra al usuario una solicitud de autorización de seguimiento, debes enviar el [estado de autorización](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) a Adapty. ```dart showLineNumbers final builder = AdaptyProfileParametersBuilder() ..setAppTrackingTransparencyStatus(AdaptyIOSAppTrackingTransparencyStatus.authorized); try { await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle unknown error } ``` :::warning Recomendamos encarecidamente que envíes este valor lo antes posible cuando cambie; solo así los datos se transmitirán a tiempo a las integraciones que hayas configurado. ::: --- # File: kids-mode-flutter --- --- title: "Modo Kids en Flutter SDK" description: "Activa fácilmente el Modo Kids para cumplir con las políticas de Apple y Google. Sin recopilación de IDFA, GAID ni datos de publicidad en Flutter SDK." --- Si tu aplicación Flutter está destinada a niños, debes seguir las políticas de [Apple](https://developer.apple.com/kids/) y [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si usas el SDK de Adapty, unos pocos pasos sencillos te ayudarán a configurarlo para cumplir con estas políticas y superar las revisiones de las tiendas. ## ¿Qué se requiere? \{#whats-required\} Debes configurar el SDK para deshabilitar la recopilación de: - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) (iOS) - [Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) (Android) - [Dirección IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) Además, te recomendamos usar el customer user ID con cuidado. Un ID de usuario en formato `opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché de actualización periódica descrita anteriormente y los onboardings de respaldo. También usamos CDN para cargar los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus onboardings, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede agotar el tiempo ligeramente después de lo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes peticiones internamente.
| ## Parámetros de respuesta \{#response-parameters\} | Parámetro | Descripción | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objeto [`AdaptyOnboarding`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyOnboarding-class.html) con: el identificador y la configuración del onboarding, el Remote Config y otras propiedades. | ## Acelera la obtención del onboarding con el onboarding de audiencia predeterminada \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Normalmente, los onboardings se obtienen casi de forma instantánea, por lo que no necesitas preocuparte por optimizar este proceso. Sin embargo, cuando tienes numerosas audiencias y onboardings, y tus usuarios tienen una conexión a internet débil, obtener un onboarding puede tardar más de lo deseable. En esos casos, puede que quieras mostrar un onboarding predeterminado para garantizar una experiencia de usuario fluida en lugar de no mostrar ningún onboarding. Para solucionar esto, puedes usar el método `getOnboardingForDefaultAudience`, que obtiene el onboarding del placement especificado para la audiencia **All Users**. Sin embargo, es importante entender que el enfoque recomendado es obtener el onboarding mediante el método `getOnboarding`, tal como se detalla en la sección [Obtener el onboarding](#fetch-onboarding) anterior. :::warning Considera usar `getOnboarding` en lugar de `getOnboardingForDefaultAudience`, ya que este último tiene limitaciones importantes: - **Problemas de compatibilidad**: Puede ocasionar problemas al dar soporte a múltiples versiones de la app, lo que requiere diseños retrocompatibles o asumir que las versiones antiguas podrían mostrarse incorrectamente. - **Sin personalización**: Solo muestra contenido para la audiencia "All Users", eliminando la segmentación por país, atribución o atributos personalizados. Si la mayor velocidad de carga compensa estos inconvenientes para tu caso de uso, utiliza `getOnboardingForDefaultAudience` como se muestra a continuación. De lo contrario, usa `getOnboarding` tal como se describe [anteriormente](#fetch-onboarding). ::: ```dart showLineNumbers try { final onboarding = await Adapty().getOnboardingForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` Parámetros: | Parámetro | Presencia | Descripción | |-----------------|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En ese caso, puede que los usuarios no reciban los datos más recientes, pero tendrán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la app y solo se borra cuando se desinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché de actualización periódica descrita anteriormente y los onboardings de respaldo. También utilizamos CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus onboardings, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| --- # File: flutter-present-onboardings --- --- title: "Presentar onboardings en el SDK de Flutter" description: "Aprende cómo presentar onboardings de forma efectiva para aumentar las conversiones." --- :::warning **Los onboardings están obsoletos en el SDK v4 y se eliminarán en una versión futura.** Ya no reciben correcciones ni mejoras. Usa [flows](flutter-get-pb-paywalls) en su lugar: a diferencia de los onboardings, que se ejecutan dentro de un WebView, los flows se renderizan de forma nativa en el dispositivo, lo que ofrece animaciones más fluidas, una apariencia nativa consistente, tiempos de carga más rápidos y sin dependencia del runtime de WebView. Consulta [Obtener flows y paywalls](flutter-get-pb-paywalls) y [Mostrar flows y paywalls](flutter-present-paywalls) para empezar. ::: Si has personalizado un onboarding con el builder, no necesitas preocuparte por renderizarlo en el código de tu app Flutter para mostrárselo al usuario. Ese onboarding contiene tanto lo que debe mostrarse como la forma en que debe mostrarse. Antes de empezar, asegúrate de que: 1. Has instalado [Adapty Flutter SDK](sdk-installation-flutter) 3.8.0 o posterior. 2. Has [creado un onboarding](create-onboarding). 3. Has añadido el onboarding a un [placement](placements). El SDK de Adapty para Flutter ofrece dos formas de presentar onboardings: - **Pantalla independiente** - **Widget embebido** ## Mostrar como pantalla independiente \{#present-as-standalone-screen\} Para mostrar un onboarding como pantalla independiente, usa el método `onboardingView.present()` en el `onboardingView` creado por el método `createOnboardingView`. Cada `view` solo puede usarse una vez. Si necesitas mostrar el onboarding de nuevo, llama a `createOnboardingView` otra vez para crear una nueva instancia de `onboardingView`. :::warning Reutilizar el mismo `onboardingView` sin recrearlo puede provocar un error `AdaptyUIError.viewAlreadyPresented`. ::: ```dart showLineNumbers title="Flutter" try { await onboardingView.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### Cerrar el onboarding \{#dismiss-the-onboarding\} Cuando necesites cerrar el onboarding por código, usa el método `dismiss()`: ```dart showLineNumbers title="Flutter" try { await onboardingView.dismiss(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### Configurar el estilo de presentación en iOS \{#configure-ios-presentation-style\} Configura cómo se presenta el onboarding en iOS pasando el parámetro `iosPresentationStyle` al método `present()`. El parámetro acepta los valores `AdaptyUIIOSPresentationStyle.fullScreen` (predeterminado) o `AdaptyUIIOSPresentationStyle.pageSheet`. ```dart showLineNumbers try { await onboardingView.present(iosPresentationStyle: AdaptyUIIOSPresentationStyle.pageSheet); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ## Integrar en la jerarquía de widgets \{#embed-in-widget-hierarchy\} Para integrar un onboarding dentro de tu árbol de widgets existente, usa el widget `AdaptyUIOnboardingPlatformView` directamente en tu jerarquía de widgets de Flutter. ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, // The onboarding object you fetched onDidFinishLoading: (meta) { }, onDidFailWithError: (error) { }, onCloseAction: (meta, actionId) { }, onPaywallAction: (meta, actionId) { }, onCustomAction: (meta, actionId) { }, onStateUpdatedAction: (meta, elementId, params) { }, onAnalyticsEvent: (meta, event) { }, ) ``` :::note Para que la platform view de Android funcione, asegúrate de que tu `MainActivity` extienda `FlutterFragmentActivity`: ```kotlin showLineNumbers title="Kotlin" class MainActivity : FlutterFragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } } ``` ::: ## Cargador durante el onboarding \{#loader-during-onboarding\} Al presentar un onboarding, puede que notes una breve pantalla de carga entre tu pantalla de presentación y el onboarding mientras se inicializa la vista subyacente. Puedes gestionar esto de distintas formas según tus necesidades. #### Controla la pantalla de presentación con onDidFinishLoading \{#control-splash-screen-using-ondidfinishloading\} :::note Este enfoque solo está disponible al incrustar el onboarding como widget. No está disponible para la presentación en pantalla independiente. ::: El enfoque multiplataforma recomendado es mantener visible la pantalla de carga o superposición personalizada hasta que el onboarding esté completamente cargado, y luego ocultarla manualmente. Al usar el widget embebido, superpón tu propio widget sobre él y ocúltalo cuando se dispare `onDidFinishLoading`: ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, onDidFinishLoading: (meta) { // Hide your custom splash screen or overlay here }, // ... other callbacks ) ``` ### Personalizar el loader nativo \{#customize-native-loader\} :::important Este enfoque es específico de plataforma y requiere mantener código de UI nativo. No se recomienda a menos que ya mantengas capas nativas separadas en tu app. ::: Si necesitas personalizar el loader predeterminado, puedes reemplazarlo con layouts específicos de cada plataforma. Este enfoque requiere implementaciones separadas para Android e iOS: - **iOS**: Añade `AdaptyOnboardingPlaceholderView.xib` a tu proyecto de Xcode - **Android**: Crea `adapty_onboarding_placeholder_view.xml` en `res/layout` y define ahí un placeholder ## Personalizar cómo se abren los enlaces en los onboardings \{#customize-how-links-open-in-onboardings\} :::important La personalización de cómo se abren los enlaces en los onboardings es compatible a partir de Adapty SDK v3.15.1. ::: Por defecto, los enlaces en los onboardings se abren en un navegador integrado en la app. Esto ofrece una experiencia fluida al mostrar las páginas web dentro de tu aplicación, sin que el usuario tenga que cambiar de app. Si prefieres abrir los enlaces en un navegador externo, puedes personalizar este comportamiento estableciendo el parámetro `externalUrlsPresentation` en `AdaptyWebPresentation.externalBrowser`:
Luego, puedes usar este ID en tu código y gestionarlo como una acción personalizada. Por ejemplo, si el usuario pulsa un botón personalizado, como **Login** o **Allow notifications**, se activará el método delegado `onboardingController` con el caso `.custom(id:)` y el parámetro `actionId` corresponderá al **Action ID** definido en el builder. Puedes crear tus propios IDs, como "allowNotifications".
```dart
// Full-screen presentation
void onboardingViewOnCustomAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String actionId,
) {
switch (actionId) {
case 'login':
_login();
break;
case 'allow_notifications':
_allowNotifications();
break;
}
}
// Embedded widget
onCustomAction: (meta, actionId) {
_handleCustomAction(actionId);
}
```
:::important
Ten en cuenta que debes gestionar qué ocurre cuando el usuario cierra el onboarding. Por ejemplo, debes dejar de mostrar el propio onboarding.
:::
```dart showLineNumbers title="Flutter"
// Full-screen presentation
void onboardingViewOnCloseAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
String actionId,
) {
await view.dismiss();
}
// Embedded widget
onCloseAction: (meta, actionId) {
Navigator.of(context).pop();
}
```
2. Haz clic en el nombre del grupo de suscripciones. Verás tus productos listados en la sección **Subscriptions**.
3. Asegúrate de que el producto que estás probando esté marcado como **Ready to Submit**.
4. Compara el ID del producto de la tabla con el que aparece en la pestaña [**Products**](https://app.adapty.io/products) del Adapty Dashboard. Si los IDs no coinciden, copia el ID del producto de la tabla y [crea un producto](create-product) con ese ID en el Adapty Dashboard.
## Paso 3. Comprueba la disponibilidad del producto \{#step-4-check-product-availability\}
1. Vuelve a **App Store Connect** y abre la misma sección **Subscriptions**.
2. Haz clic en el nombre del grupo de suscripciones para ver tus productos.
3. Selecciona el producto que estás probando.
4. Desplázate hasta la sección **Availability** y comprueba que todos los países y regiones requeridos estén listados.
## Paso 4. Comprueba los precios del producto \{#step-5-check-product-prices\}
1. De nuevo, ve a la sección **Monetization** → **Subscriptions** en **App Store Connect**.
2. Haz clic en el nombre del grupo de suscripciones.
3. Selecciona el producto que estás probando.
4. Desplázate hacia abajo hasta **Subscription Pricing** y despliega la sección **Current Pricing for New Subscribers**.
5. Asegúrate de que todos los precios requeridos estén listados.
## Paso 5. Comprueba que el estado de pago de la app, la cuenta bancaria y los formularios fiscales estén activos \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\}
1. En la página de inicio de [**App Store Connect**](https://appstoreconnect.apple.com/), haz clic en **Business**.
2. Selecciona el nombre de tu empresa.
3. Desplázate hacia abajo y comprueba que tu **Paid Apps Agreement**, tu **Bank Account** y tus **Tax forms** aparezcan como **Active**.
Siguiendo estos pasos, deberías poder resolver la advertencia `InvalidProductIdentifiers` y tener tus productos disponibles en la store.
## Paso 6. Recrea el producto si está bloqueado \{#step-6-recreate-the-product-if-its-stuck\}
Es posible que los pasos 1–5 pasen todos correctamente —estado `Approved`, Bundle ID coincidente, API key válida— y aun así el SDK devuelva `1000 noProductIDsFound`. En ese caso, puede que el producto esté bloqueado en el registro de Apple. El registro de productos de Apple entra ocasionalmente en un estado en el que un producto existe en la interfaz de App Store Connect pero no está expuesto en la ruta de búsqueda de StoreKit.
Elimina el producto en App Store Connect y vuelve a crearlo con el mismo ID de producto. Espera hasta 24 horas tras la recreación para que los cambios se propaguen.
---
# File: cantMakePayments-flutter
---
---
title: "Solución al error Code-1003 cantMakePayment en Flutter SDK"
description: "Resuelve el error de realización de pagos al gestionar suscripciones en Adapty."
---
El error 1003, `cantMakePayments`, indica que no es posible realizar compras in-app en este dispositivo.
Si encuentras el error `cantMakePayments`, normalmente se debe a una de estas razones:
- Restricciones del dispositivo: El error no está relacionado con Adapty. Consulta las soluciones más abajo.
- Configuración del modo Observer: El método `makePurchase` y el modo Observer no pueden usarse al mismo tiempo. Consulta la sección más abajo.
## Problema: Restricciones del dispositivo \{#issue-device-restrictions\}
| Problema | Solución |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| Restricciones de Screen Time | Desactiva las restricciones de compras in-app en [Screen Time](https://support.apple.com/en-us/102470) |
| Cuenta suspendida | Contacta con el soporte de Apple para resolver problemas con la cuenta |
| Restricciones regionales | Usa una cuenta de App Store de una región compatible |
## Problema: Usar el modo Observer y makePurchase a la vez \{#issue-using-both-observer-mode-and-makepurchase\}
Si usas `makePurchases` para gestionar las compras, no necesitas el modo Observer. El [modo Observer](observer-vs-full-mode) solo es necesario si implementas la lógica de compra tú mismo.
Por lo tanto, si usas `makePurchase`, puedes eliminar sin problema la activación del modo Observer del código de inicialización del SDK.
---
# File: migration-to-flutter-sdk-v4
---
---
title: "Migrar Adapty Flutter SDK a v. 4.0"
description: "Migra al Adapty Flutter SDK v4.0 reemplazando las APIs de paywall con APIs de flow, compatibles tanto con Flow Builder como con Paywall Builder."
---
Adapty Flutter SDK 4.0 introduce flows y renombra las APIs de paywall en consecuencia. Las nuevas APIs funcionan tanto con el nuevo Flow Builder como con el Paywall Builder existente — no se requieren cambios de configuración en el Adapty Dashboard.
## Referencia rápida \{#quick-reference\}
| v3 | v4 |
|---|---|
| `Adapty().getPaywall(placementId: id)` | `Adapty().getFlow(placementId: id)` |
| `Adapty().getPaywallForDefaultAudience(placementId: id)` | `Adapty().getFlowForDefaultAudience(placementId: id)` |
| `Adapty().getPaywallProducts(paywall: paywall)` | `Adapty().getPaywallProducts(flow: flow)` |
| `Adapty().logShowPaywall(paywall: paywall)` | `Adapty().logShowFlow(flow: flow)` |
| `AdaptyPaywall` (tipo) | `AdaptyFlow` |
| `AdaptyPaywallFetchPolicy` (tipo) | `AdaptyFlowFetchPolicy` |
| `AdaptyUI().createPaywallView(paywall: paywall)` | `AdaptyUI().createFlowView(flow: flow)` |
| `AdaptyUIPaywallView` (tipo) | `AdaptyUIFlowView` |
| `AdaptyUIPaywallPlatformView` (widget) | `AdaptyUIFlowPlatformView` |
| `AdaptyUI().presentPaywallView(view)` / `dismissPaywallView(view)` | `AdaptyUI().presentFlowView(view)` / `dismissFlowView(view)` |
| `AdaptyUIPaywallsEventsObserver` | `AdaptyUIFlowsEventsObserver` |
| `AdaptyUI().setPaywallsEventsObserver(observer)` | `AdaptyUI().setFlowsEventsObserver(observer)` |
| callbacks `paywallViewDid*` | callbacks `flowViewDid*` |
| `paywallViewDidFailRendering` | `flowViewDidReceiveError` |
`AdaptyPaywallProduct` mantiene su nombre — los productos siguen perteneciendo a un flow, y `getPaywallProducts` ahora recibe un `AdaptyFlow`. Ya no se pasa un `locale` al recuperar un flow. Las APIs de compra y perfil (`makePurchase`, `restorePurchases`, `getProfile`, `identify`, etc.) no han cambiado, y tampoco los métodos de vista `present`, `dismiss` y `showDialog`. Algunos comportamientos por defecto han cambiado — consulta [Cambios en el comportamiento por defecto](#default-behavior-changes).
## Versiones mínimas \{#minimum-versions\}
El SDK de Adapty para Flutter 4.0 eleva los requisitos mínimos:
- **iOS 15.0** — el objetivo de despliegue mínimo para iOS, aumentado desde iOS 13.0.
- **Xcode 26** o superior — el SDK nativo de iOS usa Swift tools 6.2.
- **Flutter 3.32.0** (Dart 3.8.0) o superior.
## Instalación \{#installation\}
### Actualizar el paquete \{#update-the-package\}
El paquete que instales depende de si tu app usa el Modo Infantil.
Para la mayoría de las apps, actualiza `adapty_flutter` a la v4.0 en tu `pubspec.yaml`:
```yaml showLineNumbers title="pubspec.yaml"
dependencies:
adapty_flutter: 4.0.0
```
Si tu app usa el Modo Infantil, especifica `adapty_flutter_kids` en su lugar:
```yaml showLineNumbers title="pubspec.yaml"
dependencies:
adapty_flutter_kids: 4.0.0
```
Este paquete **autónomo** elimina el código de IDFA y seguimiento de anuncios para cumplir con los requisitos del App Store. Actualiza la ruta de importación de Dart a `package:adapty_flutter_kids/adapty_flutter.dart`. Por lo demás, la migración es exactamente igual que la del paquete normal.
El modo Kids también requiere que desactives la recopilación de direcciones IP en el Adapty Dashboard — consulta [Kids Mode](kids-mode-flutter) para ver la configuración completa.
### iOS: los SDKs nativos ahora se distribuyen a través de Swift Package Manager
[El repositorio de specs de CocoaPods pasará a ser de solo lectura en diciembre de 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/), por lo que a partir de la v4 el SDK nativo de iOS **ya no se distribuye a través de CocoaPods** — el plugin lo obtiene únicamente a través de **Swift Package Manager**.
Si usas Flutter 3.32–3.43, activa el soporte de Swift Package Manager una sola vez:
```bash
flutter config --enable-swift-package-manager
```
Flutter 3.44 y versiones posteriores activan Swift Package Manager por defecto, así que no es necesario hacer nada en ese caso.
## Obtener flows \{#fetching-flows\}
### getPaywall → getFlow
El tipo devuelto cambia de `AdaptyPaywall` a `AdaptyFlow`, y ya no se pasa un `locale` — cuando renderizas un flow, la localización se resuelve automáticamente; para paywalls personalizados, todos los idiomas configurados se devuelven en `flow.remoteConfigs`:
```diff showLineNumbers
- final paywall = await Adapty().getPaywall(placementId: 'YOUR_PLACEMENT_ID', locale: 'en');
+ final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID');
```
`getPaywallForDefaultAudience` se renombra de la misma manera:
```diff showLineNumbers
- final paywall = await Adapty().getPaywallForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID', locale: 'en');
+ final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID');
```
El tipo de política de obtención cambia su nombre de `AdaptyPaywallFetchPolicy` a `AdaptyFlowFetchPolicy`; sus opciones (`reloadRevalidatingCacheData`, `returnCacheDataElseLoad`, `returnCacheDataIfNotExpiredElseLoad`) no cambian.
### getPaywallProducts(paywall) → getPaywallProducts(flow)
`getPaywallProducts` mantiene su nombre pero ahora recibe un `AdaptyFlow` mediante el parámetro `flow`:
```diff showLineNumbers
- final products = await Adapty().getPaywallProducts(paywall: paywall);
+ final products = await Adapty().getPaywallProducts(flow: flow);
```
## Modelo de datos \{#data-model\}
`getFlow` devuelve un `AdaptyFlow` en lugar de un `AdaptyPaywall`, y la estructura del objeto ha cambiado:
| Miembro de `AdaptyPaywall` v3 | Miembro de `AdaptyFlow` v4 | Acción |
|---|---|---|
| `remoteConfig` (único, nullable) | `remoteConfigs` (lista) | Un flow lleva un Remote Config por idioma configurado. El getter `remoteConfig` sigue existiendo y devuelve la primera entrada; para seleccionar un idioma concreto, busca en `remoteConfigs` por su `locale`. |
| `productIdentifiers` | `productIdentifiers` | Se conserva, pero ahora se recopila en todas las variaciones de paywall del flow. Los identificadores por variación están en `flow.paywalls[i].productIdentifiers`. |
| `hasViewConfiguration` | `hasViewConfiguration` | Sin cambios. |
| `placementId` (obsoleto) | eliminado | Usa `flow.placement.id`. |
| `revision` (obsoleto) | eliminado | Usa `flow.placement.revision`. |
| `vendorProductIds` (obsoleto) | eliminado | Usa `productIdentifiers`. |
| _(nuevo)_ | `paywalls` (lista de `AdaptyFlowPaywall`) | Cada entrada es una variación de paywall en el flow, con su propio `name`, `variationId` y `productIdentifiers`. |
`AdaptyPaywallViewConfiguration` ya no está expuesto — la configuración de la vista ahora es opaca. Elimina cualquier referencia a este tipo.
## Métodos de paywall web \{#web-paywall-methods\}
`openWebPaywall` y `createWebPaywallUrl` mantienen sus nombres, pero el parámetro `paywall` ahora recibe un `AdaptyFlowPaywall` (una variante de flow) en lugar de un `AdaptyPaywall`. También puedes seguir pasando un `AdaptyPaywallProduct`.
```diff showLineNumbers
final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID');
- await Adapty().openWebPaywall(paywall: paywall);
+ if (flow.paywalls.isNotEmpty) {
+ await Adapty().openWebPaywall(paywall: flow.paywalls[0]);
+ }
```
## Seguimiento de vistas de flows \{#tracking-flow-views\}
### logShowPaywall → logShowFlow
`logShowPaywall` ha pasado a llamarse `logShowFlow` y ahora recibe un `AdaptyFlow`. El evento sigue registrándose contra la misma variación, por lo que las métricas de embudo y prueba A/B existentes siguen funcionando sin cambios en el dashboard.
```diff showLineNumbers
- await Adapty().logShowPaywall(paywall: paywall);
+ await Adapty().logShowFlow(flow: flow);
```
Al igual que en v3, no es necesario llamar a este método cuando se muestran flows o paywalls renderizados por el [Flow Builder](adapty-flow-builder) o el [Paywall Builder](adapty-paywall-builder) — Adapty registra esas vistas automáticamente.
## Mostrar flows \{#displaying-flows\}
### createPaywallView → createFlowView
Renombra el método y pasa el `AdaptyFlow` mediante el parámetro `flow`. El resto de parámetros (`loadTimeout`, `preloadProducts`, `customTags`, `customTimers`, `customAssets`, `productPurchaseParams`) no cambian, ni tampoco los métodos de la vista `present`, `dismiss` y `showDialog`:
```diff showLineNumbers
- final view = await AdaptyUI().createPaywallView(paywall: paywall);
+ final view = await AdaptyUI().createFlowView(flow: flow);
await view.present();
```
### AdaptyUIPaywallView → AdaptyUIFlowView
El tipo de vista ha sido renombrado. Su propiedad `paywallVariationId` (obsoleta) ha sido eliminada — usa `variationId` en su lugar:
```diff showLineNumbers
- void flowViewDidAppear(AdaptyUIPaywallView view) {
+ void flowViewDidAppear(AdaptyUIFlowView view) {
```
### AdaptyUIPaywallPlatformView → AdaptyUIFlowPlatformView
Si incrustas la vista como un widget en tu árbol de widgets, renómbrala y pasa el parámetro `flow`. Los callbacks de eventos (`onDidAppear`, `onDidFinishPurchase`, etc.) conservan sus nombres:
```diff showLineNumbers
- AdaptyUIPaywallPlatformView(
- paywall: paywall,
+ AdaptyUIFlowPlatformView(
+ flow: flow,
onDidFinishPurchase: (view, product, purchaseResult) { /* … */ },
)
```
:::note
Una vista de flow creada con `createFlowView` es de un solo uso: tras llamar a `dismiss()`, la vista se libera de la memoria y no se puede volver a mostrar — llama a `createFlowView` de nuevo para presentar el flow otra vez.
:::
## Manejo de eventos \{#handling-events\}
La clase de observador se renombra de `AdaptyUIPaywallsEventsObserver` a `AdaptyUIFlowsEventsObserver`, su método de registro de `setPaywallsEventsObserver` a `setFlowsEventsObserver`, y todos los callbacks `paywallViewDid*` pasan a llamarse `flowViewDid*`:
```diff showLineNumbers
- class MyObserver extends AdaptyUIPaywallsEventsObserver {
+ class MyObserver extends AdaptyUIFlowsEventsObserver {
@override
- void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) {
+ void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) {
// …
}
}
- AdaptyUI().setPaywallsEventsObserver(this);
+ AdaptyUI().setFlowsEventsObserver(this);
```
Ahora hay tres callbacks **obligatorios** — tu observer no compilará sin ellos:
- **`flowViewDidFinishPurchase`**: Era opcional en v3, donde el comportamiento por defecto era cerrar la vista tras una compra. Ahora decides qué ocurre: continuar el flow o llamar a `view.dismiss()`.
- **`flowViewDidFinishRestore`**: Obligatorio, igual que en v3.
- **`flowViewDidReceiveError`**: Reemplaza a `paywallViewDidFailRendering` y ahora también recibe otros errores de la vista.
Dos cambios menores:
- `setFlowsEventsObserver` (y `setOnboardingsEventsObserver`) ahora aceptan `null` para desasociar un observador previamente configurado, por lo que el SDK ya no lo retiene.
- El nuevo callback opcional `flowViewDidReceiveAnalyticEvent` está reservado para eventos analíticos personalizados de un flow. Los flows aún no emiten estos eventos a tu código, por lo que no necesitas implementarlo.
La v4 también añade funcionalidades opcionales a las que puedes suscribirte:
- `AdaptyUI().setObserverModeResolver(...)` con un `AdaptyUIObserverModeResolver` — gestiona las compras y restauraciones iniciadas desde flows cuando el SDK funciona en [modo Observer](implement-observer-mode-flutter). Anteriormente, esto solo estaba disponible en los SDKs nativos de iOS y Android. Consulta [Presentar flows en modo Observer](flutter-present-flows-in-observer-mode).
- `AdaptyUI().setSystemRequestsHandler(...)` con un `AdaptyUISystemRequestsHandler` — reservado para solicitudes del sistema desde un flow (permisos del SO y solicitudes de valoración en el App Store). Los flows aún no activan estas solicitudes, por lo que no es necesario registrar un handler.
## APIs eliminadas \{#removed-apis\}
Estos símbolos fueron declarados obsoletos en la versión 3.x y se eliminan en la v4:
### setFallbackPaywalls → setFallback
```diff showLineNumbers
- await Adapty().setFallbackPaywalls(assetId);
+ await Adapty().setFallback(assetId);
```
### withIdfaCollectionDisabled → withAppleIdfaCollectionDisabled
```diff showLineNumbers
configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY')
- ..withIdfaCollectionDisabled(true),
+ ..withAppleIdfaCollectionDisabled(true),
```
### Otros miembros eliminados
- **`AdaptyPurchaseResultSuccess.jwsTransaction`**: Usa `appleJwsTransaction`.
- **`AdaptyUIFlowView.paywallVariationId`**: Usa `variationId`.
- **`AdaptyUIObserver` y `AdaptyUI().setObserver(...)`**: Usa `AdaptyUIFlowsEventsObserver` y `setFlowsEventsObserver(...)`.
## Cambios en el comportamiento predeterminado \{#default-behavior-changes\}
Estos cambios no causan errores de compilación, así que pruébalos en tiempo de ejecución:
- **Compra exitosa**: En v3, el comportamiento predeterminado de `paywallViewDidFinishPurchase` cerraba la vista. En v4, `flowViewDidFinishPurchase` es obligatorio y no tiene comportamiento predeterminado — cierra la vista tú mismo si eso es lo que quieres.
- **Botón Atrás del sistema Android**: Ya no cierra un flow de forma predeterminada. La acción se entrega a `flowViewDidPerformAction` como `AndroidSystemBackAction` — gestiónala ahí si quieres que el botón Atrás cierre el flow.
- **Apertura de URLs**: El comportamiento predeterminado de `flowViewDidPerformAction` ahora gestiona `OpenUrlAction` abriendo la URL de forma nativa (respetando la configuración de navegador interno o externo del dashboard), además de cerrar la vista con `CloseAction`. Sobreescribe el callback para gestionar las URLs tú mismo.
- **Errores de vista**: `flowViewDidReceiveError` es obligatorio, y el cierre depende de tu implementación. Si tu integración de v3 dependía del cierre automático de la vista al producirse errores de renderizado, llama a `view.dismiss()` en este callback.
- **Ciclo de vida de la vista**: Cerrar una vista de flow u onboarding la libera de la memoria. Una vista cerrada no puede volver a mostrarse — crea una nueva en su lugar.
## Obsolescencia de la API de onboarding \{#onboarding-api-deprecation\}
La API de onboarding heredada está obsoleta en v4.0 en favor del [Flow Builder](adapty-flow-builder). Sigue funcionando, y tu IDE marca los símbolos obsoletos mediante sus anotaciones `@Deprecated` — no hay advertencias en tiempo de ejecución. Estos símbolos se eliminarán en una versión futura, así que planifica la migración de tus onboardings al Flow Builder.
Símbolos obsoletos: `getOnboarding`, `getOnboardingForDefaultAudience`, `createOnboardingView`, `presentOnboardingView`, `dismissOnboardingView`, `setOnboardingsEventsObserver`, `AdaptyOnboarding`, `AdaptyUIOnboardingView`, `AdaptyUIOnboardingPlatformView`, `AdaptyUIOnboardingsEventsObserver`, y los modelos de estado, entrada y analíticas de onboarding.
---
# File: flutter-migration-guide-310
---
---
title: "Guía de migración al SDK de Adapty para Flutter 3.10.0"
description: ""
---
El SDK de Adapty 3.10.0 es una versión principal que incorpora mejoras que, sin embargo, pueden requerir algunos pasos de migración por tu parte:
1. Actualiza el método `makePurchase` para usar `AdaptyPurchaseParameters` en lugar de parámetros individuales.
2. Reemplaza `vendorProductIds` por `productIdentifiers` en el modelo `AdaptyPaywall`.
## Actualizar el método makePurchase \{#update-makepurchase-method\}
El método `makePurchase` ahora usa `AdaptyPurchaseParameters` en lugar de los argumentos individuales `subscriptionUpdateParams` e `isOfferPersonalized`. Esto proporciona mayor seguridad de tipos y permite una mayor extensibilidad de los parámetros de compra en el futuro.
```diff showLineNumbers
- final purchaseResult = await adapty.makePurchase(
- product: product,
- subscriptionUpdateParams: subscriptionUpdateParams,
- isOfferPersonalized: true,
- );
+ final parameters = AdaptyPurchaseParametersBuilder()
+ ..setSubscriptionUpdateParams(subscriptionUpdateParams)
+ ..setIsOfferPersonalized(true)
+ ..setObfuscatedAccountId('your-account-id')
+ ..setObfuscatedProfileId('your-profile-id');
+ final purchaseResult = await adapty.makePurchase(
+ product: product,
+ parameters: parameters.build(),
+ );
```
Si no necesitas parámetros adicionales, puedes usar simplemente:
```dart showLineNumbers
final purchaseResult = await adapty.makePurchase(
product: product,
);
```
## Actualizar el uso del modelo AdaptyPaywall \{#update-adaptyp-aywall-model-usage\}
La propiedad `vendorProductIds` ha quedado obsoleta en favor de `productIdentifiers`. La nueva propiedad devuelve objetos `AdaptyProductIdentifier` en lugar de cadenas de texto simples, lo que ofrece información de producto con una estructura más organizada.
```diff showLineNumbers
- paywall.vendorProductIds.map((vendorId) =>
- ListTextTile(title: vendorId)
- ).toList()
+ paywall.productIdentifiers.map((productId) =>
+ ListTextTile(title: productId.vendorProductId)
+ ).toList()
```
El objeto `AdaptyProductIdentifier` proporciona acceso al ID del producto del proveedor a través de la propiedad `vendorProductId`, manteniendo la misma funcionalidad y ofreciendo una mejor estructura para mejoras futuras.
## Compatibilidad con versiones anteriores \{#backward-compatibility\}
Ambos cambios mantienen la compatibilidad con versiones anteriores:
- Los parámetros antiguos en `makePurchase` están obsoletos, pero siguen funcionando
- La propiedad `vendorProductIds` está obsoleta, pero sigue siendo accesible
- El código existente seguirá funcionando, aunque verás advertencias de obsolescencia
Te recomendamos actualizar tu código para usar las nuevas API y garantizar la compatibilidad futura, además de aprovechar la mayor seguridad de tipos y extensibilidad.
---
# File: flutter-migration-guide-38
---
---
title: "Migrar el SDK de Adapty para Flutter a v. 3.8"
description: "Migra al SDK de Adapty para Flutter v3.8 para obtener mejor rendimiento y nuevas funciones de monetización."
---
El SDK 3.8.0 de Adapty es una versión mayor que incluye mejoras que pueden requerir algunos pasos de migración por tu parte.
1. Actualiza los nombres de la clase observadora y sus métodos.
2. Actualiza el nombre del método de paywalls de respaldo.
3. Actualiza el nombre de la clase de vista en los métodos de manejo de eventos.
## Actualiza los nombres de la clase observadora y sus métodos \{#update-observer-class-and-method-names\}
La clase observadora y su método de registro han sido renombrados:
```diff showLineNumbers
- class MyObserver extends AdaptyUIObserver {
+ class MyObserver extends AdaptyUIPaywallsEventsObserver {
@override
void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action) {
// Handle action
}
}
// Register observer
- AdaptyUI().setObserver(this);
+ AdaptyUI().setPaywallsEventsObserver(this);
```
## Actualiza el nombre del método de paywalls de respaldo \{#update-fallback-paywalls-method-name\}
El método para configurar los paywalls de respaldo ha sido simplificado:
```diff showLineNumbers
try {
- await Adapty.setFallbackPaywalls(assetId);
+ await Adapty.setFallback(assetId);
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
// handle the error
}
```
## Actualiza el nombre de la clase de vista en los métodos de gestión de eventos \{#update-view-class-name-in-event-handling-methods\}
Todos los métodos de gestión de eventos ahora utilizan la nueva clase `AdaptyUIPaywallView` en lugar de `AdaptyUIView`:
```diff showLineNumbers
- void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action)
+ void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action)
- void paywallViewDidSelectProduct(AdaptyUIView view, AdaptyPaywallProduct product)
+ void paywallViewDidSelectProduct(AdaptyUIPaywallView view, AdaptyPaywallProduct product)
- void paywallViewDidStartPurchase(AdaptyUIView view, AdaptyPaywallProduct product)
+ void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product)
- void paywallViewDidFinishPurchase(AdaptyUIView view, AdaptyPaywallProduct product, AdaptyProfile profile)
+ void paywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyProfile profile)
- void paywallViewDidFailPurchase(AdaptyUIView view, AdaptyPaywallProduct product, AdaptyError error)
+ void paywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error)
- void paywallViewDidFinishRestore(AdaptyUIView view, AdaptyProfile profile)
+ void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile)
- void paywallViewDidFailRestore(AdaptyUIView view, AdaptyError error)
+ void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error)
- void paywallViewDidFailLoadingProducts(AdaptyUIView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error)
+ void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error)
- void paywallViewDidFailRendering(AdaptyUIView view, AdaptyError error)
+ void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error)
```
---
# File: migration-to-flutter-sdk-34
---
---
title: "Migrar Adapty Flutter SDK a la v. 3.4"
description: "Migra al Adapty Flutter SDK v3.4 para mejor rendimiento y nuevas funciones de monetización."
---
Adapty SDK 3.4.0 es una versión mayor que introduce mejoras que requieren pasos de migración por tu parte.
## Actualizar los archivos de paywall de respaldo \{#update-fallback-paywall-files\}
Actualiza tus archivos de paywall de respaldo para garantizar la compatibilidad con la nueva versión del SDK:
1. [Descarga los archivos de paywall de respaldo actualizados](fallback-paywalls) desde el Adapty Dashboard.
2. [Reemplaza los paywalls de respaldo existentes en tu app](flutter-use-fallback-paywalls) con los nuevos archivos.
## Actualizar la implementación del Observer Mode \{#update-implementation-of-observer-mode\}
Si utilizas el Observer Mode, asegúrate de actualizar su implementación.
Anteriormente se usaban distintos métodos para reportar transacciones a Adapty. En la nueva versión, el método `reportTransaction` debe usarse de forma consistente tanto en Android como en iOS. Este método reporta explícitamente cada transacción a Adapty, garantizando que sea reconocida. Si se utilizó un paywall, pasa el ID de variación para vincular la transacción con él.
:::warning
**¡No omitas el reporte de transacciones!**
Si no llamas a `reportTransaction`, Adapty no reconocerá la transacción, no aparecerá en los análisis y no se enviará a las integraciones.
:::
```diff showLineNumbers
- // every time when calling transaction.finish()
- if (Platform.isAndroid) {
- try {
- await Adapty().restorePurchases();
- } on AdaptyError catch (adaptyError) {
- // handle the error
- } catch (e) {
- }
- }
try {
// every time when calling transaction.finish()
await Adapty().reportTransaction(
"YOUR_TRANSACTION_ID",
variationId: "PAYWALL_VARIATION_ID", // optional
);
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
// handle the error
}
```
---
# File: migration-to-flutter330
---
---
title: "Migrar el SDK de Flutter de Adapty a v3.3"
description: "Migra al SDK de Flutter de Adapty v3.3 para mejorar el rendimiento y acceder a nuevas funciones de monetización."
---
Adapty SDK 3.3.0 es una versión mayor que trae varias mejoras que, sin embargo, pueden requerir algunos pasos de migración por tu parte.
1. Actualiza el método para proporcionar paywalls de respaldo.
2. Elimina el método `getProductsIntroductoryOfferEligibility`.
3. Actualiza las configuraciones de integración para Adjust, AirBridge, Amplitude, AppMetrica, Appsflyer, Branch, Facebook Ads, Firebase and Google Analytics, Mixpanel, OneSignal, Pushwoosh.
4. Actualiza la implementación del modo Observer.
## Método actualizado para proporcionar paywalls de respaldo \{#update-method-for-providing-fallback-paywalls\}
Antes, el método requería el paywall de respaldo como una cadena JSON (`jsonString`), pero ahora recibe la ruta al archivo de respaldo local (`assetId`) en su lugar.
```diff showLineNumbers
import 'dart:async' show Future;
import 'dart:io' show Platform;
-import 'package:flutter/services.dart' show rootBundle;
-final filePath = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json';
-final jsonString = await rootBundle.loadString(filePath);
+final assetId = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json';
try {
- await adapty.setFallbackPaywalls(jsonString);
+ await adapty.setFallbackPaywalls(assetId);
} on AdaptyError catch (adaptyError) {
// handle the error
} catch (e) {
}
```
Para ver el ejemplo de código completo, consulta la página [Usar paywalls de respaldo](flutter-use-fallback-paywalls).
## Elimina el método `getProductsIntroductoryOfferEligibility` \{#remove-getproductsintroductoryoffereligibility-method\}
Antes del SDK de Adapty iOS 3.3.0, el objeto de producto siempre incluía las ofertas, independientemente de si el usuario era elegible. Tenías que verificar la elegibilidad manualmente antes de usar la oferta.
Ahora, el objeto de producto solo incluye una oferta si el usuario es elegible. Esto significa que ya no necesitas verificar la elegibilidad: si hay una oferta presente, el usuario es elegible.
## Actualiza la configuración del SDK de integraciones de terceros \{#update-third-party-integration-sdk-configuration\}
Para garantizar que las integraciones funcionen correctamente con el SDK de Adapty Flutter 3.3.0 y versiones posteriores, actualiza las configuraciones de tu SDK para las siguientes integraciones tal como se describe en las secciones a continuación.
### Adjust
Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con Adjust](adjust#connect-your-app-to-adjust).
```diff showLineNumbers
import 'package:adjust_sdk/adjust.dart';
import 'package:adjust_sdk/adjust_config.dart';
try {
final adid = await Adjust.getAdid();
if (adid == null) {
// handle the error
}
+ await Adapty().setIntegrationIdentifier(
+ key: "adjust_device_id",
+ value: adid,
+ );
final attributionData = await Adjust.getAttribution();
var attribution = MapUn valor booleano que controla el [modo Observer](observer-vs-full-mode). Actívalo si gestionas las compras y el estado de las suscripciones por tu cuenta y usas Adapty solo para enviar eventos de suscripción y analíticas.
El valor por defecto es `false`.
🚧 Al ejecutarse en modo Observer, el SDK de Adapty no cerrará ninguna transacción, así que asegúrate de gestionarlas tú mismo.
| | **withCustomerUserId** | opcional | Un identificador del usuario en tu sistema. Lo enviamos en los eventos de suscripción y analítica para atribuir los eventos al perfil correcto. También puedes buscar clientes por `customerUserId` en el menú [**Profiles and Segments**](https://app.adapty.io/profiles/users). | | **withIdfaCollectionDisabled** | opcional |Establécelo en `true` para deshabilitar la recopilación y el uso compartido del IDFA.
el uso compartido de la dirección IP del usuario.
El valor por defecto es `false`.
Para más detalles sobre la recopilación del IDFA, consulta la sección [Integración de analíticas](analytics-integration#disable-collection-of-advertising-identifiers).
| | **withIpAddressCollectionDisabled** | opcional |Establécelo en `true` para deshabilitar la recopilación y el uso compartido de la dirección IP del usuario.
El valor por defecto es `false`.
| ### Activar el módulo AdaptyUI del SDK de Adapty \{#activate-adaptyui-module-of-adapty-sdk\} Solo necesitas configurar el módulo AdaptyUI si tienes pensado usar el [Paywall Builder](adapty-paywall-builder): ```dart showLineNumbers title="Dart" try { final mediaCache = AdaptyUIMediaCacheConfiguration( memoryStorageTotalCostLimit: 100 * 1024 * 1024, // 100MB memoryStorageCountLimit: 2147483647, // 2^31 - 1, max int value in Dart diskStorageSizeLimit: 100 * 1024 * 1024, // 100MB ); await AdaptyUI().activate( configuration: AdaptyUIConfiguration(mediaCache: mediaCache), observer:
### Durante el inicio de sesión/registro \{#during-loginsignup\}
Si identificas a los usuarios después del inicio de la app (por ejemplo, tras iniciar sesión o registrarse), usa el método `identify` para establecer su customer user ID.
- Si **no has usado este customer user ID antes**, Adapty lo vinculará automáticamente al perfil actual.
- Si **ya has usado este customer user ID para identificar al usuario**, Adapty pasará a trabajar con el perfil asociado a ese customer user ID.
:::important
Los customer user IDs deben ser únicos para cada usuario. Si defines el valor del parámetro de forma fija, todos los usuarios se considerarán como uno solo.
:::
Siempre usa `await` con `identify` antes de llamar a otros métodos del SDK. Las llamadas concurrentes producen `#3006 profileWasChanged` o recaen sobre el perfil anónimo. Consulta [Orden de llamadas en el SDK de iOS](ios-sdk-call-order).
Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no reciban los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo intermitente que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché actualizada periódicamente que se describe arriba y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes peticiones internamente.
| Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :---------- | | Flow | Un objeto `AdaptyFlow` que contiene el placement, identificadores (`id`, `variationId`), nombre, Remote Configs y un indicador `hasViewConfiguration` que señala si el flow incluye una configuración de vista. Para obtener los productos reales con fines de precarga, UI personalizada o comprobaciones programáticas, llama a `getPaywallProducts(flow:)`. | ## Obtener la configuración de vista \{#fetch-the-view-configuration\} Después de obtener el flow o el paywall, comprueba si incluye una configuración de vista mediante `flow.hasViewConfiguration`. Este flag distingue cómo se diseñó el placement en el Adapty Dashboard: - **`true`** — el placement fue diseñado en el **Flow Builder** (un flow) o en el **Paywall Builder** (un paywall). Adapty renderiza la interfaz por ti. Continúa con los pasos a continuación para obtener la configuración de vista y [mostrar el flow o el paywall](ios-present-paywalls). - **`false`** — el placement es un paywall personalizado sin interfaz del Builder. Usa el método `getFlowConfiguration` para cargar la configuración de la vista. ```swift showLineNumbers guard flow.hasViewConfiguration else { // handle as remote config paywall return } let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) ``` Parámetros: | Parámetro | Presencia | Descripción | | :----------------------- | :------------- | :---------- | | **forFlow** | obligatorio | Un objeto `AdaptyFlow` obtenido mediante `Adapty.getFlow`. | | **locale** |opcional
por defecto: `nil`
| El identificador de la [localización del paywall](add-paywall-locale-in-adapty-paywall-builder). Se espera como un código de idioma con una o dos subetiquetas separadas por `-` (p. ej., `en`, `pt-br`). Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes). | | **loadTimeout** | por defecto: 5 seg | Este valor limita el tiempo de espera para este método. Si se alcanza el límite, se devolverán los datos en caché o el fallback local. Ten en cuenta que en casos poco frecuentes este método puede superar ligeramente el tiempo indicado en `loadTimeout`, ya que la operación puede constar de distintas solicitudes internamente. | | **products** | opcional | Proporciona un array de objetos `AdaptyPaywallProduct` para optimizar el momento en que se muestran los productos en pantalla. Si se pasa `nil`, AdaptyUI obtendrá automáticamente los productos necesarios. | | **systemRequestsHandler** | opcional | Un objeto que implementa `AdaptySystemRequestsHandler` y gestiona las solicitudes de permisos del sistema y valoraciones activadas por acciones del flow. Solo es necesario si tu flow incluye este tipo de acciones. | | **assetsResolver** | opcional | Un diccionario `[String: AdaptyCustomAsset]` que sobreescribe imágenes y vídeos en el flow/paywall. Consulta [Personalizar assets](#customize-assets). | | **timerResolver** | opcional | Un objeto que implementa `AdaptyTimerResolver` y proporciona fechas de finalización para los temporizadores definidos por el desarrollador. Consulta [Configurar temporizadores definidos por el desarrollador](#set-up-developer-defined-timers). | Una vez cargado, [presenta el flow/paywall](ios-present-paywalls). ## Obtén un flow o paywall para la audiencia predeterminada y cárgalo más rápido \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} Por lo general, los flows y paywalls se obtienen casi al instante, por lo que no es necesario preocuparse por acelerar este proceso. Sin embargo, si tienes muchas audiencias y placements, y tus usuarios tienen una conexión a internet lenta, obtener un flow o paywall puede tardar más de lo que desearías. En esos casos, puede que quieras mostrar un flow o paywall predeterminado para garantizar una experiencia de usuario fluida en lugar de no mostrar nada. Para solucionar esto, puedes usar el método `getFlowForDefaultAudience`, que obtiene el flow o paywall del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el flow o paywall con el método `getFlow`, tal como se detalla en la sección [Obtener información del paywall](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) anterior. :::warning Por qué recomendamos usar `getFlow` El método `getFlowForDefaultAudience` tiene algunos inconvenientes importantes: - **Posibles problemas de compatibilidad con versiones anteriores**: Si necesitas mostrar distintos paywalls para diferentes versiones de la app (la actual y las futuras), puedes encontrarte con dificultades. Tendrás que diseñar paywalls compatibles con la versión actual (legacy) o asumir que los usuarios de esa versión podrían tener problemas con paywalls que no se renderizan correctamente. - **Pérdida de targeting**: Todos los usuarios verán el mismo paywall diseñado para la audiencia **All Users**, lo que significa que pierdes la segmentación personalizada (incluyendo por país, atribución de marketing o tus propios atributos personalizados). Si estás dispuesto a aceptar estas limitaciones a cambio de una obtención más rápida del flow o del paywall, usa el método `getFlowForDefaultAudience` de la siguiente manera. De lo contrario, quédate con `getFlow` descrito [anteriormente](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder). ::: ```swift showLineNumbers Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` | Parámetro | Presencia | Descripción | |---------|--------|-----------| | **placementId** | obligatorio | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| ## Personalizar recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu paywall/flow, implementa los recursos personalizados. Las imágenes y vídeos destacados tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizados, apuntas a estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Muestra una imagen o vídeo diferente a algunos usuarios. - Muestra una imagen de vista previa local mientras se carga la imagen principal remota. - Muestra una imagen de vista previa antes de reproducir un vídeo. - Indica la resolución en píxeles del vídeo para que el reproductor reserve espacio en el layout (relación de aspecto = `width / height`) antes de que cargue el vídeo. Pasa `nil` para omitirlo. A continuación se muestra un ejemplo de cómo puedes proporcionar assets personalizados mediante un diccionario sencillo: ```swift showLineNumbers let customAssets: [String: AdaptyCustomAsset] = [ // Show a local image using a custom ID "custom_image": .image( .uiImage(value: UIImage(named: "image_name")!) ), // Show a local preview image while a remote main image is loading "hero_image": .image( .remote( url: URL(string: "https://example.com/image.jpg")!, preview: UIImage(named: "preview_image") ) ), // Show a local video with a preview image and a known resolution "hero_video": .video( .file( url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!, preview: .uiImage(value: UIImage(named: "video_preview")!), resolution: CGSize(width: 1080, height: 1920) ) ), ] let flowConfig = try await AdaptyUI.getFlowConfiguration( forFlow: flow, assetsResolver: customAssets ) ``` :::note Si no se encuentra un asset, el paywall/flow volverá a su apariencia predeterminada. ::: ## Configurar temporizadores definidos por el desarrollador \{#set-up-developer-defined-timers\} Para usar temporizadores personalizados en tu app, crea un objeto que implemente el protocolo `AdaptyTimerResolver`. Este objeto define cómo debe renderizarse cada temporizador personalizado. Si lo prefieres, puedes usar directamente un diccionario `[String: Date]`, ya que ya cumple con este protocolo. Aquí tienes un ejemplo: ```swift showLineNumbers @MainActor struct AdaptyTimerResolverImpl: AdaptyTimerResolver { func timerEndAtDate(for timerId: String) -> Date { switch timerId { case "CUSTOM_TIMER_6H": Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours case "CUSTOM_TIMER_NY": Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) default: Date(timeIntervalSinceNow: 3600.0) // 1 hour } } } ``` En este ejemplo, `CUSTOM_TIMER_NY` y `CUSTOM_TIMER_6H` son los **Timer ID** de los temporizadores definidos por el desarrollador que configuraste en el Adapty Dashboard. El `timerResolver` garantiza que tu app actualice dinámicamente cada temporizador con el valor correcto. Por ejemplo: - `CUSTOM_TIMER_NY`: El tiempo restante hasta que finalice el temporizador, como el Año Nuevo. - `CUSTOM_TIMER_6H`: El tiempo restante en un período de 6 horas que comenzó cuando el usuario abrió el paywall.opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-paywall-locale-in-adapty-paywall-builder). Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos utilizarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché de actualización periódica descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls y que el servicio sea fiable incluso cuando la conexión a internet sea escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede estar compuesta por distintas solicitudes internas.
| Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :---------- | | Paywall | Un objeto [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) con una lista de IDs de productos, el identificador del paywall, el Remote Config y varias otras propiedades. | ## Obtener la configuración de vista de un paywall creado con Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Asegúrate de activar el botón **Show on device** en el Paywall Builder. Si esta opción no está activada, la configuración de vista no estará disponible para recuperar. ::: Después de obtener el paywall, comprueba si incluye una configuración de vista, lo que indica que fue creado con Paywall Builder. Esto te indicará cómo mostrar el paywall. Si la configuración de vista está presente, trátalo como un paywall de Paywall Builder; si no, [trátalo como un paywall de Remote Config](present-remote-config-paywalls). Usa el método `getPaywallConfiguration` para cargar la configuración de la vista. ```swift showLineNumbers guard paywall.hasViewConfiguration else { // use your custom logic return } do { let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall, products: products ) // use loaded configuration } catch { // handle the error } ``` Parámetros: | Parámetro | Presencia | Descripción | | :----------------------- | :------------- | :---------- | | **paywall** | obligatorio | Un objeto `AdaptyPaywall` para obtener un controlador del paywall deseado. | | **loadTimeout** | por defecto: 5 seg | Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local. Ten en cuenta que en casos excepcionales este método puede agotar el tiempo ligeramente después de lo especificado en `loadTimeout`, ya que la operación puede constar de distintas solicitudes internamente. | | **products** | opcional | Proporciona un array de objetos `AdaptyPaywallProduct` para optimizar el tiempo de visualización de los productos en pantalla. Si se pasa `nil`, AdaptyUI obtendrá automáticamente los productos necesarios. | :::note Si estás usando varios idiomas, aprende cómo añadir una [localización en el Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) y cómo usar los códigos de idioma correctamente [aquí](localizations-and-locale-codes). ::: Una vez cargado, [muestra el paywall](ios-present-paywalls). ## Obtén un paywall para la audiencia predeterminada y acelera la carga \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} Normalmente, los paywalls se obtienen casi de forma instantánea, así que no necesitas preocuparte por optimizar este proceso. Sin embargo, cuando tienes muchas audiencias y paywalls, y tus usuarios tienen una conexión a internet débil, la carga de un paywall puede tardar más de lo deseable. En esos casos, puede que quieras mostrar un paywall predeterminado para garantizar una experiencia fluida en lugar de no mostrar ninguno. Para solucionar esto, puedes usar el método `getPaywallForDefaultAudience`, que obtiene el paywall del placement indicado para la audiencia **All Users**. Sin embargo, es importante entender que el enfoque recomendado es obtener el paywall con el método `getPaywall`, tal como se detalla en la sección [Obtener información del paywall](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) anterior. :::warning Por qué recomendamos usar `getPaywall` El método `getPaywallForDefaultAudience` tiene algunos inconvenientes importantes: - **Posibles problemas de compatibilidad con versiones anteriores**: Si necesitas mostrar paywalls diferentes para distintas versiones de la app (la actual y las futuras), puede que te encuentres con dificultades. Tendrás que diseñar paywalls que sean compatibles con la versión actual (legacy), o asumir que los usuarios con esa versión podrían tener problemas con paywalls que no se renderizan correctamente. - **Pérdida de targeting**: Todos los usuarios verán el mismo paywall diseñado para la audiencia **All Users**, lo que significa que pierdes la segmentación personalizada (incluida la basada en países, atribución de marketing o tus propios atributos personalizados). Si estás dispuesto a aceptar estos inconvenientes para beneficiarte de una obtención más rápida del paywall, usa el método `getPaywallForDefaultAudience` de la siguiente manera. De lo contrario, quédate con `getPaywall` descrito [anteriormente](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder). ::: ```swift showLineNumbers Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` :::note El método `getPaywallForDefaultAudience` está disponible a partir de la versión 2.11.2 del SDK de iOS. ::: | Parámetro | Presencia | Descripción | |---------|--------|-----------| | **placementId** | requerido | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **locale** |opcional
valor por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | valor por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| ## Personalizar recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu paywall, implementa recursos personalizados. Las imágenes y vídeos hero tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizados, seleccionas estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. :::important Para usar esta función, actualiza el SDK de Adapty para iOS a la versión 3.7.0 o superior. ::: Aquí tienes un ejemplo de cómo puedes proporcionar assets personalizados mediante un diccionario sencillo: ```swift showLineNumbers let customAssets: [String: AdaptyCustomAsset] = [ // Show a local image using a custom ID "custom_image": .image( .uiImage(value: UIImage(named: "image_name")!) ), // Show a local preview image while a remote main image is loading "hero_image": .image( .remote( url: URL(string: "https://example.com/image.jpg")!, preview: UIImage(named: "preview_image") ) ), // Show a local video with a preview image "hero_video": .video( .file( url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!, preview: .uiImage(value: UIImage(named: "video_preview")!) ) ), ] let paywallConfig = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall, assetsResolver: customAssets ) ``` :::note Si no se encuentra un asset, el paywall volverá a su apariencia predeterminada. ::: ## Configurar temporizadores definidos por el desarrollador \{#set-up-developer-defined-timers\} Para usar temporizadores personalizados en tu app, crea un objeto que implemente el protocolo `AdaptyTimerResolver`. Este objeto define cómo se debe renderizar cada temporizador personalizado. Si lo prefieres, puedes usar directamente un diccionario `[String: Date]`, ya que ya es compatible con este protocolo. Aquí tienes un ejemplo: ```swift showLineNumbers @MainActor struct AdaptyTimerResolverImpl: AdaptyTimerResolver { func timerEndAtDate(for timerId: String) -> Date { switch timerId { case "CUSTOM_TIMER_6H": Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours case "CUSTOM_TIMER_NY": Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) default: Date(timeIntervalSinceNow: 3600.0) // 1 hour } } } ``` En este ejemplo, `CUSTOM_TIMER_NY` y `CUSTOM_TIMER_6H` son los **Timer ID**s de los temporizadores definidos por el desarrollador que configuraste en el Adapty Dashboard. El `timerResolver` garantiza que tu app actualice dinámicamente cada temporizador con el valor correcto. Por ejemplo: - `CUSTOM_TIMER_NY`: El tiempo restante hasta el fin del temporizador, como el día de Año Nuevo. - `CUSTOM_TIMER_6H`: El tiempo que queda en un período de 6 horas que empezó cuando el usuario abrió el paywall.
## El número de vistas del paywall es demasiado alto \{#the-paywall-view-number-is-too-big\}
**Problema**: El recuento de vistas del paywall muestra el doble del número esperado.
**Motivo**: Es posible que estés llamando a `logShowFlow` (iOS SDK v4+) / `logShowPaywall` en tu código, lo que duplica el recuento de vistas si usas el Paywall Builder o el Flow Builder. Para flows y paywalls creados con estas herramientas, las analíticas se registran automáticamente, por lo que no necesitas usar este método.
**Solución**: Asegúrate de no llamar a `logShowFlow` (iOS SDK v4+) / `logShowPaywall` en tu código si usas el Paywall Builder o el Flow Builder.
## Otros problemas \{#other-issues\}
**Problema**: Tienes otros problemas relacionados con el Paywall Builder que no se tratan más arriba.
**Solución**: Si es necesario, migra el SDK a la última versión siguiendo las [guías de migración](ios-sdk-migration-guides). Muchos problemas se resuelven en versiones más recientes del SDK.
---
# File: ios-present-paywall-builder-paywalls-in-observer-mode
---
---
title: "Presentar paywalls del Paywall Builder en modo Observer en el SDK de iOS"
description: "Aprende cómo presentar paywalls de PB en modo observer para obtener mejores insights."
---
Si has personalizado un paywall usando el Paywall Builder, no necesitas preocuparte por renderizarlo en el código de tu app para mostrárselo al usuario. Este tipo de paywall incluye tanto lo que se debe mostrar como la forma en que debe mostrarse.
:::warning
Esta sección hace referencia al [modo Observer](observer-vs-full-mode) únicamente. Si no trabajas en modo Observer, consulta [iOS - Presentar paywalls con Paywall Builder](ios-present-paywalls).
:::
Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los flows y paywalls en dos capas: la caché de actualización periódica descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener flows y paywalls más rápido, y un servidor de respaldo independiente en caso de que el CDN no esté disponible.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede exceder ligeramente el tiempo de espera especificado en `loadTimeout`, ya que la operación puede incluir diferentes peticiones internamente.
| :::note En la versión 4, el parámetro `locale` ha pasado de `getFlow` a `getFlowConfiguration` (que solo se usa al renderizar con AdaptyUI). Para los paywalls personalizados, todas las configuraciones regionales disponibles se devuelven juntas en `flow.remoteConfigs` — elige la que coincida con el idioma del dispositivo del usuario o con la configuración de tu app. ::: ¡No escribas los IDs de productos en el código! Como los flows se configuran de forma remota, los productos disponibles, el número de productos y las ofertas especiales (como los períodos de prueba gratuitos) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si inicialmente obtienes 2 productos, tu app debería mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, tu app debería mostrar los 3 sin necesidad de cambios en el código. Lo único que tienes que escribir directamente en el código es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objeto `AdaptyFlow` que contiene el placement, los identificadores (`id`, `variationId`), el nombre, un array `remoteConfigs` (una entrada por cada locale configurado) y un flag `hasViewConfiguration`. Para obtener los productos del flow, llama a `getPaywallProducts(flow:)`. | ## Obtener productos \{#fetch-products\} Una vez que tienes el flow, puedes consultar el array de productos asociado a él:Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
|opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de lo irregular que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls en dos capas: la caché de actualización periódica descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el timeout, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede comprender varias solicitudes internamente.
| ¡No uses IDs de producto codificados directamente en el código! Como los paywalls se configuran de forma remota, los productos disponibles, su cantidad y las ofertas especiales (como pruebas gratuitas) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si al principio obtienes 2 productos, tu app debería mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, tu app debería mostrar los 3 sin necesidad de modificar el código. Lo único que debes codificar directamente es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) con: una lista de IDs de productos, el identificador del paywall, Remote Config y varias otras propiedades. | ## Obtener productos \{#fetch-products\} Una vez que tienes el paywall, puedes consultar el array de productos que le corresponde:opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios puede que no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo irregular que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
|Si la solicitud se ha realizado con éxito, la respuesta contiene este objeto. Un objeto [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile) proporciona información completa sobre los niveles de acceso, suscripciones y compras únicas de un usuario dentro de la app.
Comprueba el estado del nivel de acceso para determinar si el usuario tiene el acceso requerido a la app.
| :::warning **Nota:** si todavía usas una versión de StoreKit de Apple inferior a v2.0 y una versión del SDK de Adapty inferior a v2.9.0, debes proporcionar el [secreto compartido de Apple App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret) en su lugar. Este método está actualmente obsoleto según Apple. ::: ## Compras in-app desde el App Store Cuando un usuario inicia una compra en el App Store y la transacción llega a tu app, tienes dos opciones: - **Procesar la transacción inmediatamente:** Devuelve `true` en `shouldAddStorePayment`. Esto activará la pantalla del sistema de compra de Apple de inmediato. - **Guardar el objeto de producto para procesarlo más tarde:** Devuelve `false` en `shouldAddStorePayment` y luego llama a `makePurchase` con el producto guardado más adelante. Esto puede ser útil si necesitas mostrar algo personalizado al usuario antes de iniciar una compra. Aquí tienes el fragmento completo: ```swift showLineNumbers title="Swift" final class YourAdaptyDelegateImplementation: AdaptyDelegate { nonisolated func shouldAddStorePayment(for product: AdaptyDeferredProduct) -> Bool { // 1a. // Return `true` to continue the transaction in your app. The Apple purchase system screen will show automatically. // 1b. // Store the product object and return `false` to defer or cancel the transaction. false } // 2. Continue the deferred purchase later on by passing the product to `makePurchase` when the timing is appropriate func continueDeferredPurchase() async { let storedProduct: AdaptyDeferredProduct = // get the product object from 1b. do { try await Adapty.makePurchase(product: storedProduct) } catch { // handle the error } } } ``` ## Canjear códigos de oferta en iOS \{#redeem-offer-codes-in-ios\}Un objeto [`AdaptyProfile`](https://swift.adapty.io/documentation/adapty/adaptyprofile). Este modelo contiene información sobre niveles de acceso, suscripciones y compras únicas.
Comprueba el **estado del nivel de acceso** para determinar si el usuario tiene acceso a la app.
| :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: --- # File: ios-transaction-management --- --- title: "Gestión avanzada de transacciones en el SDK de iOS" description: "Finaliza transacciones manualmente en tu app de iOS con el SDK de Adapty." --- :::note La gestión avanzada de transacciones está disponible en el SDK de Adapty para iOS a partir de la versión 3.12. ::: La gestión avanzada de transacciones en Adapty te da mayor control sobre cómo se procesan, verifican y finalizan las transacciones. Esta funcionalidad introduce tres características opcionales que trabajan en conjunto: | Característica | Propósito | |-------------------------------------------------------------|----------| | [`appAccountToken`](#assign-appaccounttoken) | Vincula las transacciones de Apple con tu ID de usuario interno | | [`jwsTransaction`](#access-the-jws-representation) | Proporciona el payload de transacción firmado por Apple para validación | | [Finalización manual](#control-transaction-finishing-behavior) | Permite finalizar transacciones solo después de que tu backend confirme el éxito | En conjunto, estas herramientas te permiten construir flujos de validación personalizados robustos mientras Adapty sigue sincronizando las transacciones con su backend. :::important La mayoría de las apps no necesitan esto. Por defecto, Adapty valida y finaliza automáticamente las transacciones de StoreKit. Usa esta guía solo si ejecutas tu propia validación en el backend o quieres controlar por completo el ciclo de vida de las compras. ::: ## Asignar `appAccountToken` \{#assign-appaccounttoken\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) es un **UUID** que te permite vincular las transacciones de la App Store con la identidad interna de tus usuarios. StoreKit asocia este token con cada transacción, de modo que tu backend puede relacionar los datos de la App Store con tus usuarios. Usa un UUID estable generado por usuario y reutilízalo para la misma cuenta en todos los dispositivos. Esto garantiza que las compras y las notificaciones de la App Store queden correctamente vinculadas. Puedes establecer el token de dos formas: durante la activación del SDK o al identificar al usuario. :::important Siempre debes pasar `appAccountToken` junto con `customerUserId`. Si solo pasas el token, no se incluirá en la transacción. :::Para StoreKit 1: un objeto [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Para StoreKit 2: objeto [Transaction](https://developer.apple.com/documentation/storekit/transaction).
|phoneNumber
firstName
lastName
| String | | gender | Enum, los valores permitidos son: `female`, `male`, `other` | | birthday | Date | ### Atributos de usuario personalizados \{#custom-user-attributes\} Puedes definir tus propios atributos personalizados, que normalmente están relacionados con el uso de tu app. Por ejemplo, en apps de fitness pueden ser el número de entrenamientos por semana; en apps de aprendizaje de idiomas, el nivel de conocimiento del usuario, etc. Puedes usarlos en segmentos para crear paywalls y ofertas dirigidas, y también en analíticas para identificar qué métricas de producto influyen más en los ingresos. ```swift showLineNumbers do { builder = try builder.with(customAttribute: "value1", forKey: "key1") } catch { // handle key/value validation error } ``` Para eliminar una clave existente, usa el método `.withRemoved(customAttributeForKey:)`: ```swift showLineNumbers do { builder = try builder.withRemoved(customAttributeForKey: "key2") } catch { // handle error } ``` A veces necesitas saber qué atributos personalizados ya están definidos. Para ello, usa el campo `customAttributes` del objeto `AdaptyProfile`. :::warning Ten en cuenta que el valor de `customAttributes` puede estar desactualizado, ya que los atributos de usuario pueden enviarse desde distintos dispositivos en cualquier momento, por lo que los atributos en el servidor podrían haber cambiado desde la última sincronización. ::: ### Límites \{#limits\} - Hasta 30 atributos personalizados por usuario. - Los nombres de clave tienen hasta 30 caracteres. El nombre de la clave puede incluir caracteres alfanuméricos y cualquiera de los siguientes: `_` `-` `.` - El valor puede ser una cadena de texto o un número decimal con un máximo de 50 caracteres. --- # File: subscription-status --- --- title: "Comprobar el estado de suscripción en iOS SDK" description: "Rastrea y gestiona el estado de suscripción de los usuarios en Adapty para mejorar la retención de clientes." --- Con Adapty, hacer seguimiento del estado de suscripción es muy sencillo. No tienes que insertar manualmente los IDs de producto en tu código. En su lugar, puedes confirmar fácilmente el estado de suscripción de un usuario comprobando si tiene un [nivel de acceso](access-level) activo. Antes de empezar a comprobar el estado de suscripción, configura las [Notificaciones del servidor de App Store](enable-app-store-server-notifications). ## Nivel de acceso y el objeto AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Los niveles de acceso son propiedades del objeto [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile). Te recomendamos recuperar el perfil cuando tu app arranque, por ejemplo al [identificar a un usuario](identifying-users#set-customer-user-id-on-configuration), y actualizarlo cada vez que se produzcan cambios. Así podrás usar el objeto de perfil sin tener que solicitarlo repetidamente. Para recibir notificaciones de las actualizaciones del perfil, escucha los cambios tal como se describe en la sección [Escuchar actualizaciones del estado de suscripción](subscription-status#listening-for-subscription-status-updates) más abajo. :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ## Obtener el nivel de acceso desde el servidor \{#retrieving-the-access-level-from-the-server\} Para obtener el nivel de acceso desde el servidor, usa el método `.getProfile()`:Un objeto [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile). En general, solo necesitas comprobar el estado del nivel de acceso del perfil para determinar si el usuario tiene acceso premium a la app.
El método `.getProfile` devuelve el resultado más actualizado, ya que siempre intenta consultar la API. Si por algún motivo (por ejemplo, sin conexión a internet) el SDK de Adapty no puede obtener información del servidor, se devolverán los datos de la caché. También es importante destacar que el SDK de Adapty actualiza la caché de `AdaptyProfile` periódicamente para mantener esta información lo más actualizada posible.
| El método `.getProfile()` te proporciona el perfil del usuario a partir del cual puedes obtener el estado del nivel de acceso. Puedes tener múltiples niveles de acceso por app. Por ejemplo, si tienes una app de noticias y vendes suscripciones a diferentes temáticas de forma independiente, puedes crear los niveles de acceso "sports" y "science". Pero la mayoría de las veces solo necesitarás un nivel de acceso; en ese caso, puedes usar simplemente el nivel de acceso predeterminado "premium". A continuación tienes un ejemplo para comprobar el nivel de acceso predeterminado "premium":opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché se mantiene al reiniciar la app y solo se borra cuando se desinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché de actualización regular descrita anteriormente y los onboardings de respaldo. También usamos CDN para cargar los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la última versión de tus onboardings y asegurar la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes peticiones internamente.
| Parámetros de respuesta: | Parámetro | Descripción | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objeto [`AdaptyOnboarding`](https://swift.adapty.io/documentation/adapty/adaptyonboarding) con: el identificador y la configuración del onboarding, Remote Config y varias otras propiedades. | ## Acelera la obtención del onboarding con el onboarding de audiencia predeterminada \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Normalmente, los onboardings se obtienen casi de forma instantánea, por lo que no necesitas preocuparte por optimizar este proceso. Sin embargo, si tienes muchas audiencias y onboardings, y tus usuarios tienen una conexión a internet lenta, la obtención de un onboarding puede tardar más de lo deseado. En esas situaciones, puede que quieras mostrar un onboarding predeterminado para garantizar una experiencia de usuario fluida en lugar de no mostrar ninguno. Para solucionar esto, puedes usar el método `getOnboardingForDefaultAudience`, que obtiene el onboarding del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el onboarding mediante el método `getOnboarding`, tal como se detalla en la sección [Obtener el onboarding](#fetch-onboarding) anterior. :::warning Considera usar `getOnboarding` en lugar de `getOnboardingForDefaultAudience`, ya que este último tiene limitaciones importantes: - **Problemas de compatibilidad**: Puede generar problemas al dar soporte a múltiples versiones de la app, lo que obliga a usar diseños compatibles con versiones anteriores o asumir que las versiones más antiguas podrían mostrarse incorrectamente. - **Sin personalización**: Solo muestra contenido para la audiencia "All Users", eliminando la segmentación por país, atribución o atributos personalizados. Si para tu caso de uso la obtención más rápida compensa estos inconvenientes, usa `getOnboardingForDefaultAudience` como se muestra a continuación. De lo contrario, usa `getOnboarding` como se describe [arriba](#fetch-onboarding). ::: ```swift showLineNumbers Adapty.getOnboardingForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(onboarding): // el onboarding solicitado case let .failure(error): // maneja el error } } ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto por una o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda, a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos utilizarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro utilizarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché de actualización periódica descrita anteriormente y los onboardings de respaldo. También usamos CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus onboardings, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| --- # File: ios-present-onboardings --- --- title: "Present onboardings in iOS SDK" description: "Discover how to present onboardings on iOS to boost conversions and revenue." --- :::tip **A partir del SDK v4**, puedes crear [flows](get-pb-paywalls) como alternativa más potente a los onboardings. A diferencia de los onboardings, que se ejecutan dentro de un WebView, los flows se renderizan de forma nativa en el dispositivo, lo que te ofrece animaciones más fluidas, una apariencia coherente con iOS, tiempos de carga más rápidos y sin dependencia del runtime de WebView. Consulta [Obtener flows y paywalls](get-pb-paywalls) y [Mostrar flows y paywalls](ios-present-paywalls) para empezar. ::: Si has personalizado un onboarding con el builder, no necesitas preocuparte por renderizarlo en el código de tu app para mostrárselo al usuario. Ese onboarding ya incluye tanto lo que debe mostrarse como la forma en que debe mostrarse. Antes de empezar, asegúrate de: 1. Haber instalado el [SDK de Adapty para iOS](sdk-installation-ios) 3.8.0 o posterior. 2. Haber [creado un onboarding](create-onboarding). 3. Haber añadido el onboarding a un [placement](placements). ## Presentar onboardings en Swift \{#present-onboardings-in-swift\} Para mostrar el onboarding visual en la pantalla del dispositivo, sigue estos pasos: 1. Obtén la configuración de la vista del onboarding con el método `.getOnboardingConfiguration`. 2. Inicializa el onboarding visual que quieres mostrar usando el método `.onboardingController`: Parámetros de la solicitud: | Parámetro | Presencia | Descripción | |:-----------------------------|:---------|:------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onboarding configuration** | requerido | Un objeto `AdaptyUI.OnboardingConfiguration` que contiene todas las propiedades del onboarding. Usa el método `AdaptyUI.getOnboardingConfiguration` para obtenerlo. | | **delegate** | requerido | Un `AdaptyOnboardingControllerDelegate` para escuchar los eventos del onboarding. | Devuelve: | Objeto | Descripción | |:-------------------------------|:-------------------------------------------------------------| | **AdaptyOnboardingController** | Un objeto que representa la pantalla de onboarding solicitada | 3. Una vez creado correctamente el objeto, puedes mostrarlo en la pantalla del dispositivo: ```swift showLineNumbers title="Swift" import Adapty import AdaptyUI // 0. Get an onboarding if you haven't done it yet let onboarding = try await Adapty.getOnboarding(placementId: "YOUR_PLACEMENT_ID") // 1. Obtain the onboarding view configuration: let configuration = try AdaptyUI.getOnboardingConfiguration(forOnboarding: onboarding) // 2. Create Onboarding View Controller let onboardingController = try AdaptyUI.onboardingController( with: configuration, delegate:
Luego puedes usar este ID en tu código y gestionarlo como una acción personalizada. Por ejemplo, si el usuario pulsa un botón personalizado, como **Login** o **Allow notifications**, el método delegado `onboardingController` se activará con el caso `.custom(id:)` y el parámetro `actionId` será el **Action ID** definido en el builder. Puedes crear tus propios IDs, como "allowNotifications".
```swift showLineNumbers
func onboardingController(_ controller: AdaptyOnboardingController, onCustomAction action: AdaptyOnboardingsCustomAction) {
if action.actionId == "allowNotifications" {
// Request notification permissions
}
}
func onboardingController(_ controller: AdaptyOnboardingController, didFailWithError error: AdaptyUIError) {
// Handle errors
}
```
:::important
Ten en cuenta que debes gestionar qué ocurre cuando el usuario cierra el onboarding. Por ejemplo, necesitas dejar de mostrar el onboarding.
:::
Por ejemplo:
```swift showLineNumbers
func onboardingController(_ controller: AdaptyOnboardingController, onCloseAction action: AdaptyOnboardingsCloseAction) {
controller.dismiss(animated: true)
}
```
2. Haz clic en el nombre del grupo de suscripciones. Verás tus productos listados en la sección **Subscriptions**.
3. Asegúrate de que el producto que estás probando figure como **Ready to Submit**. Si no es así, sigue las instrucciones de la página [Producto en App Store](app-store-products).
4. Compara el ID del producto de la tabla con el que aparece en la pestaña [**Products**](https://app.adapty.io/products) del Adapty Dashboard. Si los IDs no coinciden, copia el ID del producto de la tabla y [crea un producto](create-product) con ese ID en el Adapty Dashboard.
## Paso 3. Verifica la disponibilidad del producto \{#step-4-check-product-availability\}
1. Vuelve a **App Store Connect** y abre la misma sección **Subscriptions**.
2. Haz clic en el nombre del grupo de suscripciones para ver tus productos.
3. Selecciona el producto que estás probando.
4. Desplázate hasta la sección **Availability** y comprueba que todos los países y regiones necesarios están listados.
## Paso 4. Verifica los precios del producto \{#step-5-check-product-prices\}
1. De nuevo, ve a la sección **Monetization** → **Subscriptions** en **App Store Connect**.
2. Haz clic en el nombre del grupo de suscripciones.
3. Selecciona el producto que estás probando.
4. Desplázate hacia abajo hasta **Subscription Pricing** y expande la sección **Current Pricing for New Subscribers**.
5. Asegúrate de que todos los precios necesarios están listados.
## Paso 5. Verifica que el estado de pago de la app, la cuenta bancaria y los formularios fiscales estén activos
1. En la página de inicio de [**App Store Connect**](https://appstoreconnect.apple.com/), haz clic en **Business**.
2. Selecciona el nombre de tu empresa.
3. Desplázate hacia abajo y comprueba que tu **Paid Apps Agreement**, **Bank Account** y **Tax forms** aparecen todos como **Active**.
Siguiendo estos pasos, deberías poder resolver la advertencia `InvalidProductIdentifiers` y publicar tus productos en el store.
## Paso 6. Vuelve a crear el producto si está bloqueado
Los pasos 1–5 pueden superarse correctamente — estado `Approved`, Bundle ID coincidente, API key válida — y aun así el SDK devuelve `1000 noProductIDsFound`. En ese caso, puede que el producto esté bloqueado en el registro de Apple. El registro de productos de Apple entra ocasionalmente en un estado en el que un producto existe en la interfaz de App Store Connect pero no queda expuesto en la ruta de consulta de StoreKit.
Elimina el producto en App Store Connect y vuelve a crearlo con el mismo ID de producto. Espera hasta 24 horas tras la recreación para que se propague.
---
# File: cantMakePayments
---
---
title: "Solución para el error Code-1003 cantMakePayment"
description: "Resuelve el error de realización de pagos al gestionar suscripciones en Adapty."
---
El error 1003, `cantMakePayments`, indica que no es posible realizar compras in-app en este dispositivo.
Si encuentras el error `cantMakePayments`, normalmente se debe a una de estas razones:
- Restricciones del dispositivo: El error no está relacionado con Adapty. Consulta las soluciones más abajo.
- Configuración del modo Observer: El método `makePurchase` y el modo Observer no pueden usarse al mismo tiempo. Consulta la sección más abajo.
## Problema: Restricciones del dispositivo \{#issue-device-restrictions\}
| Problema | Solución |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| Restricciones de Screen Time | Desactiva las restricciones de compras in-app en [Screen Time](https://support.apple.com/en-us/102470) |
| Cuenta suspendida | Contacta con el soporte de Apple para resolver problemas con la cuenta |
| Restricciones regionales | Usa una cuenta de App Store de una región compatible |
## Problema: Usar el modo Observer y makePurchase a la vez \{#issue-using-both-observer-mode-and-makepurchase\}
Si usas `makePurchases` para gestionar las compras, no necesitas el modo Observer. El [modo Observer](observer-vs-full-mode) solo es necesario si implementas la lógica de compra tú mismo.
Por lo tanto, si usas `makePurchase`, puedes eliminar sin problema la activación del modo Observer del código de inicialización del SDK.
---
# File: migration-to-ios-sdk-v4
---
---
title: "Migrar Adapty iOS SDK a v4.0"
description: "Migra al Adapty iOS SDK v4.0 reemplazando las APIs de paywall por APIs de flow, compatibles tanto con Flow Builder como con Paywall Builder."
---
Adapty iOS SDK 4.0 introduce los flows y renombra las APIs de paywall en consecuencia. Las nuevas APIs funcionan tanto con el nuevo Flow Builder como con el Paywall Builder existente — no es necesario realizar ningún cambio de configuración en el Adapty Dashboard.
## Referencia rápida \{#quick-reference\}
| v3 | v4 |
|---|---|
| `Adapty.getPaywall(placementId:locale:)` | `Adapty.getFlow(placementId:)` |
| `AdaptyUI.getPaywallConfiguration(forPaywall:)` | `AdaptyUI.getFlowConfiguration(forFlow:locale:)` |
| `Adapty.getPaywallProducts(paywall:)` | `Adapty.getPaywallProducts(flow:)` |
| `Adapty.logShowPaywall(_:)` | `Adapty.logShowFlow(_:)` |
| `AdaptyPaywallController` | `AdaptyFlowController` |
| `AdaptyPaywallControllerDelegate` | `AdaptyFlowControllerDelegate` |
| `AdaptyUI.paywallController(with:delegate:)` | `AdaptyUI.flowController(with:delegate:)` |
| `.paywall()` (modificador SwiftUI) | `.flow()` |
| `AdaptyPaywallView` | `AdaptyFlowView` |
| `didFailRenderingWith:` / `didFailRendering:` | `didReceiveError:` |
| `didFinishPurchase` (opcional, se cierra automáticamente al completarse) | `didFinishPurchase` (obligatorio, sin cierre automático) |
| Productos del paquete `Adapty_KidsMode` / `AdaptyUI_KidsMode` | Trait de paquete `KidsMode` |
| `Adapty.updateAttribution(_:source:)` (`source: String`) | `Adapty.updateAttribution(_:source:)` (`source: AdaptyAttributionSource`) |
| `Adapty.setIntegrationIdentifier(key:value:)` | `Adapty.setIntegrationIdentifier(_:)` (`AdaptyIntegrationIdentifier`) |
## Versión mínima de iOS \{#minimum-ios-version\}
Adapty iOS SDK 4.0 eleva el objetivo mínimo de despliegue de iOS 13.0 a **iOS 15.0**. Establece el iOS Deployment Target de tu proyecto en 15.0 o superior antes de actualizar.
## Instalación: CocoaPods ya no está soportado \{#installation-cocoapods-no-longer-supported\}
El SDK de Adapty para iOS 4.0 elimina el soporte de CocoaPods. Instala el SDK con [Swift Package Manager](sdk-installation-ios#install-adapty-sdk).
Si tu proyecto todavía usa CocoaPods, elimina los pods `Adapty` y `AdaptyUI` de tu `Podfile`, ejecuta `pod install` para limpiarlos y luego añade el paquete en Xcode desde **File → Add Package Dependency** usando `https://github.com/adaptyteam/AdaptySDK-iOS.git`.
## Kids Mode: productos separados reemplazados por un rasgo de paquete \{#kids-mode-separate-products-replaced-by-a-package-trait\}
En v3, activabas el [Kids Mode](kids-mode) seleccionando los productos de paquete separados **Adapty_KidsMode** y **AdaptyUI_KidsMode** y renombrando tus imports. En v4.0, estos productos han sido eliminados. Kids Mode es ahora un rasgo de paquete Swift llamado `KidsMode` en el paquete Adapty normal — al activarlo, se eliminan IDFA y AdSupport de todo el SDK en tiempo de compilación.
Para migrar:
1. En la ventana **Choose Package Products**, selecciona los productos regulares **Adapty** y **AdaptyUI** en lugar de **Adapty_KidsMode** y **AdaptyUI_KidsMode**.
2. Habilita el trait `KidsMode`. En Xcode 26.4 o posterior, actívalo para la dependencia AdaptySDK-iOS en la vista **Package Dependencies** de tu proyecto. Si añades Adapty como dependencia en `Package.swift` (requiere `swift-tools-version` 6.1 o posterior), actívalo ahí:
```swift showLineNumbers title="Package.swift"
.package(
url: "https://github.com/adaptyteam/AdaptySDK-iOS.git",
from: "4.0.0",
traits: ["KidsMode"]
)
```
3. Vuelve a cambiar tus imports a los módulos normales:
```diff showLineNumbers
- import Adapty_KidsMode
- import AdaptyUI_KidsMode
+ import Adapty
+ import AdaptyUI
```
:::note
Las versiones de Xcode anteriores a la 26.4 no pueden activar traits para un proyecto de Xcode desde la interfaz. En ese caso, añade un pequeño paquete Swift local que dependa de Adapty con el trait `KidsMode` activado, y haz que el target de tu app dependa de ese paquete.
:::
## APIs eliminadas \{#removed-apis\}
- **`Adapty.getPaywallProductsWithoutDeterminingOffer(paywall:)`** — eliminada. Todos los productos incluyen ahora información sobre la oferta, por lo que el paso de elegibilidad separado ya no es necesario.
- **`AdaptyPaywallProductWithoutDeterminingOffer`** — eliminada. Los callbacks que antes pasaban este tipo (como `didSelectProduct`) ahora pasan `AdaptyPaywallProduct`.
## Compras in-app promocionadas en App Store temporalmente eliminadas \{#app-store-promoted-in-app-purchases-temporarily-removed\}
Como parte de la migración a StoreKit 2, el SDK de Adapty para iOS 4.0 elimina el soporte para las compras in-app promocionadas en App Store. El método delegado `shouldAddStorePayment(for:)` y el tipo `AdaptyDeferredProduct` que recibe no están disponibles en la versión 4.0.
:::warning
Esta eliminación es temporal: el soporte para compras in-app promocionadas volverá en una versión posterior de la rama 4.x. Si tu app depende de las compras in-app promocionadas, mantente en el SDK de iOS 3.x hasta que el soporte regrese.
:::
## Obtener paywalls \{#fetching-paywalls\}
### getPaywall + getPaywallConfiguration → getFlow + getFlowConfiguration
Los tipos devueltos cambian de `AdaptyPaywall` / `AdaptyUI.PaywallConfiguration` a `AdaptyFlow` / `AdaptyUI.FlowConfiguration`. El parámetro `locale` deja de estar en la llamada de obtención y pasa a `getFlowConfiguration`:
```diff showLineNumbers
- let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en")
- let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall)
+ let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID")
+ let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow, locale: "en")
```
### getPaywallProducts(paywall:) → getPaywallProducts(flow:)
`getPaywallProducts` ahora recibe un `AdaptyFlow` devuelto por `Adapty.getFlow`:
```diff showLineNumbers
- let products = try await Adapty.getPaywallProducts(paywall: paywall)
+ let products = try await Adapty.getPaywallProducts(flow: flow)
```
## Seguimiento de vistas de paywall \{#tracking-paywall-views\}
### logShowPaywall(_:) → logShowFlow(_:)
`logShowPaywall` ha sido renombrado a `logShowFlow` y ahora recibe un `AdaptyFlow` en lugar de un `AdaptyPaywall`. El evento sigue registrándose contra la misma variación, por lo que las métricas de funnel y de prueba A/B existentes seguirán funcionando sin cambios en el dashboard.
```diff showLineNumbers
- try await Adapty.logShowPaywall(paywall)
+ try await Adapty.logShowFlow(flow)
```
Al igual que en v3, no es necesario llamar a este método al mostrar flows o paywalls renderizados por el [Flow Builder](adapty-flow-builder) o el [Paywall Builder](adapty-paywall-builder) — Adapty registra esas vistas automáticamente.
## didFinishPurchase ahora es obligatorio \{#didfinishpurchase-is-now-required\}
En v3, `didFinishPurchase` era opcional: si no lo implementabas, el paywall se cerraba automáticamente tras una compra exitosa. En v4.0, esta implementación de cierre automático se ha eliminado para que un flow pueda continuar después de una compra exitosa — por ejemplo, para mostrar las pantallas restantes de tu flow. Ahora tú decides qué ocurre después de una compra: cerrar la pantalla o no hacer nada para dejar que el flow continúe.
- **UIKit**: los que implementen `AdaptyFlowControllerDelegate` deben implementar `didFinishPurchase` — ya no tiene una implementación por defecto.
- **SwiftUI**: el closure `didFinishPurchase` de `.flow(...)` y `AdaptyFlowView(...)` ahora es obligatorio (no opcional), igual que `didFailPurchase` y `didFinishRestore`.
Para mantener el comportamiento de v3, cierra la pantalla tú mismo:
```swift showLineNumbers title="Swift"
func flowController(
_ controller: AdaptyFlowController,
didFinishPurchase product: AdaptyPaywallProduct,
purchaseResult: AdaptyPurchaseResult
) {
if !purchaseResult.isPurchaseCancelled {
controller.dismiss(animated: true)
}
}
```
## UIKit \{#uikit\}
### AdaptyPaywallController → AdaptyFlowController
Renombra el tipo de controlador y el método factory:
```diff showLineNumbers
- let controller = try AdaptyUI.paywallController(
- with: paywallConfiguration,
- delegate: self
- )
+ let controller = try AdaptyUI.flowController(
+ with: flowConfiguration,
+ delegate: self
+ )
```
### AdaptyPaywallControllerDelegate → AdaptyFlowControllerDelegate
Renombra el protocolo y actualiza cada firma de método. Ten en cuenta que `didSelectProduct` ahora recibe `AdaptyPaywallProduct` en lugar del eliminado `AdaptyPaywallProductWithoutDeterminingOffer`, y `didFinishPurchase` [ahora debe implementarse](#didfinishpurchase-is-now-required) — ya no tiene una implementación predeterminada.
```diff showLineNumbers
- class YourClass: AdaptyPaywallControllerDelegate {
+ class YourClass: AdaptyFlowControllerDelegate {
- func paywallControllerDidAppear(_ controller: AdaptyPaywallController) { }
+ func flowControllerDidAppear(_ controller: AdaptyFlowController) { }
- func paywallControllerDidDisappear(_ controller: AdaptyPaywallController) { }
+ func flowControllerDidDisappear(_ controller: AdaptyFlowController) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didPerform action: AdaptyUI.Action) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didPerform action: AdaptyUI.Action) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didSelectProduct product: AdaptyPaywallProduct) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didStartPurchase product: AdaptyPaywallProduct) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didStartPurchase product: AdaptyPaywallProduct) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFinishPurchase product: AdaptyPaywallProduct,
- purchaseResult: AdaptyPurchaseResult) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFinishPurchase product: AdaptyPaywallProduct,
+ purchaseResult: AdaptyPurchaseResult) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailPurchase product: AdaptyPaywallProduct,
- error: AdaptyError) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFailPurchase product: AdaptyPaywallProduct,
+ error: AdaptyError) { }
- func paywallControllerDidStartRestore(_ controller: AdaptyPaywallController) { }
+ func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFinishRestoreWith profile: AdaptyProfile) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFinishRestoreWith profile: AdaptyProfile) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailRestoreWith error: AdaptyError) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFailRestoreWith error: AdaptyError) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailRenderingWith error: AdaptyUIError) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didReceiveError error: AdaptyUIError) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFailLoadingProductsWith error: AdaptyError) -> Bool { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFailLoadingProductsWith error: AdaptyError) -> Bool { }
- func paywallController(_ controller: AdaptyPaywallController,
- didPartiallyLoadProducts failedIds: [String]) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didPartiallyLoadProducts failedIds: [String]) { }
- func paywallController(_ controller: AdaptyPaywallController,
- didFinishWebPaymentNavigation product: AdaptyPaywallProduct?,
- error: AdaptyError?) { }
+ func flowController(_ controller: AdaptyFlowController,
+ didFinishWebPaymentNavigation product: AdaptyPaywallProduct?,
+ error: AdaptyError?) { }
}
```
## SwiftUI \{#swiftui\}
### Modificador `.paywall()` → `.flow()` \{#paywall-modifier--flow\}
Renombra el modificador, actualiza el nombre del parámetro de configuración y añade el closure `didFinishPurchase` [ahora obligatorio](#didfinishpurchase-is-now-required):
```diff showLineNumbers
@State var flowPresented = false // rename freely — the variable name is your choice
var body: some View {
Text("Hello, AdaptyUI!")
- .paywall(
+ .flow(
isPresented: $flowPresented,
- paywallConfiguration: paywallConfiguration,
+ flowConfiguration: flowConfiguration,
+ didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ },
didFailPurchase: { product, error in /* handle the error */ },
didFinishRestore: { profile in /* check access level and dismiss */ },
didFailRestore: { error in /* handle the error */ },
- didFailRendering: { error in flowPresented = false }
+ didReceiveError: { error in flowPresented = false }
)
}
```
El callback renombrado se activa para los mismos errores de renderizado que `didFailRendering`, más los nuevos errores en tiempo de ejecución del script del flow (excepciones de JavaScript con código `AdaptyUIError` `4105` — `.jsException`). Los cuerpos de los handlers existentes no necesitan cambios en el código: solo hay que renombrar el parámetro.
### AdaptyPaywallView → AdaptyFlowView
Renombra la vista, actualiza el parámetro de configuración, añade el closure `didFinishPurchase` [ahora obligatorio](#didfinishpurchase-is-now-required), y actualiza cualquier closure `didSelectProduct` — ahora recibe `AdaptyPaywallProduct` en lugar del eliminado `AdaptyPaywallProductWithoutDeterminingOffer`:
```diff showLineNumbers
- AdaptyPaywallView(
- paywallConfiguration: paywallConfiguration,
- didSelectProduct: { product: AdaptyPaywallProductWithoutDeterminingOffer in /* handle */ },
+ AdaptyFlowView(
+ flowConfiguration: flowConfiguration,
+ didSelectProduct: { product: AdaptyPaywallProduct in /* handle */ },
+ didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ },
didFailPurchase: { product, error in /* handle the error */ },
didFinishRestore: { profile in /* check access level and dismiss */ },
didFailRestore: { error in /* handle the error */ },
- didFailRendering: { error in /* handle the error */ }
+ didReceiveError: { error in /* handle the error */ }
)
```
## Recursos personalizados de AdaptyUI \{#adaptyui-custom-assets\}
### AdaptyUICustomVideoAsset
Hay dos cambios que afectan a todos los puntos de llamada existentes:
- `.player` ahora acepta `AVPlayer` en lugar de `AVQueuePlayer`.
- Todos los casos han ganado un parámetro adicional al final: `resolution: CGSize?`. Pasa `nil` para mantener el comportamiento actual, o pasa el tamaño en píxeles real para que el reproductor pueda reservar espacio de layout (relación de aspecto = `width / height`) antes de que cargue el vídeo.
```diff showLineNumbers
- case file(url: URL, preview: AdaptyUICustomImageAsset?)
- case remote(url: URL, preview: AdaptyUICustomImageAsset?)
- case player(item: AVPlayerItem, player: AVQueuePlayer, preview: AdaptyUICustomImageAsset?)
+ case file(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?)
+ case remote(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?)
+ case player(item: AVPlayerItem, player: AVPlayer, preview: AdaptyUICustomImageAsset?, resolution: CGSize?)
```
## Identificadores de atribución e integración \{#attribution-and-integration-identifiers\}
### updateAttribution(_:source:)
El parámetro `source` cambia de `String` al nuevo tipo `AdaptyAttributionSource`, y el anteriormente anidado `AdaptyProfile.AttributionSource` se renombra al nivel superior `AdaptyAttributionSource`. Usa una de las fuentes predefinidas, o pasa un literal de cadena para cualquier otra fuente: `AdaptyAttributionSource` conforma con `ExpressibleByStringLiteral`, por lo que las llamadas con literales de cadena existentes siguen compilando.
```diff showLineNumbers
- try await Adapty.updateAttribution(attribution, source: "adjust")
+ try await Adapty.updateAttribution(attribution, source: .adjust)
```
Fuentes predefinidas: `.appleAds`, `.adjust`, `.appsflyer`, `.branch`, `.tenjin`. Si guardas la fuente en una variable `String`, envuélvela así: `AdaptyAttributionSource(rawValue: yourSource)`.
### setIntegrationIdentifier(_:)
`setIntegrationIdentifier(key:value:)` es reemplazado por un método variádico que acepta uno o más valores de tipo `AdaptyIntegrationIdentifier`. Usa los métodos de fábrica predefinidos en lugar de claves de cadena sin formato:
```diff showLineNumbers
- try await Adapty.setIntegrationIdentifier(key: "appsflyer_id", value: uid)
+ try await Adapty.setIntegrationIdentifier(.appsflyerId(uid))
```
Puedes establecer varios identificadores en una sola llamada:
```swift showLineNumbers
try await Adapty.setIntegrationIdentifier(
.appsflyerId(uid),
.adjustDeviceId(adid)
)
```
Reemplaza cada cadena de clave antigua por su método de fábrica:
| clave v3 | factory v4 |
|---|---|
| `"adjust_device_id"` | `.adjustDeviceId(_:)` |
| `"airbridge_device_id"` | `.airbridgeDeviceId(_:)` |
| `"amplitude_user_id"` | `.amplitudeUserId(_:)` |
| `"amplitude_device_id"` | `.amplitudeDeviceId(_:)` |
| `"appmetrica_device_id"` | `.appmetricaDeviceId(_:)` |
| `"appmetrica_profile_id"` | `.appmetricaProfileId(_:)` |
| `"appsflyer_id"` | `.appsflyerId(_:)` |
| `"branch_id"` | `.branchId(_:)` |
| `"facebook_anonymous_id"` | `.facebookAnonymousId(_:)` |
| `"firebase_app_instance_id"` | `.firebaseAppInstanceId(_:)` |
| `"mixpanel_user_id"` | `.mixpanelUserId(_:)` |
| `"one_signal_subscription_id"` | `.oneSignalSubscriptionId(_:)` |
| `"one_signal_player_id"` | `.oneSignalPlayerId(_:)` |
| `"posthog_distinct_user_id"` | `.posthogDistinctUserId(_:)` |
| `"pushwoosh_hwid"` | `.pushwooshHWID(_:)` |
| `"tenjin_analytics_installation_id"` | `.tenjinAnalyticsInstallationId(_:)` |
---
# File: migration-to-ios-315
---
---
title: "Migrar el SDK de Adapty para iOS a v3.15"
description: "Migra al SDK de Adapty para iOS v3.15 para mejorar el rendimiento y acceder a nuevas funciones de monetización."
---
Si usas [Paywall Builder](adapty-paywall-builder) en [modo Observer](observer-vs-full-mode), a partir del SDK de iOS 3.15 necesitas implementar un nuevo método `observerModeDidInitiateRestorePurchases(onStartRestore:onFinishRestore:)`. Este método te da más control sobre la lógica de restauración, permitiéndote gestionar la restauración de compras en tu propio flow. Para más detalles sobre la implementación, consulta [Mostrar paywalls de Paywall Builder en modo Observer](ios-present-paywall-builder-paywalls-in-observer-mode).
```diff showLineNumbers
func observerMode(didInitiatePurchase product: AdaptyPaywallProduct,
onStartPurchase: @escaping () -> Void,
onFinishPurchase: @escaping () -> Void) {
// use the product object to handle the purchase
// use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase
}
+ func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void,
+ onFinishRestore: @escaping () -> Void) {
+ // use the onStartRestore and onFinishRestore callbacks to notify AdaptyUI about the process of the restore
+ }
```
---
# File: migration-to-ios-sdk-34
---
---
title: "Migrar el SDK de Adapty para iOS a la v. 3.4"
description: "Migra al SDK de Adapty para iOS v3.4 para obtener mejor rendimiento y nuevas funciones de monetización."
---
El SDK de Adapty 3.4.0 es una versión principal que introduce mejoras que requieren pasos de migración por tu parte.
## Actualizar la activación del SDK \{#update-adapty-sdk-activation\}
### Durante el login/registro \{#during-loginsignup\}
Si identificas a los usuarios después de que arranque la app (por ejemplo, tras iniciar sesión o registrarse), usa el método `identify` para establecer su customer user ID.
- Si **no has usado este customer user ID antes**, Adapty lo vinculará automáticamente al perfil actual.
- Si **ya has usado este customer user ID para identificar al usuario antes**, Adapty cambiará a trabajar con el perfil asociado a ese customer user ID.
:::important
Los customer user IDs deben ser únicos para cada usuario. Si hardcodeas el valor del parámetro, todos los usuarios se considerarán como uno solo.
:::
Espera a que `identify` se complete (en su callback `onSuccess`) antes de llamar a otros métodos del SDK. Las llamadas concurrentes pueden acabar en el perfil anónimo. Consulta [Orden de llamadas en el SDK de Kotlin Multiplatform](kmp-sdk-call-order).
```kotlin showLineNumbers
Adapty.identify("YOUR_USER_ID") // Único para cada usuario
.onSuccess {
// identify exitoso
}
.onError { error ->
// gestionar el error
}
```
### Durante la activación del SDK \{#during-the-sdk-activation\}
Si ya conoces el customer user ID cuando activas el SDK, puedes enviarlo en el método `activate` en lugar de llamar a `identify` por separado.
Si conoces un customer user ID pero solo lo estableces después de la activación, eso significa que, al activarse, Adapty creará un nuevo perfil anónimo y cambiará al existente solo cuando llames a `identify`.
Puedes pasar un customer user ID existente (uno que hayas usado antes) o uno nuevo. Si pasas uno nuevo, el nuevo perfil creado en la activación se vinculará automáticamente al customer user ID.
:::note
Por defecto, la creación de perfiles anónimos no afecta a los dashboards de análisis, porque las instalaciones se cuentan en función de los ID de dispositivo.
Un ID de dispositivo representa una única instalación de la app desde el store en un dispositivo y solo se regenera tras reinstalar la app.
No depende de si es una primera instalación o una repetida, ni de si se usa un customer user ID existente.
Crear un perfil (al activar el SDK o al cerrar sesión), iniciar sesión o actualizar la app sin reinstalarla no genera eventos de instalación adicionales.
Si quieres contar las instalaciones en función de usuarios únicos en lugar de dispositivos, ve a **App settings** y configura [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```kotlin showLineNumbers
AdaptyConfig.Builder("PUBLIC_SDK_KEY")
.withCustomerUserId("user123") // Los customer user IDs deben ser únicos para cada usuario. Si hardcodeas el valor del parámetro, todos los usuarios se considerarán como uno solo.
.build()
```
### Cerrar sesión de usuarios \{#log-users-out\}
Si tienes un botón para cerrar la sesión de los usuarios, usa el método `logout`.
:::important
Cerrar la sesión de los usuarios crea un nuevo perfil anónimo para el usuario.
:::
```kotlin showLineNumbers
Adapty.logout()
.onSuccess {
// cierre de sesión exitoso
}
.onError { error ->
// gestionar el error
}
```
:::info
Para volver a iniciar sesión en la app, usa el método `identify`.
:::
### Permitir compras sin inicio de sesión \{#allow-purchases-without-login\}
Si tus usuarios pueden realizar compras tanto antes como después de iniciar sesión en tu app, debes asegurarte de que mantendrán el acceso una vez que inicien sesión:
1. Cuando un usuario sin sesión iniciada realiza una compra, Adapty la vincula a su ID de perfil anónimo.
2. Cuando el usuario inicia sesión en su cuenta, Adapty pasa a trabajar con su perfil identificado.
- Si es un nuevo customer user ID (por ejemplo, la compra se realizó antes del registro), Adapty asigna el customer user ID al perfil actual, por lo que todo el historial de compras se mantiene.
- Si es un customer user ID existente (el customer user ID ya está vinculado a un perfil), debes obtener el nivel de acceso real tras el cambio de perfil. Puedes llamar a [`getProfile`](kmp-check-subscription-status) justo después de la identificación, o [escuchar las actualizaciones del perfil](kmp-check-subscription-status) para que los datos se sincronicen automáticamente.
## Próximos pasos \{#next-steps\}
¡Enhorabuena! Has implementado la lógica de pago in-app en tu app. ¡Te deseamos lo mejor con la monetización de tu app!
Para sacar aún más partido a Adapty, puedes explorar estos temas:
- [**Pruebas**](troubleshooting-test-purchases): Asegúrate de que todo funciona correctamente
- [**Integraciones**](configuration): Integra con servicios de atribución de marketing y análisis en una sola línea de código
- [**Establecer atributos de perfil personalizados**](kmp-setting-user-attributes): Añade atributos personalizados a los perfiles de usuario y crea segmentos para lanzar pruebas A/B o mostrar diferentes paywalls a distintos usuarios
---
# File: adapty-sdk-integration-skill-kmp
---
---
title: "Integra Adapty en tu app Kotlin Multiplatform con el skill de integración del SDK"
description: "Usa el skill adapty-sdk-integration para integrar el SDK de Adapty en tu app Kotlin Multiplatform de principio a fin con tu herramienta de codificación con IA."
---
La [skill adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatiza la integración de Adapty de extremo a extremo: configuración del dashboard, instalación del SDK, paywall y verificación por etapas. Detecta tu plataforma automáticamente y obtiene la documentación de Adapty relevante en cada etapa.
**Herramientas compatibles**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Para instalarla, elige el formulario para tu herramienta. La lista completa está en el [README de la skill](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex u otra herramienta** — usa la [CLI de skills](https://skills.sh) (ten en cuenta que las skills instaladas de esta forma no se actualizan automáticamente):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
También puedes clonar el repositorio y copiar `skills/adapty-sdk-integration/` en el directorio de skills de tu herramienta.
Tras la instalación, ejecuta la skill en tu proyecto:
```
/adapty-sdk-integration
```
La skill hace algunas preguntas de configuración y luego te guía por la configuración del dashboard, la instalación del SDK, el paywall y la verificación.
:::important
La funcionalidad está en beta. Si se detiene o se comporta de forma inesperada, sigue la [guía de integración paso a paso](adapty-cursor-kmp) — te guía a través de cada etapa con la documentación correcta.
:::
La [skill adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatiza la integración de Adapty de extremo a extremo: configuración del dashboard, instalación del SDK, paywall y verificación por etapas. Detecta tu plataforma automáticamente y obtiene la documentación de Adapty relevante en cada etapa.
**Herramientas compatibles**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Para instalarla, elige el formulario para tu herramienta. La lista completa está en el [README de la skill](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex u otra herramienta** — usa la [CLI de skills](https://skills.sh) (ten en cuenta que las skills instaladas de esta forma no se actualizan automáticamente):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
También puedes clonar el repositorio y copiar `skills/adapty-sdk-integration/` en el directorio de skills de tu herramienta.
Tras la instalación, ejecuta la skill en tu proyecto:
```
/adapty-sdk-integration
```
La skill hace algunas preguntas de configuración y luego te guía por la configuración del dashboard, la instalación del SDK, el paywall y la verificación.
---
# File: adapty-cursor-kmp
---
---
title: "Integra Adapty en tu app de Kotlin Multiplatform con ayuda de IA"
description: "Una guía paso a paso para integrar Adapty en tu app de Kotlin Multiplatform usando Cursor, Context7, ChatGPT, Claude u otras herramientas de IA."
---
Esta guía te lleva paso a paso por la integración de Adapty en tu app Kotlin Multiplatform con una herramienta de codificación con IA: le proporcionas la documentación correcta de Adapty en el orden correcto.
For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command.
## Antes de empezar: configuración del dashboard \{#before-you-start-dashboard-setup\}
Adapty requiere algo de configuración en el dashboard antes de escribir código con el SDK. Puedes hacerlo con una skill interactiva de LLM o manualmente desde el Dashboard.
### Enfoque con skill (recomendado) \{#skill-approach-recommended\}
El skill de Adapty CLI permite que tu LLM configure tu app, productos, niveles de acceso, paywalls y placements directamente, sin necesidad de abrir el Dashboard en cada paso. Solo tienes que [conectar tus stores](integrate-payments) en el Dashboard.
```
npx skills add adaptyteam/adapty-cli --skill adapty-cli
```
Una vez añadido el skill, ejecuta `/adapty-cli` en tu agente. Te guiará paso a paso, incluyendo cuándo abrir el Dashboard para conectar tus stores.
### Enfoque desde el dashboard
Si prefieres configurarlo todo de forma manual, esto es lo que necesitas antes de escribir código. Tu LLM no puede buscar los valores del dashboard por ti — tendrás que proporcionarlos tú mismo.
1. **Conecta tus app stores**: En el Adapty Dashboard, ve a **App settings → General**. Conecta tanto App Store como Google Play si tu app KMP apunta a ambas plataformas. Esto es necesario para que las compras funcionen.
[Conecta los app stores](integrate-payments)
2. **Copia tu clave SDK pública**: En el Adapty Dashboard, ve a **App settings → General** y busca la sección **API keys**. En el código, es la cadena que pasas al constructor de configuración de Adapty.
3. **Crea al menos un producto**: En el Adapty Dashboard, ve a la página **Products**. No haces referencia a los productos directamente en el código — Adapty los entrega a través de paywalls.
[Añadir productos](quickstart-products)
4. **Crea un paywall y un placement**: En el Adapty Dashboard, crea un paywall en la página **Paywalls** y asígnalo a un placement en la página **Placements**. En el código, el ID del placement es el string que pasas a `Adapty.getPaywall("YOUR_PLACEMENT_ID")`.
[Crear un paywall](quickstart-paywalls)
5. **Configura los niveles de acceso**: En el Adapty Dashboard, configúralos por producto en la página **Products**. En el código, la cadena que se comprueba es `profile.accessLevels["premium"]?.isActive`. El nivel de acceso `premium` predeterminado funciona para la mayoría de las apps. Si los usuarios de pago tienen acceso a distintas funcionalidades según el producto (por ejemplo, un plan `basic` frente a un plan `pro`), [crea niveles de acceso adicionales](assigning-access-level-to-a-product) antes de empezar a programar.
:::tip
Una vez que tengas los cinco, estarás listo para escribir código. Dile a tu LLM: "Mi clave SDK pública es X, mi placement ID es Y" para que pueda generar el código correcto de inicialización y obtención de paywalls.
:::
### Configura cuando estés listo \{#set-up-when-ready\}
No son obligatorios para empezar a programar, pero los necesitarás a medida que tu integración madure:
- **Pruebas A/B**: Configúralas en la página **Placements**. No se necesitan cambios de código.
[Pruebas A/B](ab-tests)
- **Paywalls y placements adicionales**: Añade más llamadas `getPaywall` con diferentes IDs de placement.
- **Integraciones de analíticas**: Configúralas en la página **Integrations**. La configuración varía según la integración. Consulta [integraciones de analíticas](analytics-integration) e [integraciones de atribución](attribution-integration).
## Proporciona la documentación de Adapty a tu LLM \{#feed-adapty-docs-to-your-llm\}
### Usa Context7 (recomendado)
[Context7](https://context7.com) es un servidor MCP que da a tu LLM acceso directo a la documentación actualizada de Adapty. Tu LLM obtiene automáticamente la documentación adecuada según lo que preguntes, sin necesidad de pegar URLs manualmente.
Context7 funciona con **Cursor**, **Claude Code**, **Windsurf** y otras herramientas compatibles con MCP. Para configurarlo, ejecuta:
```
npx ctx7 setup
```
Esto detecta tu editor y configura el servidor Context7. Para la configuración manual, consulta el [repositorio de Context7 en GitHub](https://github.com/upstash/context7).
Una vez configurado, haz referencia a la librería de Adapty en tus prompts:
```
Use the adaptyteam/adapty-docs library to look up how to install the Kotlin Multiplatform SDK
```
:::warning
Aunque Context7 elimina la necesidad de pegar links de documentación manualmente, el orden de implementación importa. Sigue el [paso a paso de implementación](#implementation-walkthrough) de principio a fin para asegurarte de que todo funciona.
:::
### Usa documentación en texto plano
Puedes acceder a cualquier documento de Adapty en texto plano Markdown. Añade `.md` al final de su URL, o haz clic en **Copy for LLM** bajo el título del artículo. Por ejemplo: [adapty-cursor-kmp.md](https://adapty.io/docs/es/adapty-cursor-kmp.md).
Cada etapa del [recorrido de implementación](#implementation-walkthrough) a continuación incluye un bloque "Send this to your LLM" con enlaces `.md` para pegar.
Para obtener más documentación a la vez, consulta los [archivos de índice y subconjuntos por plataforma](#plain-text-doc-index-files) a continuación.
## Guía de implementación paso a paso \{#implementation-walkthrough\}
El resto de esta guía recorre la integración de Adapty en orden de implementación. Cada etapa incluye la documentación que debes enviar a tu LLM, qué deberías ver al terminar y los problemas más comunes.
### Planifica tu integración \{#plan-your-integration\}
Antes de escribir código, pídele a tu LLM que analice tu proyecto y elabore un plan de implementación. Si tu herramienta de IA tiene un modo de planificación (como el modo plan de Cursor o Claude Code), úsalo para que el LLM pueda leer tanto la estructura de tu proyecto como la documentación de Adapty antes de generar cualquier código.
Indícale a tu LLM qué enfoque utilizas para las compras, ya que esto determina qué guías debe seguir:
- [**Adapty Paywall Builder**](adapty-paywall-builder): Creas paywalls en el editor no-code de Adapty y el SDK los renderiza automáticamente.
- [**Paywalls creados manualmente**](kmp-making-purchases): Construyes tu propia interfaz de paywall en código, pero sigues usando Adapty para obtener productos y gestionar compras.
- [**Modo Observer**](observer-vs-full-mode): Mantienes tu infraestructura de compras existente y usas Adapty solo para analíticas e integraciones.
¿No sabes cuál elegir? Lee la [tabla comparativa en la guía de inicio rápido](kmp-quickstart-paywalls).
### Instalar y configurar el SDK \{#install-and-configure-the-sdk\}
Añade la dependencia del SDK de Adapty mediante Gradle y actívalo con tu clave pública del SDK. Esta es la base: sin esto, nada más funciona.
**Guía:** [Instalar y configurar el SDK de Adapty](sdk-installation-kotlin-multiplatform)
Envía esto a tu LLM:
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/es/sdk-installation-kotlin-multiplatform.md
```
:::tip[Checkpoint]
- **Esperado:** La app compila y se ejecuta. Logcat (Android) o la consola de Xcode (iOS) muestra el log de activación de Adapty.
- **Problema frecuente:** "Public API key is missing" → comprueba que has reemplazado el placeholder con tu clave real desde App settings.
:::
### Mostrar paywalls y gestionar compras \{#show-paywalls-and-handle-purchases\}
Obtén un paywall por ID de placement, muéstralo y gestiona los eventos de compra. Las guías que necesitas dependen de cómo gestiones las compras.
Prueba cada compra en el sandbox a medida que avanzas — no esperes hasta el final. Consulta [Probar compras en sandbox](test-purchases-in-sandbox) para las instrucciones de configuración.
Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen conexiones a internet inestables, considera usar `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero tendrán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.
El SDK de Adapty almacena flows y paywalls localmente en dos capas: la caché de actualización regular descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtenerlos más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente y asegurar la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo de espera especificado en `loadTimeout`, ya que la operación puede consistir en diferentes solicitudes internamente.
Para Kotlin Multiplatform: puedes crear una `Duration` con funciones de extensión como `5.seconds`, donde `.seconds` proviene de `kotlin.time.Duration.Companion.seconds`.
| Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :---------- | | Flow | Un objeto `AdaptyFlow` que contiene el placement, los identificadores (`instanceIdentity`, `variationId`), el nombre, las variaciones de paywall (`paywalls` — una lista de `AdaptyFlowPaywall`) y los Remote Configs (`remoteConfigs` — una lista con una entrada por idioma). Para obtener los productos reales y usarlos en precarga, UI personalizada o comprobaciones programáticas, llama a `getPaywallProducts(flow)`. | ## Obtener la configuración de la vista \{#fetch-the-view-configuration\} Una vez obtenido el flow o el paywall, carga su configuración de vista y crea la vista en un solo paso con el método `createFlowView`. No hay ningún indicador separado que comprobar: si el placement fue diseñado en el **Flow Builder** (un flow) o en el **Paywall Builder** (un paywall), `createFlowView` devuelve la vista lista para presentarse. Si el placement es un paywall personalizado sin interfaz de Builder, `createFlowView` devuelve un `AdaptyResult.Error` — [trátalo como un paywall de Remote Config](present-remote-config-paywalls-kmp). :::important Asegúrate de activar el botón **Show on device** en el Flow Builder. Si esta opción no está activada, la configuración de la vista no estará disponible para recuperarla. ::: ```kotlin showLineNumbers AdaptyUI.createFlowView( flow = flow, loadTimeout = 5.seconds, preloadProducts = true ).onSuccess { view -> // use view }.onError { error -> // the flow has no view configured, or view creation failed } ``` | Parámetro | Presencia | Descripción | | :--------------------------- | :------------- | :----------------------------------------------------------- | | **flow** | obligatorio | Un objeto `AdaptyFlow` obtenido mediante `Adapty.getFlow`. | | **loadTimeout** | opcional | Este valor limita el tiempo de espera para este método. Si se alcanza el límite, se devolverán datos en caché o el fallback local. Ten en cuenta que en casos excepcionales este método puede exceder ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede estar compuesta por diferentes solicitudes internamente. Puedes usar funciones de extensión como `5.seconds` de `kotlin.time.Duration.Companion`. | | **preloadProducts** | opcional | Establécelo en `true` para precargar productos y mejorar el rendimiento. Cuando está activado, los productos se cargan de antemano, reduciendo el tiempo necesario para mostrar el flow o el paywall. | | **productPurchaseParams** | opcional | Un mapa de [`AdaptyProductIdentifier`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-product-identifier/) a [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). Úsalo para configurar parámetros de compra específicos, como ofertas personalizadas o parámetros de actualización de suscripción para productos individuales en el flow o el paywall. | :::note Si utilizas varios idiomas, aprende cómo añadir una [localización del Builder](add-paywall-locale-in-adapty-paywall-builder). ::: Una vez cargado, [presenta el flow o el paywall](kmp-present-paywalls). ## Obtén un flow o paywall para la audiencia predeterminada y accede más rápido \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} Por lo general, los flows y paywalls se obtienen casi de forma instantánea, así que no necesitas preocuparte por acelerar este proceso. Sin embargo, cuando tienes muchas audiencias y placements, y tus usuarios tienen una conexión a internet débil, obtener un flow o paywall puede tardar más de lo deseable. En esas situaciones, puede que quieras mostrar un flow o paywall predeterminado para garantizar una experiencia de usuario fluida en lugar de no mostrar nada. Para solucionar esto, puedes usar el método `getFlowForDefaultAudience`, que obtiene el flow o paywall del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el flow o paywall mediante el método `getFlow`, tal como se detalla en la sección [Obtener flow/paywall](#fetch-flowpaywall) anterior. :::warning Por qué recomendamos usar `getFlow` El método `getFlowForDefaultAudience` tiene algunos inconvenientes importantes: - **Posibles problemas de compatibilidad con versiones anteriores**: Si necesitas mostrar flows distintos según la versión de la app (la actual y versiones futuras), puedes encontrarte con dificultades. Tendrás que diseñar flows compatibles con la versión actual (heredada) o asumir que los usuarios con esa versión podrían tener problemas al renderizar ciertos flows. - **Pérdida de targeting**: Todos los usuarios verán el mismo flow diseñado para la audiencia **All Users**, lo que significa que pierdes la segmentación personalizada (incluida la basada en países, atribución de marketing o tus propios atributos personalizados). Si estás dispuesto a aceptar estas desventajas a cambio de una obtención más rápida de flows o paywalls, utiliza el método `getFlowForDefaultAudience` de la siguiente manera. De lo contrario, quédate con `getFlow` descrito [arriba](#fetch-flowpaywall). ::: ```kotlin showLineNumbers Adapty.getFlowForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { flow -> // the requested flow }.onError { error -> // handle the error } ``` | Parámetro | Presencia | Descripción | |---------|--------|-----------| | **placementId** | obligatorio | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **fetchPolicy** | predeterminado: `AdaptyPaywallFetchPolicy.Default` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si consideras que tus usuarios tienen una conexión a internet inestable, puedes usar `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo intermitente que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| ## Personaliza los recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu flow o paywall, implementa los recursos personalizados. Las imágenes y vídeos hero tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizados, seleccionas estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, debes [asignar un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. Aquí tienes un ejemplo de cómo puedes proporcionar recursos personalizados a través de un mapa: :::info El SDK de Kotlin Multiplatform solo admite recursos locales. Para contenido remoto, debes descargar y almacenar en caché los recursos localmente antes de usarlos como recursos personalizados. ::: ```kotlin showLineNumbers // Import generated Res class for accessing resources viewModelScope.launch { // Get URIs for bundled resources using Res.getUri() val heroImagePath = Res.getUri("files/images/hero_image.png") val demoVideoPath = Res.getUri("files/videos/demo_video.mp4") // Or read image as byte data val imageByteData = Res.readBytes("files/images/avatar.png") // Create custom assets map val customAssets: Mapopcional
predeterminado: `en`
|El identificador de la [localización del paywall](add-paywall-locale-in-adapty-paywall-builder). Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta es para el idioma y la segunda para la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | predeterminado: `AdaptyPaywallFetchPolicy.Default` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la aplicación y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché de actualización regular descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN sea inaccesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | predeterminado: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede agotar el tiempo de espera algo más tarde de lo especificado en `loadTimeout`, ya que la operación puede consistir en distintas peticiones internamente.
Para Kotlin Multiplatform: Puedes crear `TimeInterval` con funciones de extensión (como `5.seconds`, donde `.seconds` proviene de `import com.adapty.utils.seconds`), o `TimeInterval.seconds(5)`. Para no establecer ningún límite, usa `TimeInterval.INFINITE`.
| Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Un objeto [`AdaptyPaywall`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall/) con una lista de IDs de productos, el identificador del paywall, el Remote Config y varias otras propiedades. | ## Obtener la configuración de vista de un paywall creado con Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Asegúrate de activar el interruptor **Show on device** en el Paywall Builder. Si esta opción no está activada, la configuración de vista no estará disponible para recuperar. ::: Tras obtener el paywall, comprueba si incluye una `ViewConfiguration`, lo que indica que fue creado con Paywall Builder. Esto te indicará cómo mostrar el paywall. Si la `ViewConfiguration` está presente, trátalo como un paywall de Paywall Builder; de lo contrario, [trátalo como un paywall de Remote Config](present-remote-config-paywalls-kmp). Usa el método `createPaywallView` para cargar la configuración de la vista. ```kotlin showLineNumbers if (paywall.hasViewConfiguration) { AdaptyUI.createPaywallView( paywall = paywall, loadTimeout = 5.seconds, preloadProducts = true ).onSuccess { paywallView -> // use paywallView }.onError { error -> // handle the error } } else { // use your custom logic } ``` | Parámetro | Presencia | Descripción | | :--------------------------- | :------------- | :----------------------------------------------------------- | | **paywall** | requerido | Un objeto `AdaptyPaywall` para obtener un controlador para el paywall deseado. | | **loadTimeout** | opcional | Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el fallback local. Ten en cuenta que en casos excepcionales este método puede agotar el tiempo de espera ligeramente después de lo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes solicitudes internamente. Puedes usar funciones de extensión como `5.seconds` de `kotlin.time.Duration.Companion`. | | **preloadProducts** | opcional | Establece en `true` para precargar productos y mejorar el rendimiento. Cuando está activado, los productos se cargan de antemano, reduciendo el tiempo necesario para mostrar el paywall. | | **productPurchaseParams** | opcional | Un mapa de [`AdaptyProductIdentifier`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-product-identifier/) a [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). Úsalo para configurar parámetros de compra específicos, como ofertas personalizadas o parámetros de actualización de suscripción para productos individuales en el paywall. | :::note Si usas varios idiomas, aprende cómo añadir una [localización del Paywall Builder](add-paywall-locale-in-adapty-paywall-builder). ::: Una vez cargado, [muestra el paywall](kmp-present-paywalls). ## Obtén un paywall para la audiencia por defecto y cárgalo más rápido \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} Por lo general, los paywalls se cargan casi de inmediato, por lo que no necesitas preocuparte por acelerar este proceso. Sin embargo, cuando tienes numerosas audiencias y paywalls, y tus usuarios tienen una conexión a internet débil, la carga de un paywall puede tardar más de lo deseado. En esas situaciones, puede que quieras mostrar un paywall por defecto para garantizar una experiencia de usuario fluida en lugar de no mostrar ningún paywall. Para abordar esto, puedes usar el método `getPaywallForDefaultAudience`, que obtiene el paywall del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el paywall con el método `getPaywall`, tal como se detalla en la sección [Obtener información del paywall](#fetch-paywall-designed-with-paywall-builder) anterior. :::warning Por qué recomendamos usar `getPaywall` El método `getPaywallForDefaultAudience` tiene algunas desventajas importantes: - **Posibles problemas de compatibilidad con versiones anteriores**: Si necesitas mostrar diferentes paywalls para distintas versiones de la aplicación (actual y futuras), puedes encontrarte con dificultades. Tendrás que diseñar paywalls compatibles con la versión actual (heredada) o asumir que los usuarios con esa versión pueden tener problemas con paywalls que no se rendericen correctamente. - **Pérdida de targeting**: Todos los usuarios verán el mismo paywall diseñado para la audiencia **All Users**, lo que significa que pierdes la segmentación personalizada (incluyendo por países, atribución de marketing o tus propios atributos personalizados). Si estás dispuesto a aceptar estos inconvenientes para beneficiarte de una obtención más rápida del paywall, utiliza el método `getPaywallForDefaultAudience` como se indica a continuación. De lo contrario, sigue usando `getPaywall` descrito [anteriormente](#fetch-paywall-designed-with-paywall-builder). ::: ```kotlin showLineNumbers Adapty.getPaywallForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` | Parámetro | Presencia | Descripción | |---------|--------|-----------| | **placementId** | obligatorio | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **locale** |opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `AdaptyPaywallFetchPolicy.Default` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` para devolver los datos en caché si existen. En ese caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| ## Personalizar recursos \{#customize-assets\} Para personalizar las imágenes y vídeos de tu paywall, implementa los recursos personalizados. Las imágenes y vídeos hero tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizado, apuntas a estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de previsualización local mientras se carga una imagen principal remota. - Mostrar una imagen de previsualización antes de reproducir un vídeo. :::important Para usar esta función, actualiza el SDK de Adapty a la versión 3.7.0 o superior. ::: A continuación se muestra un ejemplo de cómo puedes proporcionar recursos personalizados mediante un mapa: :::info El SDK de Kotlin Multiplatform solo admite recursos locales. Para contenido remoto, debes descargar y almacenar en caché los recursos localmente antes de usarlos como recursos personalizados. ::: ```kotlin showLineNumbers // Import generated Res class for accessing resources viewModelScope.launch { // Get URIs for bundled resources using Res.getUri() val heroImagePath = Res.getUri("files/images/hero_image.png") val demoVideoPath = Res.getUri("files/videos/demo_video.mp4") // Or read image as byte data val imageByteData = Res.readBytes("files/images/avatar.png") // Create custom assets map val customAssets: Map
## El número de vistas del paywall es demasiado alto \{#the-paywall-view-number-is-too-big\}
**Problema**: El contador de vistas del paywall muestra el doble del número esperado.
**Motivo**: Es posible que estés llamando a `logShowPaywall` en tu código, lo que duplica el contador de vistas si estás usando el Paywall Builder. Para paywalls diseñados con el Paywall Builder, las analíticas se registran automáticamente, por lo que no es necesario usar este método.
**Solución**: Asegúrate de no estar llamando a `logShowPaywall` en tu código si estás usando el Paywall Builder.
---
# File: kmp-implement-paywalls-manually
---
---
title: "Implementar paywalls manualmente en el SDK de Kotlin Multiplatform"
description: "Aprende a implementar paywalls manualmente en tu app de Kotlin Multiplatform con el SDK de Adapty."
---
## Aceptar compras \{#accept-purchases\}
Si trabajas con paywalls que has implementado tú mismo, puedes delegar el manejo de compras a Adapty usando el método `makePurchase`. De esta forma, Adapty se encargará de todos los escenarios del usuario y tú solo tendrás que gestionar los resultados de la compra.
:::important
`makePurchase` funciona con productos creados en el Adapty Dashboard. Asegúrate de configurar los productos y las formas de recuperarlos en el dashboard siguiendo la [guía de inicio rápido](quickstart).
:::
Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no reciban los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo irregular que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los flows y paywalls en dos capas: la caché de actualización periódica descrita anteriormente y los [paywalls de respaldo](kmp-use-fallback-paywalls). También usamos CDN para obtener flows y paywalls más rápido, y un servidor de respaldo independiente en caso de que el CDN sea inaccesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus flows y paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | predeterminado: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede agotar el tiempo de espera un poco más tarde de lo especificado en `loadTimeout`, ya que la operación puede estar compuesta de diferentes solicitudes internamente.
| ¡No escribas los IDs de producto en el código! Como los flows se configuran de forma remota, los productos disponibles, el número de productos y las ofertas especiales (como las pruebas gratuitas) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si en un primer momento recuperas 2 productos, tu app debería mostrar esos 2 productos. Sin embargo, si más adelante recuperas 3 productos, tu app debería mostrar los 3 sin necesidad de modificar el código. Lo único que tienes que escribir en el código es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objeto `AdaptyFlow` con: el identificador del flow, las variaciones de paywall (`paywalls` — cada una con sus propios identificadores de producto), una lista `remoteConfigs` (una entrada por locale configurado) y varias otras propiedades. Para obtener los productos del flow, llama a `getPaywallProducts(flow)`. | :::note En la v4, `getFlow` no tiene el parámetro `locale`. Cuando renderizas un flow con `createFlowView`, la localización se resuelve automáticamente. Para paywalls personalizados, todos los idiomas disponibles se devuelven juntos en `flow.remoteConfigs` — elige el idioma que coincida con el dispositivo del usuario o la configuración de tu app. Consulta [Localizaciones y códigos de idioma](kmp-localizations-and-locale-codes) para más detalles. ::: ## Obtener productos \{#fetch-products\} Una vez que tengas el flow, puedes consultar el array de productos que le corresponde: ```kotlin showLineNumbers Adapty.getPaywallProducts(flow).onSuccess { products -> // the requested products }.onError { error -> // handle the error } ``` Parámetros de respuesta: | Parameter | Description | | :-------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Lista de objetos [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) con: identificador del producto, nombre del producto, precio, moneda, duración de la suscripción y otras propiedades. | Al implementar tu propio diseño de flow, probablemente necesitarás acceder a estas propiedades del objeto [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/). A continuación se ilustran las propiedades más utilizadas; consulta el documento enlazado para obtener todos los detalles sobre las propiedades disponibles. | Propiedad | Descripción | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Para mostrar el título del producto, usa `product.localizedTitle`. Ten en cuenta que la localización se basa en el país del store seleccionado por el usuario, no en el idioma del dispositivo. | | **Price** | Para mostrar el precio localizado, usa `product.price.localizedString`. Esta localización se basa en la configuración regional del dispositivo. También puedes acceder al precio como número con `product.price.amount`. El valor se proporciona en la moneda local. Para obtener el símbolo de moneda correspondiente, usa `product.price.currencySymbol`. | | **Subscription Period** | Para mostrar el período (p. ej. semana, mes, año, etc.), usa `product.subscriptionDetails?.localizedSubscriptionPeriod`. Esta localización se basa en la configuración regional del dispositivo. Para obtener el período de suscripción de forma programática, usa `product.subscriptionDetails?.subscriptionPeriod`. Desde ahí puedes acceder al enum `unit` para conocer la unidad (es decir, DAY, WEEK, MONTH, YEAR o UNKNOWN). El valor `numberOfUnits` te dará el número de unidades del período. Por ejemplo, para una suscripción trimestral verías `MONTH` en la propiedad unit y `3` en la propiedad numberOfUnits. | | **Introductory Offer** | Para mostrar un badge u otro indicador de que una suscripción incluye una oferta introductoria, consulta la propiedad `product.subscriptionDetails?.introductoryOfferPhases`. Es una lista que puede contener hasta dos fases de descuento: la fase de prueba gratuita y la fase de precio introductorio. Dentro de cada objeto de fase encontrarás las siguientes propiedades útiles:Por defecto, el SDK intentará cargar datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` para devolver datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo irregular que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la aplicación y solo se borra cuando se reinstala la app o mediante una limpieza manual.
|opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto de una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
| | **fetchPolicy** | por defecto: `AdaptyPaywallFetchPolicy.Default` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no recibir los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo irregular que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls en dos capas: la caché de actualización regular descrita anteriormente y los [paywalls de respaldo](kmp-use-fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN sea inaccesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo límite especificado en `loadTimeout`, ya que la operación puede estar compuesta de distintas peticiones internamente.
| ¡No codifiques los IDs de producto de forma fija! Dado que los paywalls se configuran de forma remota, los productos disponibles, el número de productos y las ofertas especiales (como los períodos de prueba gratuitos) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si inicialmente obtienes 2 productos, tu app debería mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, tu app debería mostrar los 3 sin necesidad de cambios en el código. Lo único que tienes que codificar de forma fija es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall/) con: una lista de IDs de producto, el identificador del paywall, Remote Config y varias otras propiedades. | ## Obtener productos \{#fetch-products\} Una vez que tienes el paywall, puedes consultar el array de productos que le corresponde: ```kotlin showLineNumbers Adapty.getPaywallProducts(paywall).onSuccess { products -> // the requested products }.onError { error -> // handle the error } ``` Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Lista de objetos [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) con: identificador del producto, nombre del producto, precio, moneda, duración de la suscripción y otras propiedades. | Al implementar tu propio diseño de paywall, probablemente necesitarás acceder a estas propiedades del objeto [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/). A continuación se ilustran las propiedades más utilizadas, pero consulta el documento enlazado para obtener detalles completos sobre todas las propiedades disponibles. | Propiedad | Descripción | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Para mostrar el título del producto, usa `product.localizedTitle`. Ten en cuenta que la localización se basa en el país de la store seleccionado por el usuario, no en el idioma del dispositivo. | | **Price** | Para mostrar el precio en formato localizado, usa `product.price.localizedString`. Esta localización se basa en la configuración regional del dispositivo. También puedes acceder al precio como número con `product.price.amount`. El valor se proporcionará en la moneda local. Para obtener el símbolo de moneda correspondiente, usa `product.price.currencySymbol`. | | **Subscription Period** | Para mostrar el período (p. ej., semana, mes, año, etc.), usa `product.subscriptionDetails?.localizedSubscriptionPeriod`. Esta localización se basa en la configuración regional del dispositivo. Para obtener el período de suscripción de forma programática, usa `product.subscriptionDetails?.subscriptionPeriod`. Desde ahí puedes acceder al enum `unit` para conocer la duración (es decir, DAY, WEEK, MONTH, YEAR o UNKNOWN). El valor `numberOfUnits` te dará el número de unidades del período. Por ejemplo, para una suscripción trimestral verás `MONTH` en la propiedad unit y `3` en la propiedad numberOfUnits. | | **Introductory Offer** | Para mostrar una insignia u otro indicador de que una suscripción incluye una oferta introductoria, consulta la propiedad `product.subscriptionDetails?.introductoryOfferPhases`. Es una lista que puede contener hasta dos fases de descuento: la fase de prueba gratuita y la fase de precio introductorio. Dentro de cada objeto de fase encontrarás las siguientes propiedades útiles:opcional
predeterminado: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
| | **fetchPolicy** | predeterminado: `AdaptyPaywallFetchPolicy.Default` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la aplicación y solo se borra cuando se reinstala la app o mediante una limpieza manual.
|Si la solicitud se ha completado correctamente, la respuesta contiene este objeto. Un objeto [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/) proporciona información completa sobre los niveles de acceso, suscripciones y compras únicas de un usuario dentro de la app.
Comprueba el estado del nivel de acceso para determinar si el usuario tiene el acceso requerido a la app.
| :::warning **Nota:** si todavía usas una versión de StoreKit de Apple inferior a v2.0 y una versión del SDK de Adapty inferior a v2.9.0, debes proporcionar el [secreto compartido de Apple App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret) en su lugar. Apple ha declarado este método como obsoleto. ::: ## Cambiar la suscripción al realizar una compra \{#change-subscription-when-making-a-purchase\} Cuando un usuario elige una nueva suscripción en lugar de renovar la actual, el funcionamiento depende del store. En Google Play, la suscripción no se actualiza automáticamente. Tendrás que gestionar el cambio en el código de tu aplicación móvil como se describe a continuación. Para reemplazar la suscripción por otra en Android, llama al método `.makePurchase()` con el parámetro adicional: ```kotlin showLineNumbers val subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters( oldSubVendorProductId = "old_subscription_product_id", replacementMode = AdaptyAndroidSubscriptionUpdateReplacementMode.CHARGE_FULL_PRICE ) val purchaseParams = AdaptyPurchaseParameters.Builder() .setSubscriptionUpdateParams(subscriptionUpdateParams) .build() Adapty.makePurchase( product = product, parameters = purchaseParams ).onSuccess { purchaseResult -> when (purchaseResult) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile // successful cross-grade } is AdaptyPurchaseResult.UserCanceled -> { // user canceled the purchase flow } is AdaptyPurchaseResult.Pending -> { // the purchase has not been finished yet, e.g. user will pay offline by cash } } }.onError { error -> // Handle the error } ``` Parámetro de solicitud adicional: | Parámetro | Presencia | Descripción | |:---------------|:---------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **parameters** | opcional | un objeto [`AdaptyAndroidSubscriptionUpdateParameters`](https://kmp.adapty.io/////adapty/com.adapty.kmp.models/-adapty-android-subscription-update-parameters/) pasado a través de [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/). | Puedes leer más sobre suscripciones y modos de reemplazo en la documentación de Google Developer: - [Acerca de los modos de reemplazo](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recomendaciones de Google para los modos de reemplazo](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Modo de reemplazo [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Nota: este método solo está disponible para actualizaciones de suscripción. No se admiten cambios a planes inferiores. - Modo de reemplazo [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Nota: el cambio de suscripción real solo se producirá cuando finalice el período de facturación de la suscripción actual. ## Canjear códigos de oferta en iOS \{#redeem-offer-codes-in-ios\}Un objeto [`AdaptyProfile`](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-profile/). Este modelo contiene información sobre los niveles de acceso, suscripciones y compras no relacionadas con suscripciones.
Comprueba el **estado del nivel de acceso** para determinar si el usuario tiene acceso a la app.
| :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: --- # File: implement-observer-mode-kmp --- --- title: "Implementar el modo Observador en el SDK de Kotlin Multiplatform" description: "Implementa el modo observador en Adapty para rastrear los eventos de suscripción de los usuarios en el SDK de Kotlin Multiplatform." --- Si ya tienes tu propia infraestructura de compras y no estás listo para migrar completamente a Adapty, puedes explorar el [modo Observer](observer-vs-full-mode). En su forma básica, el modo Observer ofrece analíticas avanzadas e integración fluida con sistemas de atribución y analíticas. Si esto satisface tus necesidades, solo tienes que: 1. Activarlo al configurar el SDK estableciendo el parámetro `observerMode` en `true`. Sigue las instrucciones de configuración para [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform). 2. [Notificar las transacciones](report-transactions-observer-mode-kmp) desde tu infraestructura de compras existente a Adapty. :::tip En el SDK v4, también puedes mostrar flows y paywalls renderizados por Adapty en modo Observer: cuando el usuario pulsa el botón de compra o restauración, el SDK cede la acción a tu código para que puedas realizar la compra o restauración tú mismo. Consulta [Presentar flows en modo Observer](kmp-present-flows-in-observer-mode). ::: ## Configuración del modo Observer \{#observer-mode-setup\} Activa el modo Observer si gestionas las compras y el estado de la suscripción por tu cuenta y utilizas Adapty para enviar eventos de suscripción y analíticas. :::important Al ejecutarse en modo Observer, el SDK de Adapty no cerrará ninguna transacción, así que asegúrate de gestionarlas tú mismo. ::: ```kotlin showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withObserverMode(true) // default false .build() Adapty.activate(configuration = config) .onSuccess { Log.d("Adapty", "SDK initialised in observer mode") } .onError { error -> Log.e("Adapty", "Adapty init error: ${error.message}") } ``` Parámetros: | Parámetro | Descripción | | --------------------------- | ------------------------------------------------------------ | | observerMode | Un valor booleano que controla el [modo Observer](observer-vs-full-mode). El valor predeterminado es `false`. | ## Usar paywalls de Adapty en el modo Observer \{#using-adapty-paywalls-in-observer-mode\} Si también quieres usar las paywalls y las funciones de pruebas A/B de Adapty, puedes hacerlo, pero requiere una configuración adicional en el modo Observer. Esto es lo que necesitas hacer además de los pasos anteriores: 1. Muestra los paywalls de la forma habitual para [paywalls con Remote Config](present-remote-config-paywalls-kmp). 3. [Asocia los paywalls](report-transactions-observer-mode-kmp) con las transacciones de compra. --- # File: report-transactions-observer-mode-kmp --- --- title: "Reportar transacciones en el modo Observer en el SDK de Kotlin Multiplatform" description: "Reporta transacciones de compra en el modo Observer de Adapty para obtener información sobre usuarios y seguimiento de ingresos en el SDK de Kotlin Multiplatform." --- En el modo Observer, el SDK de Adapty no puede rastrear por sí solo las compras realizadas a través de tu sistema de compras existente. Necesitas reportar las transacciones desde tu app store. Es fundamental configurar esto **antes** de publicar tu app para evitar errores en los análisis. Usa `reportTransaction` para reportar de forma explícita cada transacción y que Adapty pueda reconocerla. :::warning **¡No omitas el reporte de transacciones!** Si no llamas a `reportTransaction`, Adapty no reconocerá la transacción, no aparecerá en los análisis y no se enviará a las integraciones. ::: Si usas paywalls de Adapty, incluye el `variationId` al reportar una transacción. Esto vincula la compra con el paywall que la originó, garantizando un análisis preciso del paywall. ```kotlin showLineNumbers Adapty.reportTransaction( transactionId = "your_transaction_id", variationId = paywall.variationId ).onSuccess { profile -> // Transaction reported successfully // profile contains updated user data }.onError { error -> // handle the error } ``` Parámetros: | Parámetro | Presencia | Descripción | | --------------- | ---------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | obligatorio | El ID de transacción de tu compra en el app store. Normalmente es el token de compra o el identificador de transacción devuelto por el store. | | variationId | opcional | El identificador de cadena de la variante. Puedes obtenerlo usando la propiedad `variationId` del objeto [AdaptyPaywall](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-paywall/). | --- # File: kmp-troubleshoot-purchases --- --- title: "Solucionar problemas de compras en el SDK de Kotlin Multiplatform" description: "Solucionar problemas de compras en el SDK de Kotlin Multiplatform" --- Esta guía te ayuda a resolver problemas comunes al implementar compras manualmente en el SDK de Kotlin Multiplatform. ## makePurchase se llama correctamente, pero el perfil no se actualiza \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **Problema**: El método `makePurchase` se completa correctamente, pero el perfil del usuario y el estado de la suscripción no se actualizan en Adapty. **Causa**: Esto normalmente indica una configuración incompleta de Google Play Store. **Solución**: Asegúrate de haber completado todos los [pasos de configuración de Google Play](initial-android). ## makePurchase se invoca dos veces \{#makepurchase-is-invoked-twice\} **Problema**: El método `makePurchase` se está llamando varias veces para la misma compra. **Causa**: Esto suele ocurrir cuando el flujo de compra se activa varias veces debido a problemas de gestión del estado de la interfaz o por interacciones rápidas del usuario. **Solución**: Asegúrate de haber completado todos los [pasos de configuración de Google Play](initial-android). ## AdaptyError.cantMakePayments en el modo observador \{#adaptye-rror-cantmakepayments-in-observer-mode\} **Problema**: Estás recibiendo `AdaptyError.cantMakePayments` al usar `makePurchase` en el modo observador. **Causa**: En el modo observador, debes gestionar las compras por tu cuenta, no usar el método `makePurchase` de Adapty. **Solución**: Si usas `makePurchase` para las compras, desactiva el modo observador. Tienes que elegir entre usar `makePurchase` o gestionar las compras por tu cuenta en el modo observador. Consulta [Implementar el modo observador](implement-observer-mode-kmp) para más detalles. ## Error de Adapty: (code: 103, message: Play Market request failed on purchases updated: responseCode=3, debugMessage=Billing Unavailable, detail: null) \{#adapty-error-code-103-message-play-market-request-failed-on-purchases-updated-responsecode3-debugmessagebilling-unavailable-detail-null\} **Problema**: Estás recibiendo un error de facturación no disponible de Google Play Store. **Causa**: Este error no está relacionado con Adapty. Es un error de la biblioteca Google Play Billing que indica que la facturación no está disponible en el dispositivo. **Solución**: Este error no está relacionado con Adapty. Puedes consultarlo en la documentación de Play Store: [Handle BillingResult response codes](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers. ## No se encuentran makePurchasesCompletionHandlers \{#not-found-makepurchasescompletionhandlers\} **Problema**: Estás teniendo problemas porque no se encuentran los `makePurchasesCompletionHandlers`. **Causa**: Esto suele estar relacionado con problemas en las pruebas en sandbox. **Solución**: Crea un nuevo usuario de sandbox e inténtalo de nuevo. Esto suele resolver los problemas con los manejadores de finalización de compras en sandbox. --- # File: kmp-user --- --- title: "Usuarios y acceso en Kotlin Multiplatform SDK" description: "Aprende a gestionar usuarios y niveles de acceso en tu app de Kotlin Multiplatform con el SDK de Adapty." --- Esta página contiene todas las guías para trabajar con usuarios y niveles de acceso en tu app de Kotlin Multiplatform. Elige el tema que necesites: - **[Identificar usuarios](kmp-identifying-users)** - Aprende a identificar usuarios en tu app - **[Actualizar datos de usuario](kmp-setting-user-attributes)** - Establece atributos de usuario y datos de perfil - **[Escuchar cambios en el estado de la suscripción](kmp-listen-subscription-changes)** - Monitoriza los cambios de suscripción en tiempo real - **[Modo Niños](kids-mode-kmp)** - Implementa el Modo Niños en tu app --- # File: kmp-identifying-users --- --- title: "Identificar usuarios en Kotlin Multiplatform SDK" description: "Identifica usuarios en Adapty para mejorar las experiencias de suscripción personalizadas." --- Adapty crea un ID de perfil interno para cada usuario. Sin embargo, si tienes tu propio sistema de autenticación, deberías establecer tu propio Customer User ID. Puedes encontrar usuarios por su Customer User ID en la sección [Perfiles](profiles-crm) y usarlo en la [API del lado del servidor](getting-started-with-server-side-api), que se enviará a todas las integraciones. ### Configurar el ID de usuario del cliente durante la configuración \{#setting-customer-user-id-on-configuration\} Si tienes un ID de usuario durante la configuración, pásalo como parámetro `customerUserId` al método `.activate()`: ```kotlin showLineNumbers Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId("YOUR_USER_ID") .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } } ``` :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ### Configuración del ID de usuario tras la inicialización \{#setting-customer-user-id-after-configuration\} Si no tienes un ID de usuario en la configuración del SDK, puedes establecerlo más adelante en cualquier momento con el método `.identify()`. Los casos más habituales para usar este método son tras el registro o la autenticación, cuando el usuario pasa de ser anónimo a estar autenticado. ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID").onSuccess { // successful identify }.onError { error -> // handle the error } ``` Parámetros de la solicitud: - **Customer User ID** (obligatorio): un identificador de usuario de tipo string. :::warning Reenvío de datos significativos del usuario En algunos casos, como cuando un usuario vuelve a iniciar sesión en su cuenta, los servidores de Adapty ya tienen información sobre ese usuario. En estos escenarios, el SDK de Adapty cambiará automáticamente para trabajar con el nuevo usuario. Si enviaste algún dato al usuario anónimo, como atributos personalizados o atribuciones de redes de terceros, deberás reenviar esos datos para el usuario identificado. También es importante tener en cuenta que debes volver a solicitar todos los paywalls y productos después de identificar al usuario, ya que los datos del nuevo usuario pueden ser diferentes. ::: ### Cerrar sesión e iniciar sesión \{#logging-out-and-logging-in\} Puedes cerrar la sesión del usuario en cualquier momento llamando al método `.logout()`: ```kotlin showLineNumbers Adapty.logout().onSuccess { // successful logout }.onError { error -> // handle the error } ``` Después puedes iniciar sesión con el método `.identify()`. ## Asignar `appAccountToken` (iOS) \{#assign-appaccounttoken-ios\} [`iosAppAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) es un **UUID** que te permite vincular las transacciones del App Store con la identidad interna de tus usuarios. StoreKit asocia este token con cada transacción, de modo que tu backend puede relacionar los datos del App Store con tus usuarios. Usa un UUID estable generado por usuario y reutilízalo para la misma cuenta en todos los dispositivos. Esto garantiza que las compras y las notificaciones del App Store queden correctamente vinculadas. Puedes establecer el token de dos formas: durante la activación del SDK o al identificar al usuario. :::important Siempre debes pasar `iosAppAccountToken` junto con `customerUserId`. Si solo pasas el token, no se incluirá en la transacción. ::: ```kotlin showLineNumbers // Durante la configuración: Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId( id = "YOUR_USER_ID", iosAppAccountToken = "YOUR_IOS_APP_ACCOUNT_TOKEN" ) .build() ).onSuccess { // activación exitosa }.onError { error -> // manejar el error } // O al identificar usuarios Adapty.identify( customerUserId = "YOUR_USER_ID", iosAppAccountToken = "YOUR_IOS_APP_ACCOUNT_TOKEN" ).onSuccess { // identificación exitosa }.onError { error -> // manejar el error } ``` ## Establecer IDs de cuenta ofuscados (Android) \{#set-obfuscated-account-ids-android\} Google Play requiere IDs de cuenta ofuscados en ciertos casos de uso para mejorar la privacidad y seguridad del usuario. Estos IDs ayudan a Google Play a identificar las compras manteniendo el anonimato de la información del usuario, algo especialmente importante para la prevención de fraudes y los análisis. Es posible que necesites configurar estos IDs si tu aplicación maneja datos sensibles de usuarios o si debes cumplir con regulaciones de privacidad específicas. Los IDs ofuscados permiten a Google Play rastrear las compras sin exponer los identificadores reales de los usuarios. :::important Siempre debes pasar `androidObfuscatedAccountId` junto con `customerUserId`. Si solo pasas el ID de cuenta ofuscado, no se incluirá en la transacción. ::: ```kotlin showLineNumbers // Durante la configuración: Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId( id = "YOUR_USER_ID", androidObfuscatedAccountId = "YOUR_OBFUSCATED_ACCOUNT_ID" ) .build() ).onSuccess { // activación correcta }.onError { error -> // gestionar el error } // O al identificar usuarios Adapty.identify( customerUserId = "YOUR_USER_ID", androidObfuscatedAccountId = "YOUR_OBFUSCATED_ACCOUNT_ID" ).onSuccess { // identificación correcta }.onError { error -> // gestionar el error } ``` ## Detectar usuarios en varios dispositivos \{#detect-users-across-devices\} Cuando el SDK se activa, lee automáticamente los derechos existentes del usuario desde StoreKit (iOS) o Google Play Billing (Android) y los sincroniza con el backend de Adapty. Una suscripción activa aparece en el perfil de Adapty sin que la app llame a `restorePurchases`. Lo que **no** ocurre automáticamente es reconocer que un perfil en un dispositivo nuevo pertenece al mismo usuario que el perfil en el dispositivo original. Adapty relaciona perfiles por Customer User ID, así que la continuidad de identidad depende de lo que uses como CUID. **Lo que Adapty puede detectar entre dispositivos** | Tu configuración | Lo que Adapty detecta | Lo que debes hacer | | --- | --- | --- | | Customer User ID = `device_id` (sin login en la app) | El nuevo dispositivo obtiene un CUID diferente y, por tanto, un perfil diferente. La suscripción se sincroniza con el nuevo perfil mediante un evento **Access level updated**, pero `subscription_started` no se dispara — el nuevo perfil se trata como heredero de la compra original. Los análisis basados en `subscription_started` contarán de menos a los usuarios que vuelven. | Usa un ID de cuenta estable como Customer User ID para que un usuario que regresa coincida con el perfil existente en todos los dispositivos. | | Customer User ID = ID de cuenta estable (login en cada dispositivo) | El SDK sincroniza automáticamente la suscripción en `activate()`, e `identify()` relaciona el perfil existente por CUID. | No se necesita configuración adicional — tanto la identidad como la suscripción se resuelven automáticamente. | | Heredero de Apple Family Sharing | El miembro de la familia recibe la suscripción solo a través de un evento **Access level updated** — `subscription_started` no se dispara. | Escucha el evento **Access level updated**. Consulta [Apple Family Sharing](apple-family-sharing) para ver la matriz de eventos completa. | | Misma cuenta de Apple/Google, distintos usuarios dentro de la app | El primer perfil que registra la compra se convierte en el principal. Los perfiles posteriores ven la suscripción a través de una cadena de herederos, con un evento **Access level updated**. | Exige login y elige un [modo de compartición](sharing-paid-access-between-user-accounts) que se adapte a tu modelo. | **Restaurar compras en un dispositivo nuevo** Muestra un botón "Restaurar compras" iniciado por el usuario en tu paywall. Apple App Review (directriz 3.1.1) lo exige, y actúa como alternativa cuando la sincronización automática no cubre algún caso límite. El botón debe llamar a `restorePurchases` en tu SDK. No es necesario llamar a `restorePurchases` de forma programática al primer inicio para el uso normal — el SDK ya ejecuta el equivalente en `activate()`. Reserva las llamadas programáticas para forzar una verificación de recibo actualizada, por ejemplo al depurar un acceso que falta después de que `activate()` haya completado. --- # File: kmp-setting-user-attributes --- --- title: "Establecer atributos de usuario en el SDK de Kotlin Multiplatform" description: "Aprende cómo establecer atributos de usuario en Adapty para mejorar la segmentación de audiencias." --- Puedes establecer atributos opcionales como el correo electrónico, el número de teléfono, etc., en el usuario de tu aplicación. Luego puedes usar estos atributos para crear [segmentos](segments) de usuarios o simplemente verlos en el CRM. ### Establecer atributos de usuario \{#setting-user-attributes\} Para establecer atributos de usuario, llama al método `.updateProfile()`: ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() .withEmail("email@email.com") .withPhoneNumber("+18888888888") .withFirstName("John") .withLastName("Appleseed") .withGender(AdaptyProfile.Gender.FEMALE) .withBirthday(AdaptyProfile.Date(1970, 1, 3)) Adapty.updateProfile(builder.build()) .onSuccess { // profile updated successfully } .onError { error -> // handle the error } ``` Ten en cuenta que los atributos que hayas establecido previamente con el método `updateProfile` no se restablecerán. :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ### Lista de claves permitidas \{#the-allowed-keys-list\} Las claves permitidas `phoneNumber
firstName
lastName
| String | | gender | Enum, los valores permitidos son: `AdaptyProfile.Gender.FEMALE`, `AdaptyProfile.Gender.MALE`, `AdaptyProfile.Gender.OTHER` | | birthday | Date | ### Atributos personalizados de usuario \{#custom-user-attributes\} Puedes definir tus propios atributos personalizados. Estos suelen estar relacionados con el uso de tu aplicación. Por ejemplo, en aplicaciones de fitness podrían ser el número de ejercicios por semana; en aplicaciones de aprendizaje de idiomas, el nivel de conocimiento del usuario, etc. Puedes usarlos en segmentos para crear paywalls y ofertas dirigidas, y también en análisis para determinar qué métricas de producto influyen más en los ingresos. ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() builder.withCustomAttribute("key1", "value1") ``` Para eliminar una clave existente, usa el método `.withRemovedCustomAttribute()`: ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() builder.withRemovedCustomAttribute("key2") ``` En ocasiones necesitas saber qué atributos personalizados ya se han establecido anteriormente. Para ello, utiliza el campo `customAttributes` del objeto `AdaptyProfile`. :::warning Ten en cuenta que el valor de `customAttributes` puede estar desactualizado, ya que los atributos de usuario pueden enviarse desde distintos dispositivos en cualquier momento, por lo que los atributos en el servidor pueden haber cambiado desde la última sincronización. ::: ### Límites \{#limits\} - Hasta 30 atributos personalizados por usuario - Los nombres de clave tienen un máximo de 30 caracteres. El nombre de la clave puede incluir caracteres alfanuméricos y cualquiera de los siguientes: `_` `-` `.` - El valor puede ser una cadena de texto o un número flotante con un máximo de 50 caracteres. --- # File: kmp-listen-subscription-changes --- --- title: "Verificar el estado de la suscripción en el SDK de Kotlin Multiplatform" description: "Rastrea y gestiona el estado de la suscripción de usuarios en Adapty para mejorar la retención de clientes en tu app de Kotlin Multiplatform." --- Con Adapty, hacer seguimiento del estado de la suscripción es muy sencillo. No tienes que insertar manualmente IDs de productos en tu código. En su lugar, puedes confirmar fácilmente el estado de la suscripción de un usuario comprobando si tiene un [nivel de acceso](access-level) activo. Antes de empezar a verificar el estado de la suscripción, configura las [notificaciones de desarrollador en tiempo real (RTDN)](enable-real-time-developer-notifications-rtdn). ## Nivel de acceso y el objeto AdaptyProfile \{#access-level-and-the-adaptyprofile-object\} Los niveles de acceso son propiedades del objeto [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/). Te recomendamos obtener el perfil cuando tu app se inicie, por ejemplo al [identificar un usuario](android-identifying-users#setting-customer-user-id-on-configuration), y actualizarlo cada vez que se produzcan cambios. Así podrás usar el objeto de perfil sin tener que solicitarlo repetidamente. Para recibir notificaciones sobre actualizaciones del perfil, escucha los cambios tal como se describe en la sección [Escuchar actualizaciones del perfil, incluidos los niveles de acceso](android-listen-subscription-changes) a continuación. :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ## Obtener el nivel de acceso desde el servidor \{#retrieving-the-access-level-from-the-server\} Para obtener el nivel de acceso desde el servidor, usa el método `.getProfile()`: ```kotlin showLineNumbers Adapty.getProfile().onSuccess { profile -> // check the access }.onError { error -> // handle the error } ``` Parámetros de respuesta: | Parámetro | Descripción | | --------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Profile |Un objeto [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/). En general, solo tienes que comprobar el estado del nivel de acceso del perfil para determinar si el usuario tiene acceso premium a la app.
El método `.getProfile` proporciona el resultado más actualizado, ya que siempre intenta consultar la API. Si por alguna razón (por ejemplo, sin conexión a internet), el SDK de Adapty no puede obtener información del servidor, se devolverán los datos de la caché. También es importante tener en cuenta que el SDK de Adapty actualiza la caché de `AdaptyProfile` periódicamente para mantener esta información lo más actualizada posible.
| El método `.getProfile()` te proporciona el perfil de usuario desde el que puedes obtener el estado del nivel de acceso. Puedes tener varios niveles de acceso por app. Por ejemplo, si tienes una app de noticias y vendes suscripciones a distintos temas de forma independiente, puedes crear niveles de acceso "sports" y "science". Pero la mayoría de las veces solo necesitarás un nivel de acceso; en ese caso, puedes usar simplemente el nivel de acceso predeterminado "premium". A continuación se muestra un ejemplo para comprobar el nivel de acceso predeterminado "premium": ```kotlin showLineNumbers Adapty.getProfile().onSuccess { profile -> if (profile.accessLevels["premium"]?.isActive == true) { // grant access to premium features } }.onError { error -> // handle the error } ``` ### Escuchar actualizaciones del estado de la suscripción \{#listening-for-subscription-status-updates\} Cada vez que cambia la suscripción de un usuario, Adapty lanza un evento. Para recibir mensajes de Adapty, necesitas realizar una configuración adicional: ```kotlin showLineNumbers Adapty.setOnProfileUpdatedListener { profile -> // handle any changes to subscription state } ``` Adapty también lanza un evento al inicio de la aplicación. En ese caso, se pasará el estado de la suscripción almacenado en caché. ### Caché del estado de la suscripción \{#subscription-status-cache\} La caché implementada en el SDK de Adapty almacena el estado de la suscripción del perfil. Esto significa que, aunque el servidor no esté disponible, se puede acceder a los datos en caché para obtener información sobre el estado de la suscripción del perfil. Sin embargo, es importante tener en cuenta que no es posible solicitar datos directamente desde la caché. El SDK consulta periódicamente el servidor cada minuto para comprobar si hay actualizaciones o cambios relacionados con el perfil. Si hay alguna modificación, como nuevas transacciones u otras actualizaciones, se enviarán a los datos en caché para mantenerlos sincronizados con el servidor. --- # File: kmp-deal-with-att --- --- title: "Gestionar ATT en el SDK de Kotlin Multiplatform" description: "Comienza con Adapty en Kotlin Multiplatform para simplificar la configuración y gestión de suscripciones." --- Si tu aplicación usa el framework AppTrackingTransparency y muestra al usuario una solicitud de autorización de seguimiento, debes enviar el [estado de autorización](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) a Adapty. ```kotlin showLineNumbers val profileParameters = AdaptyProfileParameters.Builder() .withAttStatus(3) // 3 = ATTrackingManagerAuthorizationStatusAuthorized .build() Adapty.updateProfile(profileParameters) .onSuccess { // ATT status updated successfully } .onError { error -> // handle AdaptyError } ``` :::warning Te recomendamos encarecidamente que envíes este valor lo antes posible cuando cambie; solo así los datos se transmitirán a tiempo a las integraciones que hayas configurado. ::: --- # File: kids-mode-kmp --- --- title: "Modo para Niños en el SDK de Kotlin Multiplatform" description: "Activa fácilmente el Modo para Niños para cumplir con las políticas de Google. Sin GAID ni datos publicitarios recopilados en el SDK de Kotlin Multiplatform." --- Si tu aplicación de Kotlin Multiplatform está destinada a niños, debes seguir las políticas de [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si usas el SDK de Adapty, unos pocos pasos sencillos te ayudarán a configurarlo para cumplir con estas políticas y superar las revisiones de la app store. ## ¿Qué se requiere? \{#whats-required\} Necesitas configurar el SDK de Adapty para deshabilitar la recopilación de: - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) (iOS) - [Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) (Android) - [Dirección IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) Además, te recomendamos usar el ID de usuario del cliente con cuidado. Un ID de usuario con el formato `opcional
predeterminado: `en`
| El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
| | **fetchPolicy** | predeterminado: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de lo intermitente que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala o mediante una limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché de actualización periódica descrita anteriormente y los onboardings de respaldo. También usamos CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para asegurarte siempre la versión más reciente de tus onboardings, garantizando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | predeterminado: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede incluir distintas peticiones internamente.
| Parámetros de respuesta: | Parámetro | Descripción | |:----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objeto [`AdaptyOnboarding`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-onboarding/) con: el identificador y la configuración del onboarding, Remote Config y otras propiedades. | ## Acelera la obtención del onboarding con el onboarding de audiencia predeterminada \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Normalmente, los onboardings se obtienen casi al instante, por lo que no necesitas preocuparte por acelerar este proceso. Sin embargo, cuando tienes numerosas audiencias y onboardings, y tus usuarios tienen una conexión a internet débil, obtener un onboarding puede tardar más de lo deseable. En esas situaciones, puede que quieras mostrar un onboarding predeterminado para garantizar una experiencia de usuario fluida en lugar de no mostrar ninguno. Para solucionar esto, puedes usar el método `getOnboardingForDefaultAudience`, que obtiene el onboarding del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el onboarding mediante el método `getOnboarding`, tal como se detalla en la sección [Obtener onboarding](#fetch-onboarding) anterior. :::warning Considera usar `getOnboarding` en lugar de `getOnboardingForDefaultAudience`, ya que este último tiene limitaciones importantes: - **Problemas de compatibilidad**: Puede ocasionar problemas al dar soporte a varias versiones de la app, ya que requiere diseños retrocompatibles o aceptar que las versiones anteriores podrían mostrarse incorrectamente. - **Sin personalización**: Solo muestra contenido para la audiencia "All Users", lo que elimina la segmentación por país, atribución o atributos personalizados. Si la velocidad de carga supera estos inconvenientes en tu caso de uso, utiliza `getOnboardingForDefaultAudience` como se muestra a continuación. De lo contrario, usa `getOnboarding` como se describe [arriba](#fetch-onboarding). ::: ```kotlin showLineNumbers Adapty.getOnboardingForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { paywall -> // el onboarding solicitado }.onError { error -> // gestiona el error } ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |opcional
por defecto: `en`
| El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que los usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra al reinstalar la app o mediante una limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché con actualizaciones periódicas descrita anteriormente y los onboardings de respaldo. También usamos una CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que la CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus onboardings, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| --- # File: kmp-present-onboardings --- --- title: "Presentar onboardings en el SDK de Kotlin Multiplatform" description: "Aprende a presentar onboardings de forma efectiva para aumentar las conversiones." --- :::warning **Los onboardings están obsoletos en SDK v4 y se eliminarán en una versión futura.** Ya no reciben correcciones ni mejoras. Usa [flows](kmp-get-pb-paywalls) en su lugar: a diferencia de los onboardings, que se ejecutan dentro de un WebView, los flows se renderizan de forma nativa en el dispositivo, lo que ofrece animaciones más fluidas, una apariencia nativa consistente, tiempos de carga más rápidos y sin dependencia del runtime de WebView. Consulta [Obtener flows y paywalls](kmp-get-pb-paywalls) y [Mostrar flows y paywalls](kmp-present-paywalls) para empezar. ::: Si has personalizado un onboarding con el builder, no necesitas preocuparte por renderizarlo en el código de tu app Kotlin Multiplatform para mostrárselo al usuario. Ese onboarding incluye tanto lo que debe mostrarse como la forma en que debe mostrarse. Antes de empezar, asegúrate de que: 1. Tienes instalado el [SDK de Adapty para Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) 3.16.1 o posterior. 2. Has [creado un onboarding](create-onboarding). 3. Has añadido el onboarding a un [placement](placements). Adapty Kotlin Multiplatform SDK ofrece dos formas de mostrar onboardings: - **Con Compose Multiplatform** - **Sin Compose Multiplatform** ## Con Compose Multiplatform \{#with-compose-multiplatform\} Para mostrar un onboarding, usa el método `view.present()` en el `view` creado por el método `createOnboardingView`. Cada `view` solo puede usarse una vez. Si necesitas mostrar el onboarding de nuevo, llama a `createOnboardingView` otra vez para crear una nueva instancia de `view`. :::warning Reutilizar el mismo `view` sin recrearlo puede provocar un error. ::: ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { AdaptyUI.createOnboardingView(onboarding = onboarding).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ### Configurar el estilo de presentación en iOS \{#configure-ios-presentation-style\} Configura cómo se presenta el onboarding en iOS pasando el parámetro `iosPresentationStyle` al método `present()`. El parámetro acepta los valores `AdaptyUIIOSPresentationStyle.FULLSCREEN` (predeterminado) o `AdaptyUIIOSPresentationStyle.PAGESHEET`. ```kotlin showLineNumbers viewModelScope.launch { val view = AdaptyUI.createOnboardingView(onboarding = onboarding).getOrNull() view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET) } ``` ### Personalizar cómo se abren los enlaces en los onboardings \{#customize-how-links-open-in-onboardings\} Por defecto, los enlaces en los onboardings se abren en un navegador integrado en la app. Esto ofrece una experiencia fluida al mostrar las páginas web dentro de tu aplicación, sin que el usuario tenga que cambiar de app. Si prefieres que los enlaces se abran en un navegador externo, puedes personalizar este comportamiento estableciendo el parámetro `externalUrlsPresentation` en `AdaptyWebPresentation.EXTERNAL_BROWSER`: ```kotlin showLineNumbers viewModelScope.launch { AdaptyUI.createOnboardingView( onboarding = onboarding, externalUrlsPresentation = AdaptyWebPresentation.EXTERNAL_BROWSER // default – IN_APP_BROWSER ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ## Sin Compose Multiplatform \{#without-compose-multiplatform\} :::note `createNativeOnboardingView` forma parte del módulo principal `io.adapty:adapty-kmp`. Si tu proyecto no usa Compose Multiplatform, no necesitas la dependencia `io.adapty:adapty-kmp-ui`. ::: Para integrar un onboarding sin Compose Multiplatform, llama a `createNativeOnboardingView`. Devuelve un `AdaptyNativeOnboardingView` que puedes añadir a tu layout:
Por ejemplo, si un usuario pulsa un botón personalizado, como **Login** o **Allow notifications**, el método delegado `onCustomAction` se activará con el ID de acción del builder. Puedes crear tus propios IDs, como "allowNotifications".
```kotlin
class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver {
override fun onboardingViewOnCustomAction(
view: AdaptyUIOnboardingView,
meta: AdaptyUIOnboardingMeta,
actionId: String
) {
when (actionId) {
"openPaywall" -> {
// Display paywall from onboarding
// You would typically fetch and present a new paywall here
mainUiScope.launch {
// Example: Get paywall by placement ID
// val paywallResult = Adapty.getPaywall("your_placement_id")
// paywallResult.onSuccess { paywall ->
// val paywallViewResult = AdaptyUI.createPaywallView(paywall)
// paywallViewResult.onSuccess { paywallView ->
// paywallView.present()
// }
// }
}
}
"allowNotifications" -> {
// Handle notification permissions
}
else -> {
// Handle other custom actions
}
}
}
}
// Set up the observer
AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver())
```
2. Haz clic en el nombre del grupo de suscripción. Verás tus productos listados en la sección **Subscriptions**.
3. Asegúrate de que el producto que estás probando esté marcado como **Ready to Submit**. Si no lo está, sigue las instrucciones de la página [Producto en App Store](app-store-products).
4. Compara el ID del producto en la tabla con el que aparece en la pestaña [**Products**](https://app.adapty.io/products) del Adapty Dashboard. Si los IDs no coinciden, copia el ID del producto de la tabla y [crea un producto](create-product) con ese ID en el Adapty Dashboard.
## Paso 3. Comprueba la disponibilidad del producto \{#step-4-check-product-availability\}
1. Vuelve a **App Store Connect** y abre la misma sección **Subscriptions**.
2. Haz clic en el nombre del grupo de suscripción para ver tus productos.
3. Selecciona el producto que estás probando.
4. Desplázate hasta la sección **Availability** y comprueba que todos los países y regiones requeridos estén listados.
## Paso 4. Comprueba los precios del producto \{#step-5-check-product-prices\}
1. De nuevo, ve a la sección **Monetization** → **Subscriptions** en **App Store Connect**.
2. Haz clic en el nombre del grupo de suscripción.
3. Selecciona el producto que estás probando.
4. Desplázate hacia abajo hasta **Subscription Pricing** y despliega la sección **Current Pricing for New Subscribers**.
5. Asegúrate de que todos los precios requeridos estén listados.
## Paso 5. Comprueba que el estado de pago de la app, la cuenta bancaria y los formularios fiscales estén activos \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\}
1. En la página de inicio de [**App Store Connect**](https://appstoreconnect.apple.com/), haz clic en **Business**.
2. Selecciona el nombre de tu empresa.
3. Desplázate hacia abajo y comprueba que tu **Paid Apps Agreement**, **Bank Account** y **Tax forms** aparezcan como **Active**.
Siguiendo estos pasos deberías poder resolver la advertencia `InvalidProductIdentifiers` y hacer que tus productos estén disponibles en el store.
## Paso 6. Vuelve a crear el producto si está bloqueado \{#step-6-recreate-the-product-if-its-stuck\}
Es posible que los pasos 1–5 pasen correctamente —estado `Approved`, Bundle ID coincidente, API key válida— y el SDK siga devolviendo `1000 noProductIDsFound`. En ese caso, puede que el producto esté bloqueado en el registro de Apple. El registro de productos de Apple puede entrar en un estado en el que el producto existe en la interfaz de App Store Connect pero no está expuesto a la ruta de búsqueda de StoreKit.
Elimina el producto en App Store Connect y vuelve a crearlo con el mismo ID de producto. Espera hasta 24 horas tras la recreación para que los cambios se propaguen.
---
# File: cantMakePayments-kmp
---
---
title: "Solución para el error Code-1003 cantMakePayment en el SDK de Kotlin Multiplatform"
description: "Resuelve el error al realizar pagos cuando gestionas suscripciones en Adapty."
---
El error 1003, `cantMakePayments`, indica que no es posible realizar compras in-app en este dispositivo.
Si encuentras el error `cantMakePayments`, normalmente se debe a una de estas razones:
- Restricciones del dispositivo: El error no está relacionado con Adapty. Consulta las soluciones más abajo.
- Configuración del modo Observer: El método `makePurchase` y el modo Observer no pueden usarse al mismo tiempo. Consulta la sección más abajo.
## Problema: Restricciones del dispositivo \{#issue-device-restrictions\}
| Problema | Solución |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| Restricciones de Screen Time | Desactiva las restricciones de compras in-app en [Screen Time](https://support.apple.com/en-us/102470) |
| Cuenta suspendida | Contacta con el soporte de Apple para resolver problemas con la cuenta |
| Restricciones regionales | Usa una cuenta de App Store de una región compatible |
## Problema: Usar el modo Observer y makePurchase a la vez \{#issue-using-both-observer-mode-and-makepurchase\}
Si usas `makePurchases` para gestionar las compras, no necesitas el modo Observer. El [modo Observer](observer-vs-full-mode) solo es necesario si implementas la lógica de compra tú mismo.
Por lo tanto, si usas `makePurchase`, puedes eliminar sin problema la activación del modo Observer del código de inicialización del SDK.
---
# File: kmp-sdk-migration-guides
---
---
title: "Guías de migración del SDK de Kotlin Multiplatform"
description: "Guías de migración para las versiones del SDK de Kotlin Multiplatform de Adapty."
---
Esta página contiene todas las guías de migración para el SDK de Kotlin Multiplatform de Adapty. Elige la versión a la que quieres migrar para ver las instrucciones detalladas:
- **[Migrar a v4.0 (beta)](migration-to-kmp-sdk-v4)**
- **[Migrar a v3.15](migration-to-kmp-315)**
---
# File: migration-to-kmp-sdk-v4
---
---
title: "Migrar el SDK de Adapty Kotlin Multiplatform a la versión 4.0"
description: "Migra al SDK de Adapty Kotlin Multiplatform v4.0 (beta) reemplazando las APIs de paywall por APIs de flow, compatibles tanto con Flow Builder como con Paywall Builder."
---
El SDK de Adapty Kotlin Multiplatform 4.0 (beta) introduce los flows y renombra las APIs de paywall en consecuencia. Las nuevas APIs funcionan tanto con el nuevo Flow Builder como con el Paywall Builder existente — no se requieren cambios de configuración en el Adapty Dashboard.
## Referencia rápida \{#quick-reference\}
| v3 | v4 |
|---|---|
| `Adapty.getPaywall(placementId, locale)` | `Adapty.getFlow(placementId)` |
| `Adapty.getPaywallForDefaultAudience(placementId, locale)` | `Adapty.getFlowForDefaultAudience(placementId)` |
| `Adapty.getPaywallProducts(paywall)` | `Adapty.getPaywallProducts(flow)` |
| `Adapty.logShowPaywall(paywall)` | `Adapty.logShowFlow(flow)` |
| `AdaptyPaywall` | `AdaptyFlow` |
| `AdaptyUI.createPaywallView(paywall, ...)` | `AdaptyUI.createFlowView(flow, ...)` |
| `AdaptyUI.createNativePaywallView(...)` → `AdaptyNativePaywallView` | `AdaptyUI.createNativeFlowView(...)` → `AdaptyNativeFlowView` |
| `AdaptyUIPaywallView` | `AdaptyUIFlowView` |
| `AdaptyUI.presentPaywallView(view)` / `dismissPaywallView(view)` | `AdaptyUI.presentFlowView(view)` / `dismissFlowView(view)` |
| `AdaptyUI.setPaywallsEventsObserver(observer)` | `AdaptyUI.setFlowsEventsObserver(observer)` |
| `AdaptyUI.registerPaywallEventsListener` / `unregisterPaywallEventsListener` | `AdaptyUI.registerFlowEventsListener` / `unregisterFlowEventsListener` |
| `AdaptyUIPaywallsEventsObserver` | `AdaptyUIFlowsEventsObserver` |
| `AdaptyUIPaywallPlatformView(paywall, ...)` | `AdaptyUIFlowPlatformView(flow, ...)` |
| `paywallViewDidPerformAction`, `paywallViewDidAppear` y otros callbacks `paywallView...` | `flowViewDidPerformAction`, `flowViewDidAppear` y otros callbacks `flowView...` |
| `paywallViewDidFailRendering` | `flowViewDidReceiveError` |
`AdaptyPaywallProduct` mantiene su nombre — los productos siguen perteneciendo a un flow, y `getPaywallProducts` también mantiene su nombre, ahora recibiendo un `AdaptyFlow`. Los métodos `getFlow` y `getFlowForDefaultAudience` ya no aceptan un parámetro `locale`. Las APIs de compra y perfil (`makePurchase`, `restorePurchases`, `getProfile`, `identify`, `updateProfile`) y los respaldos mediante `setFallback` no han cambiado. Los métodos de onboarding siguen funcionando, pero están deprecados — consulta [Deprecación de la API de Onboarding](#onboarding-api-deprecation). Algunos comportamientos predeterminados han cambiado — consulta [Cambios en el comportamiento predeterminado](#default-behavior-changes).
## Instalación \{#installation\}
v4.0 es una versión previa al lanzamiento, así que fija la versión exacta — Gradle no selecciona versiones preliminares mediante rangos dinámicos:
```toml showLineNumbers title="libs.versions.toml"
[versions]
adapty-kmp = "4.0.0-beta.1"
[libraries]
adapty-kmp = { module = "io.adapty:adapty-kmp", version.ref = "adapty-kmp" }
adapty-kmp-ui = { module = "io.adapty:adapty-kmp-ui", version.ref = "adapty-kmp" }
```
El módulo `adapty-kmp-ui` solo es necesario si renderizas flows y paywalls con la capa Compose Multiplatform (`view.present()`). Consulta [Instalar Adapty SDK](sdk-installation-kotlin-multiplatform) para la configuración completa.
Los SDKs nativos subyacentes de Adapty se han actualizado a sus versiones 4.x en ambas plataformas y se resuelven automáticamente — no es necesario ningún cambio en la compilación. El deployment target de iOS se mantiene en **15.0**, sin cambios en esta versión.
## Obtener flows \{#fetching-flows\}
### getPaywall → getFlow
El tipo devuelto cambia de `AdaptyPaywall` a `AdaptyFlow`, y el parámetro `locale` se elimina — cuando renderizas un flow, el locale se resuelve automáticamente; para los paywalls personalizados, todos los locales se devuelven en `flow.remoteConfigs`:
```diff showLineNumbers
- Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en")
- .onSuccess { paywall ->
- // use the paywall
+ Adapty.getFlow("YOUR_PLACEMENT_ID")
+ .onSuccess { flow ->
+ // use the flow
}
.onError { error ->
// handle the error
}
```
`getPaywallForDefaultAudience` se renombra de la misma manera:
```diff showLineNumbers
- Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en")
+ Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID")
```
### getPaywallProducts(paywall) → getPaywallProducts(flow)
`getPaywallProducts` mantiene su nombre pero ahora recibe un `AdaptyFlow`:
```diff showLineNumbers
- Adapty.getPaywallProducts(paywall)
+ Adapty.getPaywallProducts(flow)
.onSuccess { products ->
// use the products
}
```
## Modelo de datos \{#data-model\}
`getFlow` devuelve un `AdaptyFlow` en lugar de un `AdaptyPaywall`, y la estructura del objeto ha cambiado:
| Propiedad v3 `AdaptyPaywall` | Propiedad v4 `AdaptyFlow` | Acción |
|---|---|---|
| `remoteConfig: AdaptyRemoteConfig?` (única) | `remoteConfigs: List
### Durante el inicio de sesión/registro \{#during-loginsignup\}
Si identificas a los usuarios después del inicio de la app (por ejemplo, cuando inician sesión o se registran), usa el método `identify` para establecer su customer user ID.
- Si **no has usado este customer user ID antes**, Adapty lo vinculará automáticamente al perfil actual.
- Si **ya has usado este customer user ID para identificar al usuario antes**, Adapty pasará a trabajar con el perfil asociado a ese customer user ID.
:::important
Los customer user IDs deben ser únicos para cada usuario. Si hardcodeas el valor del parámetro, todos los usuarios se considerarán como uno solo.
:::
Siempre usa `await` con `identify` antes de llamar a otros métodos del SDK. Las llamadas concurrentes generan `#3006 profileWasChanged` o aterrizan en el perfil anónimo. Consulta [Orden de llamadas en el SDK de React Native](react-native-sdk-call-order).
```typescript showLineNumbers
try {
await adapty.identify("YOUR_USER_ID"); // Unique for each user
// successfully identified
} catch (error) {
// handle the error
}
```
### Durante la activación del SDK \{#during-the-sdk-activation\}
Si ya conoces el customer user ID cuando activas el SDK, puedes enviarlo en el método `activate` en lugar de llamar a `identify` por separado.
Si conoces un customer user ID pero solo lo configuras después de la activación, eso significa que, al activarse, Adapty creará un nuevo perfil anónimo y solo pasará al existente cuando llames a `identify`.
Puedes pasar un customer user ID existente (uno que ya hayas usado antes) o uno nuevo. Si pasas uno nuevo, el perfil creado al activarse se vinculará automáticamente a ese customer user ID.
:::note
Por defecto, la creación de perfiles anónimos no afecta a los dashboards de análisis, porque las instalaciones se cuentan por IDs de dispositivo.
Un ID de dispositivo representa una única instalación de la app desde el store en un dispositivo y solo se regenera cuando la app se reinstala.
No depende de si es la primera instalación o una repetida, ni de si se usa un customer user ID existente.
Crear un perfil (al activar el SDK o al cerrar sesión), iniciar sesión o actualizar la app sin reinstalarla no genera eventos de instalación adicionales.
Si quieres contar las instalaciones por usuarios únicos en lugar de por dispositivos, ve a **App settings** y configura [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```typescript showLineNumbers
adapty.activate("PUBLIC_SDK_KEY", {
customerUserId: "YOUR_USER_ID" // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one.
});
```
### Cerrar sesión de usuarios \{#log-users-out\}
Si tienes un botón para cerrar la sesión de los usuarios, usa el método `logout`.
:::important
Cerrar la sesión crea un nuevo perfil anónimo para el usuario.
:::
```typescript showLineNumbers
try {
await adapty.logout();
// successful logout
} catch (error) {
// handle the error
}
```
:::info
Para volver a iniciar sesión en la app, usa el método `identify`.
:::
### Permitir compras sin inicio de sesión \{#allow-purchases-without-login\}
Si tus usuarios pueden realizar compras tanto antes como después de iniciar sesión en tu app, debes asegurarte de que mantengan el acceso después de iniciar sesión:
1. Cuando un usuario sin sesión iniciada realiza una compra, Adapty la vincula a su ID de perfil anónimo.
2. Cuando el usuario inicia sesión en su cuenta, Adapty pasa a trabajar con su perfil identificado.
- Si es un customer user ID nuevo (por ejemplo, la compra se realizó antes del registro), Adapty asigna el customer user ID al perfil actual, por lo que se mantiene todo el historial de compras.
- Si es un customer user ID existente (el customer user ID ya está vinculado a un perfil), necesitas obtener el nivel de acceso actual después del cambio de perfil. Puedes llamar a [`getProfile`](react-native-check-subscription-status) justo después de la identificación, o [escuchar las actualizaciones del perfil](react-native-check-subscription-status) para que los datos se sincronicen automáticamente.
## Próximos pasos \{#next-steps\}
¡Enhorabuena! Has implementado la lógica de pago in-app en tu app. ¡Te deseamos todo lo mejor con la monetización de tu app!
Para sacar aún más partido a Adapty, puedes explorar estos temas:
- [**Pruebas**](troubleshooting-test-purchases): Asegúrate de que todo funciona como se espera
- [**Onboardings**](react-native-onboardings): Engancha a los usuarios con onboardings y aumenta la retención
- [**Integraciones**](configuration): Integra con servicios de atribución de marketing y análisis con una sola línea de código
- [**Establecer atributos de perfil personalizados**](react-native-setting-user-attributes): Añade atributos personalizados a los perfiles de usuario y crea segmentos para lanzar pruebas A/B o mostrar diferentes paywalls a distintos usuarios
---
# File: adapty-sdk-integration-skill-react-native
---
---
title: "Integra Adapty en tu app de React Native con la skill de integración del SDK"
description: "Usa la skill adapty-sdk-integration para integrar el SDK de Adapty en tu app de React Native de principio a fin con tu herramienta de codificación con IA."
---
La [skill adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatiza la integración de Adapty de extremo a extremo: configuración del dashboard, instalación del SDK, paywall y verificación por etapas. Detecta tu plataforma automáticamente y obtiene la documentación de Adapty relevante en cada etapa.
**Herramientas compatibles**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Para instalarla, elige el formulario para tu herramienta. La lista completa está en el [README de la skill](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex u otra herramienta** — usa la [CLI de skills](https://skills.sh) (ten en cuenta que las skills instaladas de esta forma no se actualizan automáticamente):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
También puedes clonar el repositorio y copiar `skills/adapty-sdk-integration/` en el directorio de skills de tu herramienta.
Tras la instalación, ejecuta la skill en tu proyecto:
```
/adapty-sdk-integration
```
La skill hace algunas preguntas de configuración y luego te guía por la configuración del dashboard, la instalación del SDK, el paywall y la verificación.
:::important
La skill está en beta. Si se queda bloqueada o se comporta de forma inesperada, sigue la [guía de integración paso a paso](adapty-cursor-react-native) — te lleva a través de cada etapa con la documentación correcta.
:::
La [skill adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatiza la integración de Adapty de extremo a extremo: configuración del dashboard, instalación del SDK, paywall y verificación por etapas. Detecta tu plataforma automáticamente y obtiene la documentación de Adapty relevante en cada etapa.
**Herramientas compatibles**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Para instalarla, elige el formulario para tu herramienta. La lista completa está en el [README de la skill](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex u otra herramienta** — usa la [CLI de skills](https://skills.sh) (ten en cuenta que las skills instaladas de esta forma no se actualizan automáticamente):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
También puedes clonar el repositorio y copiar `skills/adapty-sdk-integration/` en el directorio de skills de tu herramienta.
Tras la instalación, ejecuta la skill en tu proyecto:
```
/adapty-sdk-integration
```
La skill hace algunas preguntas de configuración y luego te guía por la configuración del dashboard, la instalación del SDK, el paywall y la verificación.
---
# File: adapty-cursor-react-native
---
---
title: "Integra Adapty en tu app React Native con ayuda de IA"
description: "Una guía paso a paso para integrar Adapty en tu app React Native usando Cursor, Context7, ChatGPT, Claude u otras herramientas de IA."
---
Esta guía te lleva paso a paso por la integración de Adapty en tu app de React Native con una herramienta de codificación con IA: le proporcionas la documentación correcta de Adapty en el orden correcto.
For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command.
## Antes de empezar: configuración del dashboard \{#before-you-start-dashboard-setup\}
Adapty necesita algo de configuración en el dashboard antes de que escribas código con el SDK. Puedes hacerlo con una skill interactiva de LLM o manualmente desde el Dashboard.
### Enfoque con skill (recomendado) \{#skill-approach-recommended\}
El skill de Adapty CLI permite que tu LLM configure tu app, productos, niveles de acceso, paywalls y placements directamente — sin necesidad de abrir el Dashboard en cada paso. Solo necesitas [conectar tus stores](integrate-payments) en el Dashboard.
```
npx skills add adaptyteam/adapty-cli --skill adapty-cli
```
Una vez añadido el skill, ejecuta `/adapty-cli` en tu agente. Te guiará paso a paso — incluyendo cuándo abrir el Dashboard para conectar tus stores.
### Enfoque desde el dashboard
Si prefieres configurar todo de forma manual, esto es lo que necesitas antes de escribir código. Tu LLM no puede buscar los valores del dashboard por ti — tendrás que proporcionarlos.
1. **Conecta tus app stores**: En el Adapty Dashboard, ve a **App settings → General**. Conecta tanto App Store como Google Play si tu app tiene como destino ambas plataformas. Esto es necesario para que las compras funcionen.
[Conecta los app stores](integrate-payments)
2. **Copia tu clave SDK pública**: En el Adapty Dashboard, ve a **App settings → General** y busca la sección **API keys**. En el código, es la cadena que pasas a `adapty.activate("YOUR_PUBLIC_SDK_KEY")`.
3. **Crea al menos un producto**: En el Adapty Dashboard, ve a la página **Products**. No referencias los productos directamente en el código — Adapty los entrega a través de paywalls.
[Añadir productos](quickstart-products)
4. **Crea un paywall y un placement**: En el Adapty Dashboard, crea un paywall en la página **Paywalls** y luego asígnalo a un placement en la página **Placements**. En el código, el ID del placement es la cadena que pasas a `adapty.getPaywall("YOUR_PLACEMENT_ID")`.
[Crear paywall](quickstart-paywalls)
5. **Configura los niveles de acceso**: En el Adapty Dashboard, configúralos por producto en la página **Products**. En el código, la cadena que se comprueba es `profile.accessLevels['premium']?.isActive`. El nivel de acceso `premium` predeterminado funciona para la mayoría de las apps. Si los usuarios de pago acceden a funciones distintas según el producto (por ejemplo, un plan `basic` frente a un plan `pro`), [crea niveles de acceso adicionales](assigning-access-level-to-a-product) antes de empezar a programar.
:::tip
Una vez que tengas los cinco, estás listo para escribir código. Dile a tu LLM: "Mi clave SDK pública es X, mi ID de placement es Y" para que pueda generar el código de inicialización y de obtención de paywall correctamente.
:::
### Configura cuando estés listo \{#set-up-when-ready\}
Estos pasos no son necesarios para empezar a programar, pero los necesitarás a medida que tu integración madure:
- **Pruebas A/B**: Configúralas en la página **Placements**. No se requieren cambios en el código.
[Pruebas A/B](ab-tests)
- **Paywalls y placements adicionales**: Añade más llamadas `getPaywall` con distintos IDs de placement.
- **Integraciones de analíticas**: Configúralas en la página **Integrations**. La configuración varía según la integración. Consulta [integraciones de analíticas](analytics-integration) e [integraciones de atribución](attribution-integration).
## Proporciona la documentación de Adapty a tu LLM \{#feed-adapty-docs-to-your-llm\}
### Usar Context7 (recomendado)
[Context7](https://context7.com) es un servidor MCP que da a tu LLM acceso directo a la documentación actualizada de Adapty. Tu LLM obtiene automáticamente la documentación correcta según lo que preguntes, sin necesidad de pegar URLs manualmente.
Context7 funciona con **Cursor**, **Claude Code**, **Windsurf** y otras herramientas compatibles con MCP. Para configurarlo, ejecuta:
```
npx ctx7 setup
```
Esto detecta tu editor y configura el servidor Context7. Para la configuración manual, consulta el [repositorio de Context7 en GitHub](https://github.com/upstash/context7).
Una vez configurado, haz referencia a la biblioteca de Adapty en tus prompts:
```
Use the adaptyteam/adapty-docs library to look up how to install the React Native SDK
```
:::warning
Aunque Context7 elimina la necesidad de pegar enlaces de documentación manualmente, el orden de implementación es importante. Sigue el [recorrido de implementación](#implementation-walkthrough) paso a paso para asegurarte de que todo funciona correctamente.
:::
### Usa los documentos en texto plano
Puedes acceder a cualquier documento de Adapty en texto plano Markdown. Añade `.md` al final de su URL, o haz clic en **Copy for LLM** debajo del título del artículo. Por ejemplo: [adapty-cursor-react-native.md](https://adapty.io/docs/es/adapty-cursor-react-native.md).
Cada etapa del [recorrido de implementación](#implementation-walkthrough) a continuación incluye un bloque "Send this to your LLM" con enlaces `.md` para pegar.
Para acceder a más documentación de una vez, consulta los [archivos de índice y subconjuntos por plataforma](#plain-text-doc-index-files) a continuación.
## Guía de implementación paso a paso \{#implementation-walkthrough\}
El resto de esta guía recorre la integración de Adapty en orden de implementación. Cada etapa incluye la documentación que debes enviar a tu LLM, qué deberías ver al terminar y los problemas más habituales.
### Planifica tu integración \{#plan-your-integration\}
Antes de escribir código, pídele a tu LLM que analice tu proyecto y cree un plan de implementación. Si tu herramienta de IA tiene un modo de planificación (como el modo plan de Cursor o Claude Code), úsalo para que el LLM pueda leer tanto la estructura de tu proyecto como la documentación de Adapty antes de generar cualquier código.
Dile a tu LLM qué enfoque usas para las compras, ya que esto determina qué guías debe seguir:
- [**Adapty Paywall Builder**](adapty-paywall-builder): Creas paywalls en el editor sin código de Adapty y el SDK los renderiza automáticamente.
- [**Paywalls creados manualmente**](react-native-making-purchases): Construyes tu propia interfaz de paywall en código, pero sigues usando Adapty para obtener productos y gestionar compras.
- [**Modo observer**](observer-vs-full-mode): Mantienes tu infraestructura de compras existente y usas Adapty solo para análisis e integraciones.
¿No sabes cuál elegir? Consulta la [tabla comparativa en la guía de inicio rápido](react-native-quickstart-paywalls).
### Instalar y configurar el SDK \{#install-and-configure-the-sdk\}
Añade la dependencia del SDK de Adapty con npm (o yarn) y actívalo con tu clave SDK pública. Esta es la base: sin ella, nada más funciona.
Tenemos guías de instalación independientes para proyectos Expo y React Native puro — elige la que corresponda a tu configuración.
**Guías:**
- [Instalar con Expo](sdk-installation-react-native-expo)
- [Instalar con React Native puro](sdk-installation-react-native-pure)
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/es/sdk-installation-react-native-expo.md
- https://adapty.io/docs/es/sdk-installation-react-native-pure.md
```
:::tip[Checkpoint]
- **Esperado:** La app se compila y ejecuta tanto en iOS como en Android. Los logs de Metro bundler muestran el log de activación de Adapty.
- **Error frecuente:** "Public API key is missing" → comprueba que hayas reemplazado el marcador de posición con tu clave real desde **App settings**.
:::
### Mostrar paywalls y gestionar compras \{#show-paywalls-and-handle-purchases\}
Obtén un paywall por su ID de placement, muéstralo y gestiona los eventos de compra. Las guías que necesitas dependen de cómo gestiones las compras.
Prueba cada compra en el sandbox a medida que avanzas — no esperes hasta el final. Consulta [Probar compras en sandbox](test-purchases-in-sandbox) para ver las instrucciones de configuración.
Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché cuando existan. En este caso, los usuarios puede que no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché de actualización periódica descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN sea inaccesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| | **loadTimeoutMs** | por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo indicado en `loadTimeout`, ya que la operación puede implicar distintas solicitudes internamente.
Para Android: puedes crear un `TimeInterval` con funciones de extensión (como `5.seconds`, donde `.seconds` proviene de `import com.adapty.utils.seconds`), o con `TimeInterval.seconds(5)`. Para no establecer ningún límite, usa `TimeInterval.INFINITE`.
| Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | Un objeto `AdaptyFlow` con los identificadores del flow (`id`, `variationId`), el nombre, el placement, sus variantes de paywall (`paywalls`) y los Remote Configs (`remoteConfigs`). | ## Obtener la configuración de la vista \{#fetch-the-view-configuration\} :::important Asegúrate de activar el botón **Show on device** en el builder. Si esta opción no está activada, la configuración de la vista no estará disponible para recuperar. ::: Si el placement fue diseñado en el **Flow Builder** o en el **Paywall Builder**, Adapty renderiza la interfaz por ti. Crea la vista con `createFlowView` y, a continuación, [presenta el flow o el paywall](react-native-present-paywalls). Si el placement es un paywall personalizado sin interfaz del Builder, [trátalo como un paywall de Remote Config](present-remote-config-paywalls-react-native). En el SDK de React Native, llama a `createFlowView` directamente — no necesitas obtener primero la configuración de la vista. :::warning El resultado del método `createFlowView` solo puede usarse una vez. Si necesitas usarlo de nuevo, llama de nuevo al método `createFlowView`. Llamarlo dos veces sin recrearlo puede provocar el error `AdaptyUIError.viewAlreadyPresented`. ::: ```typescript showLineNumbers try { const view = await createFlowView(flow); } catch (error) { // handle the error } ``` Parámetros: | Parámetro | Presencia | Descripción | | :------------------- | :-------- | :----------------------------------------------------------- | | **flow** | obligatorio | Un objeto `AdaptyFlow` para obtener un controlador del flow/paywall deseado. | | **customTags** | opcional | Define un diccionario de etiquetas personalizadas y sus valores resueltos. Las etiquetas personalizadas actúan como marcadores de posición en el contenido, reemplazados dinámicamente por cadenas específicas para personalizar el contenido dentro del flow/paywall. Consulta el tema Custom tags in paywall builder para más detalles. | | **prefetchProducts** | opcional | Actívalo para optimizar el momento en que se muestran los productos en pantalla. Cuando es `true`, AdaptyUI recuperará automáticamente los productos necesarios. Valor predeterminado: `false`. | | **android.enableSafeArea** | opcional | Solo para Android (se ignora en iOS). Pásalo como objeto anidado: `android: { enableSafeArea: true }`. Cuando es `true`, la vista del flow aplica márgenes de área segura. Por defecto es `true` para la presentación modal (`createFlowView` + `present()`) y `false` para el componente `AdaptyFlowView` embebido. El valor predeterminado es adecuado para la mayoría de los casos. | :::note Si utilizas varios idiomas, aprende cómo añadir una [localización de flow](add-paywall-locale-in-adapty-paywall-builder) y cómo usar los códigos de idioma correctamente [aquí](react-native-localizations-and-locale-codes). ::: Una vez que tengas la vista, [muestra el flow/paywall](react-native-present-paywalls). ## Obtén un flow o paywall para la audiencia predeterminada y cárgalo más rápido \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} Por lo general, los flows y paywalls se cargan casi al instante, así que no tendrás que preocuparte por optimizar este proceso. Sin embargo, si tienes muchas audiencias y placements, y tus usuarios tienen una conexión a internet lenta, la carga de un flow o paywall puede tardar más de lo deseado. En esos casos, puede que quieras mostrar un flow o paywall predeterminado para garantizar una experiencia fluida, en lugar de no mostrar nada. Para solucionar esto, puedes usar el método `getFlowForDefaultAudience`, que obtiene el flow o paywall del placement especificado para la audiencia **All Users**. Sin embargo, es importante entender que el enfoque recomendado es obtener el flow o paywall con el método `getFlow`, tal como se explica en la sección [Obtener flow/paywall](#fetch-flowpaywall) anterior. :::warning Por qué recomendamos usar `getFlow` El método `getFlowForDefaultAudience` tiene algunos inconvenientes importantes: - **Posibles problemas de compatibilidad con versiones anteriores**: Si necesitas mostrar diferentes paywalls para distintas versiones de la app (la actual y futuras), podrías encontrarte con dificultades. Tendrás que diseñar paywalls que sean compatibles con la versión actual (heredada) o asumir que los usuarios con esa versión podrían tener problemas con paywalls que no se renderizan correctamente. - **Pérdida de targeting**: Todos los usuarios verán el mismo paywall diseñado para la audiencia **All Users**, lo que significa que pierdes la segmentación personalizada (incluyendo por país, atribución de marketing o tus propios atributos personalizados). Si estás dispuesto a aceptar estas desventajas para beneficiarte de una obtención más rápida del flow o paywall, usa el método `getFlowForDefaultAudience` de la siguiente manera. De lo contrario, quédate con `getFlow` descrito [arriba](#fetch-flowpaywall). ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const flow = await adapty.getFlowForDefaultAudience(id); // the requested flow/paywall } catch (error) { // handle the error } ``` | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen conexiones a internet inestables, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En ese caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de lo intermitente que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
| ## Personalizar assets \{#customize-assets\} Para personalizar imágenes y vídeos en tu flow/paywall, implementa los assets personalizados. Las imágenes y vídeos hero tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de assets personalizados, seleccionas estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. :::important Para usar esta función, actualiza el SDK de React Native de Adapty a la versión 3.8.0 o superior. ::: A continuación se muestra un ejemplo de cómo puedes proporcionar recursos personalizados mediante un diccionario simple: ```javascript const customAssets: Recordopcional
por defecto: `en`
|El identificador de la [localización del paywall](add-paywall-locale-in-adapty-paywall-builder). Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché de actualización periódica descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| | **loadTimeoutMs** | por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos poco frecuentes este método puede superar ligeramente el tiempo de espera especificado en `loadTimeout`, ya que la operación puede estar compuesta de distintas solicitudes internamente.
Para Android: puedes crear un `TimeInterval` con funciones de extensión (como `5.seconds`, donde `.seconds` proviene de `import com.adapty.utils.seconds`), o con `TimeInterval.seconds(5)`. Para no establecer ningún límite, usa `TimeInterval.INFINITE`.
| Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | Un objeto [`AdaptyPaywall`](https://react-native.adapty.io/interfaces/adaptypaywall) con una lista de IDs de productos, el identificador del paywall, Remote Config y otras propiedades. | ## Obtener la configuración de vista de un paywall diseñado con Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Asegúrate de activar el interruptor **Show on device** en el Paywall Builder. Si esta opción no está activada, la configuración de vista no estará disponible para recuperar. ::: Después de obtener el paywall, comprueba si incluye un `ViewConfiguration`, lo que indica que fue creado con Paywall Builder. Esto te indicará cómo mostrar el paywall. Si el `ViewConfiguration` está presente, trátalo como un paywall de Paywall Builder; si no, [trátalo como un paywall de Remote Config](present-remote-config-paywalls-react-native). En el SDK de React Native, llama directamente al método `createPaywallView` sin necesidad de obtener primero la configuración de vista manualmente. :::warning El resultado del método `createPaywallView` solo puede usarse una vez. Si necesitas volver a utilizarlo, llama de nuevo al método `createPaywallView`. Llamarlo dos veces sin recrearlo puede provocar el error `AdaptyUIError.viewAlreadyPresented`. ::: ```typescript showLineNumbers // for the Adapty SDK < 3.14 – import {createPaywallView} from 'react-native-adapty/dist/ui'; if (paywall.hasViewConfiguration) { try { const view = await createPaywallView(paywall); } catch (error) { // handle the error } } else { //use your custom logic } ``` Parámetros: | Parámetro | Presencia | Descripción | | :------------------- | :-------- | :----------------------------------------------------------- | | **paywall** | requerido | Un objeto `AdaptyPaywall` para obtener un controlador para el paywall deseado. | | **customTags** | opcional | Define un diccionario de etiquetas personalizadas y sus valores resueltos. Las etiquetas personalizadas actúan como marcadores de posición en el contenido del paywall, reemplazándose dinámicamente con cadenas específicas para personalizar el contenido. Consulta el tema Custom tags in paywall builder para más detalles. | | **prefetchProducts** | opcional | Actívalo para optimizar el momento en que se muestran los productos en pantalla. Cuando es `true`, AdaptyUI obtiene automáticamente los productos necesarios. Valor predeterminado: `false`. | :::note Si utilizas varios idiomas, aprende cómo añadir una [localización del Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) y cómo usar los códigos de idioma correctamente [aquí](react-native-localizations-and-locale-codes). ::: Una vez que tengas la vista, [muestra el paywall](react-native-present-paywalls). ## Obtén un paywall para la audiencia predeterminada y acelera la carga \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} Por lo general, los paywalls se cargan casi al instante, así que no tendrás que preocuparte por optimizar este proceso. Sin embargo, si tienes muchas audiencias y paywalls, y tus usuarios tienen una conexión a internet débil, la carga puede tardar más de lo deseable. En esas situaciones, puede que quieras mostrar un paywall predeterminado para garantizar una buena experiencia de usuario en lugar de no mostrar ninguno. Para abordar esto, puedes usar el método `getPaywallForDefaultAudience`, que obtiene el paywall del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el paywall con el método `getPaywall`, tal como se detalla en la sección [Obtener información del paywall](#fetch-paywall-designed-with-paywall-builder) más arriba. :::warning Por qué recomendamos usar `getPaywall` El método `getPaywallForDefaultAudience` tiene algunos inconvenientes importantes: - **Posibles problemas de compatibilidad con versiones anteriores**: Si necesitas mostrar diferentes paywalls para distintas versiones de la app (actual y futuras), es posible que te encuentres con dificultades. Tendrás que diseñar paywalls que sean compatibles con la versión actual (heredada) o asumir que los usuarios con esa versión podrían tener problemas con paywalls que no se renderizan correctamente. - **Pérdida de segmentación**: Todos los usuarios verán el mismo paywall diseñado para la audiencia **All Users**, lo que significa que pierdes la segmentación personalizada (incluida la basada en países, atribución de marketing o tus propios atributos personalizados). Si estás dispuesto a aceptar estas desventajas para beneficiarte de una obtención más rápida del paywall, usa el método `getPaywallForDefaultAudience` de la siguiente manera. De lo contrario, sigue usando `getPaywall` descrito [arriba](#fetch-paywall-designed-with-paywall-builder). ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywallForDefaultAudience(id, locale); // the requested paywall } catch (error) { // handle the error } ``` :::note El método `getPaywallForDefaultAudience` está disponible a partir de la versión 2.11.2 del SDK de React Native. ::: | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements). Es el valor que especificaste al crear un placement en tu Adapty Dashboard. | | **locale** |opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués brasileño.
Consulta [Localizaciones y códigos de idioma](react-native-localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la aplicación y solo se borra cuando se desinstala la app o mediante una limpieza manual.
| ## Personalizar recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu paywall, implementa recursos personalizados. Las imágenes y vídeos hero tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizado, seleccionas estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el Adapty Dashboard. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. :::important Para usar esta función, actualiza el SDK de React Native de Adapty a la versión 3.8.0 o superior. ::: Este es un ejemplo de cómo puedes proporcionar recursos personalizados mediante un diccionario simple: ```javascript const customAssets: Record
## El número de visualizaciones del paywall es demasiado alto \{#the-paywall-view-number-is-too-big\}
**Problema**: El contador de visualizaciones del paywall muestra el doble del número esperado.
**Motivo**: Es posible que estés llamando a `logShowFlow` (React Native SDK v4+) / `logShowPaywall` en tu código, lo que duplica el contador de visualizaciones si usas el Paywall Builder o el Flow Builder. Para flows y paywalls creados con estas herramientas, el seguimiento de analíticas es automático, por lo que no necesitas usar este método.
**Solución**: Asegúrate de no llamar a `logShowFlow` (React Native SDK v4+) / `logShowPaywall` en tu código si usas el Paywall Builder o el Flow Builder.
## Otros problemas \{#other-issues\}
**Problema**: Estás experimentando otros problemas relacionados con el Paywall Builder que no se tratan más arriba.
**Solución**: Si es necesario, migra el SDK a la versión más reciente siguiendo las [guías de migración](react-native-sdk-migration-guides). Muchos problemas se resuelven en versiones más nuevas del SDK.
---
# File: react-native-quickstart-manual
---
---
title: "Habilitar compras en tu paywall personalizado con React Native SDK"
description: "Integra el SDK de Adapty en tus paywalls personalizados de React Native para habilitar compras in-app."
---
Esta guía describe cómo integrar Adapty en tus paywalls personalizados. Mantén el control total sobre la implementación del paywall, mientras el SDK de Adapty obtiene los productos, gestiona las nuevas compras y restaura las anteriores.
:::important
**Esta guía es para desarrolladores que implementan paywalls personalizados.** Si buscas la forma más sencilla de habilitar compras, usa el [Adapty Flow Builder](react-native-quickstart-paywalls). Con Flow Builder, creas flows en un editor visual sin código, Adapty gestiona toda la lógica de compra automáticamente y puedes probar distintos diseños sin volver a publicar tu app.
:::
## Antes de empezar \{#before-you-start\}
### Configurar productos \{#set-up-products\}
Para habilitar las compras in-app, necesitas entender tres conceptos clave:
- [**Productos**](product) – todo lo que los usuarios pueden comprar (suscripciones, consumibles, acceso de por vida)
- [**Paywalls**](paywalls) – configuraciones que definen qué productos ofrecer. En Adapty, los paywalls son la única forma de recuperar productos, pero este diseño te permite modificar productos, precios y ofertas sin tocar el código de tu app.
- [**Placements**](placements) – dónde y cuándo mostrar los paywalls en tu app (por ejemplo, `main`, `onboarding`, `settings`). Configuras los paywalls para los placements en el dashboard y luego los solicitas por ID de placement en tu código. Esto facilita ejecutar pruebas A/B y mostrar distintos paywalls a distintos usuarios.
Asegúrate de entender estos conceptos incluso si trabajas con tu propio paywall personalizado. Básicamente, son tu forma de gestionar los productos que vendes en tu app.
Para implementar tu paywall personalizado, tendrás que crear un **paywall** y añadirlo a un **placement**. Esta configuración te permite recuperar tus productos. Para entender qué debes hacer en el dashboard, sigue la guía de inicio rápido [aquí](quickstart).
### Gestión de usuarios \{#manage-users\}
Puedes trabajar con o sin autenticación de backend de tu parte.
Sin embargo, el SDK de Adapty gestiona los usuarios anónimos e identificados de forma diferente. Lee la [guía de inicio rápido de identificación](react-native-quickstart-identify) para entender los detalles y asegurarte de que estás trabajando con los usuarios correctamente.
## Paso 1. Obtener productos \{#step-1-get-products\}
Para obtener los productos de tu paywall personalizado, necesitas:
1. Obtener el objeto `flow` pasando el ID del [placement](placements) al método `getFlow`.
2. Obtener el array de productos de este flow usando el método `getPaywallProducts`.
```typescript showLineNumbers
async function loadPaywall() {
try {
const flow: AdaptyFlow = await adapty.getFlow('YOUR_PLACEMENT_ID');
const products: AdaptyPaywallProduct[] = await adapty.getPaywallProducts(flow);
// Use products to build your custom paywall UI
} catch (error) {
// Handle the error
}
}
```
## Paso 2. Aceptar compras \{#step-2-accept-purchases\}
Cuando un usuario pulsa sobre un producto en tu paywall personalizado, llama al método `makePurchase` con el producto seleccionado. Esto gestionará el flow de compra y devolverá el perfil actualizado.
```typescript showLineNumbers
async function purchaseProduct(product: AdaptyPaywallProduct) {
try {
const purchaseResult: AdaptyPurchaseResult = await adapty.makePurchase(product);
switch (purchaseResult.type) {
case 'success':
// Purchase successful, profile updated
break;
case 'user_cancelled':
// User canceled the purchase
break;
case 'pending':
// Purchase is pending (e.g., user will pay offline with cash)
break;
}
} catch (error) {
// Handle the error
}
}
```
## Paso 3. Restaurar compras \{#step-3-restore-purchases\}
Los stores requieren que todas las aplicaciones con suscripciones ofrezcan una forma de que los usuarios puedan restaurar sus compras.
Llama al método `restorePurchases` cuando el usuario pulse el botón de restaurar. Esto sincronizará su historial de compras con Adapty y devolverá el perfil actualizado.
```typescript showLineNumbers
async function restorePurchases() {
try {
const profile: AdaptyProfile = await adapty.restorePurchases();
// Restore successful, profile updated
} catch (error) {
// Handle the error
}
}
```
## Próximos pasos \{#next-steps\}
:::tip
¿Tienes preguntas o estás teniendo algún problema? Consulta nuestro [foro de soporte](https://adapty.featurebase.app/) donde encontrarás respuestas a preguntas frecuentes o podrás plantear las tuyas. ¡Nuestro equipo y la comunidad están aquí para ayudarte!
:::
Tu paywall está listo para mostrarse en la app. Prueba tus compras en el [sandbox de App Store](test-purchases-in-sandbox) o en [Google Play Store](testing-on-android) para asegurarte de que puedes completar una compra de prueba desde el paywall. Para ver cómo funciona esto en una implementación lista para producción, consulta [CustomPurchaseScreen.tsx](https://github.com/adaptyteam/AdaptySDK-React-Native/blob/master/examples/ExpoGoWebMock/src/CustomPurchaseScreen.tsx) en nuestra app de ejemplo, donde se muestra el manejo de compras con gestión adecuada de errores, estados de carga y estado de la interfaz.
A continuación, [comprueba si los usuarios han completado su compra](react-native-check-subscription-status) para determinar si mostrar el paywall o conceder acceso a las funciones de pago.
---
# File: fetch-paywalls-and-products-react-native
---
---
title: "Obtener paywalls y productos para paywalls de Remote Config en el SDK de React Native"
description: "Obtén paywalls y productos en el SDK de React Native de Adapty para mejorar la monetización de los usuarios."
---
Por defecto, el SDK intentará cargar datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no recibir los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo irregular que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los flows y paywalls en dos capas: la caché actualizada regularmente descrita anteriormente y los [paywalls de respaldo](react-native-use-fallback-paywalls). También usamos CDN para cargar flows y paywalls más rápido, y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para asegurarse de que siempre obtengas la versión más reciente de tus flows, garantizando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeoutMs** | por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede agotar el tiempo de espera ligeramente después de lo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes peticiones internamente.
| :::note En v4, `getFlow` ya no acepta un parámetro `locale`. En el caso de los paywalls personalizados, todos los idiomas disponibles se devuelven en el Remote Config del flow (`flow.remoteConfigs`); elige el que corresponda al idioma del dispositivo o la configuración de la app del usuario. ::: ¡No escribas los IDs de productos en el código! Dado que los flows se configuran de forma remota, los productos disponibles, su cantidad y las ofertas especiales (como las pruebas gratuitas) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si inicialmente obtienes 2 productos, la app debería mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, la app debería mostrar los 3 sin necesidad de modificar el código. Lo único que debes escribir en el código es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | Un objeto `AdaptyFlow` que contiene el placement, los identificadores (`id`, `variationId`), el nombre, sus variaciones de paywall (`paywalls`) y un array `remoteConfigs` (una entrada por cada locale configurado). Para obtener los productos del flow, llama a `getPaywallProducts(flow)`. | ## Obtener productos \{#fetch-products\} Una vez que tienes el flow, puedes consultar el array de productos que le corresponde: ```typescript showLineNumbers try { // ...flow const products = await adapty.getPaywallProducts(flow); // the requested products list } catch (error) { // handle the error } ``` Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Lista de objetos [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) con: identificador del producto, nombre del producto, precio, moneda, duración de la suscripción y varias otras propiedades. | Al implementar tu propio diseño de paywall, probablemente necesitarás acceder a estas propiedades del objeto [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct). A continuación se ilustran las propiedades más utilizadas, pero consulta el documento enlazado para obtener todos los detalles sobre las propiedades disponibles. | Propiedad | Descripción | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Para mostrar el título del producto, usa `product.localizedTitle`. Ten en cuenta que la localización se basa en el país de la store seleccionado por el usuario, no en el idioma del dispositivo. | | **Price** | Para mostrar el precio en formato localizado, usa `product.price?.localizedString`. Esta localización se basa en la configuración de idioma del dispositivo. También puedes acceder al precio como número con `product.price?.amount`. El valor se proporcionará en la moneda local. Para obtener el símbolo de moneda correspondiente, usa `product.price?.currencySymbol`. | | **Subscription Period** | Para mostrar el período (p. ej., semana, mes, año, etc.), usa `product.subscription?.localizedSubscriptionPeriod`. Esta localización se basa en el idioma del dispositivo. Para obtener el período de suscripción de forma programática, usa `product.subscription?.subscriptionPeriod`. Desde ahí puedes acceder a la propiedad `unit` para conocer la unidad de tiempo ('day', 'week', 'month', 'year' o 'unknown'). El valor `numberOfUnits` te dará el número de unidades del período. Por ejemplo, para una suscripción trimestral verás `'month'` en la propiedad unit y `3` en la propiedad numberOfUnits. | | **Introductory Offer** | Para mostrar un distintivo u otro indicador de que una suscripción incluye una oferta introductoria, consulta la propiedad `product.subscription?.offer?.phases`. Es una lista que puede contener hasta dos fases de descuento: la fase de prueba gratuita y la fase de precio introductorio. Dentro de cada objeto de fase encontrarás las siguientes propiedades útiles:Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo intermitente que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.
|opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](react-native-localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no reciban los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando la app se reinstala o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls en dos capas: la caché de actualización regular descrita anteriormente y los [paywalls de respaldo](react-native-use-fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN sea inaccesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es limitada.
| | **loadTimeoutMs** | por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede estar compuesta de diferentes peticiones internamente.
| ¡No escribas los IDs de productos en el código! Dado que los paywalls se configuran de forma remota, los productos disponibles, el número de productos y las ofertas especiales (como períodos de prueba gratuitos) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si inicialmente obtienes 2 productos, tu app debería mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, tu app debería mostrar los 3 sin necesidad de cambios en el código. Lo único que debes escribir directamente en el código es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://react-native.adapty.io/interfaces/adaptypaywall) con: una lista de IDs de producto, el identificador del paywall, Remote Config y varias otras propiedades. | ## Obtener productos \{#fetch-products\} Una vez que tienes el paywall, puedes consultar el array de productos que le corresponde: ```typescript showLineNumbers try { // ...paywall const products = await adapty.getPaywallProducts(paywall); // the requested products list } catch (error) { // handle the error } ``` Parámetros de respuesta: | Parámetro | Descripción | | :-------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | Lista de objetos [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) con: identificador del producto, nombre del producto, precio, moneda, duración de la suscripción y otras propiedades. | Al implementar tu propio diseño de paywall, probablemente necesitarás acceder a estas propiedades del objeto [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct). A continuación se muestran las propiedades más utilizadas, pero consulta el documento enlazado para obtener todos los detalles sobre las propiedades disponibles. | Propiedad | Descripción | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Título** | Para mostrar el título del producto, usa `product.localizedTitle`. Ten en cuenta que la localización se basa en el país del store seleccionado por el usuario, no en el idioma del dispositivo. | | **Precio** | Para mostrar el precio localizado, usa `product.price?.localizedString`. La localización se basa en la configuración regional del dispositivo. También puedes acceder al precio como número con `product.price?.amount`. El valor se devolverá en la moneda local. Para obtener el símbolo de la moneda, usa `product.price?.currencySymbol`. | | **Período de suscripción** | Para mostrar el período (p. ej., semana, mes, año, etc.), usa `product.subscription?.localizedSubscriptionPeriod`. La localización se basa en la configuración regional del dispositivo. Para obtener el período de suscripción mediante código, usa `product.subscription?.subscriptionPeriod`. Desde ahí puedes acceder a la propiedad `unit` para conocer la unidad de tiempo (es decir, `'day'`, `'week'`, `'month'`, `'year'` o `'unknown'`). El valor `numberOfUnits` te dará el número de unidades del período. Por ejemplo, en una suscripción trimestral verás `'month'` en la propiedad `unit` y `3` en la propiedad `numberOfUnits`. | | **Oferta introductoria** | Para mostrar una etiqueta u otro indicador de que una suscripción incluye una oferta introductoria, consulta la propiedad `product.subscription?.offer?.phases`. Es una lista que puede contener hasta dos fases de descuento: la fase de prueba gratuita y la fase de precio introductorio. Dentro de cada objeto de fase encontrarás las siguientes propiedades útiles:opcional
predeterminado: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](react-native-localizations-and-locale-codes) para obtener más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | predeterminado: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si consideras que tus usuarios tienen una conexión a internet inestable, puedes usar `.returnCacheDataElseLoad` para devolver los datos en caché cuando estén disponibles. En este caso, puede que los usuarios no reciban los datos más recientes, pero experimentarán tiempos de carga más rápidos independientemente de la calidad de su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
|Si la solicitud se ha realizado correctamente, la respuesta contiene este objeto. Un objeto [AdaptyProfile](https://react-native.adapty.io/interfaces/adaptyprofile) proporciona información completa sobre los niveles de acceso, suscripciones y compras únicas de un usuario dentro de la app.
Comprueba el estado del nivel de acceso para determinar si el usuario tiene el acceso requerido a la app.
| :::warning **Nota:** si todavía usas una versión de StoreKit de Apple inferior a v2.0 y una versión del SDK de Adapty inferior a v2.9.0, debes proporcionar el [secreto compartido de Apple App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret) en su lugar. Este método está actualmente en desuso por Apple. ::: ## Cambiar de suscripción al realizar una compra \{#change-subscription-when-making-a-purchase\} Cuando un usuario opta por una nueva suscripción en lugar de renovar la actual, el funcionamiento depende del store: - En el App Store, la suscripción se actualiza automáticamente dentro del grupo de suscripciones. Si un usuario adquiere una suscripción de un grupo mientras ya tiene activa otra de un grupo diferente, ambas suscripciones estarán activas al mismo tiempo. - En Google Play, la suscripción no se actualiza automáticamente. Debes gestionar el cambio en el código de tu app como se describe a continuación. Para reemplazar una suscripción por otra en Android, llama al método `.makePurchase()` con el parámetro adicional: ```typescript showLineNumbers try { const purchaseResult = await adapty.makePurchase(product, params); switch (purchaseResult.type) { case 'success': const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features } break; case 'user_cancelled': // Handle the case where the user canceled the purchase break; case 'pending': // Handle deferred purchases (e.g., the user will pay offline with cash) break; } } catch (error) { // Handle the error } ``` Parámetro de solicitud adicional: | Parámetro | Presencia | Descripción | | :--------- | :-------- | :----------------------------------------------------------- | | **params** | requerido | un objeto del tipo [`MakePurchaseParamsInput`](https://react-native.adapty.io/types/makepurchaseparamsinput). | :::info **Versión 3.8.2+**: La estructura `MakePurchaseParamsInput` ha sido actualizada. `oldSubVendorProductId` y `prorationMode` ahora están anidados bajo `subscriptionUpdateParams`, e `isOfferPersonalized` se ha movido al nivel superior. ```javascript makePurchase(product, { android: { subscriptionUpdateParams: { oldSubVendorProductId: 'old_product_id', prorationMode: 'charge_prorated_price' }, isOfferPersonalized: true } }); ``` ::: Puedes leer más sobre suscripciones y modos de reemplazo en la documentación para desarrolladores de Google: - [Acerca de los modos de reemplazo](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recomendaciones de Google para los modos de reemplazo](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Modo de reemplazo [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Nota: este método solo está disponible para actualizaciones de suscripción. No se admiten cambios a un plan inferior. - Modo de reemplazo [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Nota: el cambio de suscripción real solo se producirá cuando finalice el período de facturación de la suscripción actual. ## Canjear códigos de oferta en iOS \{#redeem-offer-codes-in-ios\}Un objeto [`AdaptyProfile`](https://react-native.adapty.io/interfaces/adaptyprofile). Este modelo contiene información sobre niveles de acceso, suscripciones y compras únicas.
Comprueba el **estado del nivel de acceso** para determinar si el usuario tiene acceso a la app.
| :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: --- # File: implement-observer-mode-react-native --- --- title: "Implementar el modo Observer en React Native SDK" description: "Implementa el modo Observer en Adapty para rastrear eventos de suscripción de usuarios en React Native SDK." --- Si ya tienes tu propia infraestructura de compras y no estás listo para migrar completamente a Adapty, puedes explorar el [modo Observer](observer-vs-full-mode). En su forma básica, el modo Observer ofrece analíticas avanzadas e integración fluida con sistemas de atribución y analíticas. Si esto cubre tus necesidades, solo tienes que: 1. Activarlo al configurar el SDK de Adapty estableciendo el parámetro `observerMode` en `true`. Sigue las instrucciones de configuración para [React Native](sdk-installation-reactnative). 2. [Reportar transacciones](report-transactions-observer-mode-react-native) desde tu infraestructura de compras existente a Adapty. ### Configuración del modo Observer \{#observer-mode-setup\} Activa el modo Observer si gestionas las compras y el estado de la suscripción tú mismo y usas Adapty solo para enviar eventos de suscripción y analíticas. :::important Cuando se ejecuta en modo Observer, el SDK de Adapty no cerrará ninguna transacción, así que asegúrate de gestionarlas tú mismo. ::: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { observerMode: true, // Enable observer mode }); ``` Parámetros: | Parámetro | Descripción | | --------------------------- | ------------------------------------------------------------ | | observerMode | Un valor booleano que controla el [modo Observer](observer-vs-full-mode). El valor por defecto es `false`. | ## Usar los paywalls de Adapty en el modo Observer \{#using-adapty-paywalls-in-observer-mode\} Si también quieres usar los paywalls y las funciones de pruebas A/B de Adapty, puedes hacerlo, pero requiere una configuración adicional en el modo Observer. Esto es lo que necesitas hacer además de los pasos anteriores: 1. Muestra los paywalls de la forma habitual para los [paywalls de Remote Config](present-remote-config-paywalls-react-native). 3. [Asocia los paywalls](report-transactions-observer-mode-react-native) con las transacciones de compra. --- # File: report-transactions-observer-mode-react-native --- --- title: "Reportar transacciones en Observer Mode en el SDK de React Native" description: "Reporta transacciones de compra en el Observer Mode de Adapty para obtener información sobre usuarios y seguimiento de ingresos en el SDK de React Native." ---Para iOS, StoreKit 1: un objeto [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Para iOS, StoreKit 2: objeto [Transaction](https://developer.apple.com/documentation/storekit/transaction).
Para Android: identificador de cadena (purchase.getOrderId de la compra, donde la compra es una instancia de la clase [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la biblioteca de facturación.
| | variationId | obligatorio | El identificador de cadena de la variante. Puedes obtenerlo usando la propiedad `variationId` del objeto [AdaptyPaywall](https://react-native.adapty.io/interfaces/adaptypaywall). |phoneNumber
firstName
lastName
| String | | gender | Enum, los valores permitidos son: `female`, `male`, `other` | | birthday | Date | ### Atributos de usuario personalizados \{#custom-user-attributes\} Puedes definir tus propios atributos personalizados. Estos suelen estar relacionados con el uso de tu app. Por ejemplo, en aplicaciones de fitness pueden ser el número de ejercicios por semana; en apps de aprendizaje de idiomas, el nivel de conocimiento del usuario, etc. Puedes usarlos en segmentos para crear paywalls y ofertas dirigidas, y también en analíticas para determinar qué métricas de producto influyen más en los ingresos. ```typescript showLineNumbers try { await adapty.updateProfile({ codableCustomAttributes: { key_1: 'value_1', key_2: 2, }, }); } catch (error) { // handle `AdaptyError` } ``` Para eliminar una clave existente, usa el método `.withRemoved(customAttributeForKey:)`: ```typescript showLineNumbers try { // to remove a key, pass null as its value await adapty.updateProfile({ codableCustomAttributes: { key_1: null, key_2: null, }, }); } catch (error) { // handle `AdaptyError` } ``` A veces necesitas saber qué atributos personalizados ya están configurados. Para ello, usa el campo `customAttributes` del objeto `AdaptyProfile`. :::warning Ten en cuenta que el valor de `customAttributes` puede estar desactualizado, ya que los atributos de usuario pueden enviarse desde distintos dispositivos en cualquier momento, por lo que los atributos en el servidor podrían haber cambiado después de la última sincronización. ::: ### Límites \{#limits\} - Hasta 30 atributos personalizados por usuario - Los nombres de clave pueden tener hasta 30 caracteres. El nombre de la clave puede incluir caracteres alfanuméricos y cualquiera de los siguientes: `_` `-` `.` - El valor puede ser una cadena de texto o un número flotante con un máximo de 50 caracteres. --- # File: react-native-listen-subscription-changes --- --- title: "Comprobar el estado de suscripción en el SDK de React Native" description: "Haz seguimiento y gestión del estado de suscripción del usuario en Adapty para mejorar la retención de clientes en tu app de React Native." --- Con Adapty, hacer seguimiento del estado de suscripción es muy sencillo. No tienes que insertar manualmente los IDs de producto en tu código. En su lugar, puedes comprobar fácilmente el estado de suscripción de un usuario verificando si tiene un [nivel de acceso](access-level) activo.Un objeto [AdaptyProfile](https://react-native.adapty.io/interfaces/adaptyprofile). Por lo general, solo necesitas comprobar el estado del nivel de acceso del perfil para determinar si el usuario tiene acceso premium a la app.
El método `.getProfile` devuelve el resultado más actualizado, ya que siempre intenta consultar la API. Si por algún motivo (por ejemplo, sin conexión a internet) el SDK de Adapty no puede recuperar información del servidor, se devolverán los datos de la caché. También es importante tener en cuenta que el SDK de Adapty actualiza la caché de `AdaptyProfile` de forma periódica para mantener esta información lo más actualizada posible.
| El método `.getProfile()` te proporciona el perfil de usuario desde el que puedes obtener el estado del nivel de acceso. Puedes tener múltiples niveles de acceso por app. Por ejemplo, si tienes una app de noticias y vendes suscripciones a diferentes temáticas de forma independiente, puedes crear niveles de acceso "sports" y "science". Pero la mayoría de las veces solo necesitarás un nivel de acceso; en ese caso, puedes usar simplemente el nivel de acceso predeterminado "premium". Aquí tienes un ejemplo para comprobar el nivel de acceso "premium" predeterminado: ```typescript showLineNumbers try { const profile = await adapty.getProfile(); const isActive = profile.accessLevels?.["premium"]?.isActive; if (isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` ### Escuchar actualizaciones del estado de suscripción \{#listening-for-subscription-status-updates\} Cada vez que cambia la suscripción del usuario, Adapty lanza un evento. Para recibir mensajes de Adapty, necesitas realizar algunas configuraciones adicionales: ```typescript showLineNumbers // Create an "onLatestProfileLoad" event listener adapty.addEventListener('onLatestProfileLoad', profile => { // handle any changes to subscription state }); ``` Adapty también lanza un evento al iniciar la aplicación. En ese caso, se pasará el estado de suscripción almacenado en caché. ### Caché del estado de suscripción \{#subscription-status-cache\} La caché implementada en el SDK de Adapty almacena el estado de suscripción del perfil. Esto significa que, aunque el servidor no esté disponible, se puede acceder a los datos en caché para obtener información sobre el estado de suscripción del perfil. No obstante, hay que tener en cuenta que no es posible solicitar datos directamente desde la caché. El SDK consulta el servidor periódicamente cada minuto para comprobar si hay actualizaciones o cambios relacionados con el perfil. Si hay alguna modificación, como nuevas transacciones u otras actualizaciones, se enviarán a los datos en caché para mantenerlos sincronizados con el servidor. --- # File: react-native-deal-with-att --- --- title: "Gestionar ATT en el SDK de React Native" description: "Empieza con Adapty en React Native para simplificar la configuración y gestión de suscripciones." --- Si tu aplicación utiliza el framework AppTrackingTransparency y muestra al usuario una solicitud de autorización de seguimiento de la app, debes enviar el [estado de autorización](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) a Adapty. ```typescript showLineNumbers try { await adapty.updateProfile({ // you can also pass a string value (validated via tsc) if you prefer appTrackingTransparencyStatus: AppTrackingTransparencyStatus.Authorized, }); } catch (error) { // handle `AdaptyError` } ``` :::warning Te recomendamos encarecidamente que envíes este valor lo antes posible cuando cambie; solo así los datos se enviarán a tiempo a las integraciones que hayas configurado. ::: --- # File: kids-mode-react-native --- --- title: "Modo Kids en React Native SDK" description: "Activa fácilmente el Modo Kids para cumplir con las políticas de Apple y Google. Sin IDFA, GAID ni datos publicitarios en React Native SDK." --- Si tu aplicación React Native está destinada a niños, debes seguir las políticas de [Apple](https://developer.apple.com/kids/) y [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si usas el SDK de Adapty, unos pocos pasos sencillos te ayudarán a configurarlo para cumplir con estas políticas y superar las revisiones de las tiendas. :::important En iOS, el modo Kids se activa mediante el trait de Swift Package `KidsMode`, que elimina en compilación todo el código relacionado con IDFA, AdSupport y AppTrackingTransparency. Requiere el SDK v4 (que instala el SDK nativo de iOS a través de Swift Package Manager) y **Xcode 26** o posterior. Consulta [Actualizaciones en tu iOS Podfile](#updates-in-your-ios-podfile) a continuación. ::: ## ¿Qué se necesita? \{#whats-required\} Tienes que configurar el SDK para desactivar la recopilación de: - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) (iOS) - [Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) (Android) - [Dirección IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) Además, te recomendamos usar el customer user ID con cuidado. Un ID de usuario con formato `opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto de una o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda, a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués brasileño.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo irregular que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché se mantiene intacta al reiniciar la app y solo se borra cuando se desinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché de actualización periódica descrita anteriormente y los onboardings de respaldo. También usamos CDN para cargar los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus onboardings, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeoutMs** | por defecto: 5 seg |Este valor limita el tiempo de espera de este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el fallback local.
Ten en cuenta que en casos excepcionales este método puede agotarse ligeramente después del tiempo especificado en `loadTimeout`, ya que la operación puede estar compuesta de diferentes solicitudes internamente.
| Parámetros de respuesta: | Parámetro | Descripción | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objeto [`AdaptyOnboarding`](https://react-native.adapty.io/interfaces/adaptyonboarding) con: el identificador y la configuración del onboarding, Remote Config y varias otras propiedades. | ## Acelera la obtención del onboarding con el onboarding de audiencia predeterminada \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Por lo general, los onboardings se obtienen casi de forma instantánea, así que no tienes que preocuparte por acelerar este proceso. Sin embargo, cuando tienes muchas audiencias y onboardings, y tus usuarios tienen una conexión a internet débil, obtener un onboarding puede tardar más de lo deseado. En esos casos, puede que quieras mostrar un onboarding predeterminado para garantizar una experiencia de usuario fluida en lugar de no mostrar ningún onboarding. Para solucionar esto, puedes usar el método `getOnboardingForDefaultAudience`, que obtiene el onboarding del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el onboarding con el método `getOnboarding`, tal como se detalla en la sección [Obtener onboarding](#fetch-onboarding) anterior. :::warning Considera usar `getOnboarding` en lugar de `getOnboardingForDefaultAudience`, ya que este último tiene limitaciones importantes: - **Problemas de compatibilidad**: Puede generar problemas al dar soporte a varias versiones de la app, lo que obliga a diseñar con compatibilidad hacia atrás o asumir que las versiones antiguas podrían mostrarse incorrectamente. - **Sin personalización**: Solo muestra contenido para la audiencia "All Users", eliminando la segmentación por país, atribución o atributos personalizados. Si la obtención más rápida compensa estos inconvenientes en tu caso de uso, utiliza `getOnboardingForDefaultAudience` como se muestra a continuación. De lo contrario, usa `getOnboarding` como se describe [arriba](#fetch-onboarding). ::: ```typescript showLineNumbers try { const placementId = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const onboarding = await adapty.getOnboardingForDefaultAudience(placementId, locale); // el onboarding solicitado } catch (error) { // manejar el error } ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | requerido | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto por uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, puede que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo irregular que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar peticiones de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché de actualización periódica descrita anteriormente y los onboardings de respaldo. También usamos CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus onboardings y al mismo tiempo asegurar la fiabilidad incluso cuando la conexión a internet es escasa.
| --- # File: react-native-present-onboardings --- --- title: "Presentar onboardings en el SDK de React Native" description: "Descubre cómo presentar onboardings en React Native para aumentar conversiones e ingresos." --- :::warning **Los onboardings están obsoletos en el SDK v4 y se eliminarán en una versión futura.** Ya no reciben correcciones ni mejoras. Usa [flows](react-native-get-pb-paywalls) en su lugar: a diferencia de los onboardings, que se ejecutan dentro de un WebView, los flows se renderizan de forma nativa en el dispositivo, lo que ofrece animaciones más fluidas, una apariencia nativa coherente, tiempos de carga más rápidos y sin dependencia del entorno WebView. Consulta [Obtener flows y paywalls](react-native-get-pb-paywalls) y [Mostrar flows y paywalls](react-native-present-paywalls) para empezar. ::: Si has personalizado un onboarding usando el builder, no necesitas preocuparte por renderizarlo en el código de tu aplicación móvil para mostrárselo al usuario. Ese onboarding incluye tanto lo que debe mostrarse como la forma en que debe mostrarse. Antes de empezar, asegúrate de que: 1. Tienes instalado el [SDK de Adapty para React Native](sdk-installation-reactnative) 3.8.0 o posterior. 2. Has [creado un onboarding](create-onboarding). 3. Has añadido el onboarding a un [placement](placements). El SDK de Adapty para React Native ofrece dos formas de presentar onboardings: - **Componente React**: El componente embebido te permite integrarlo en la arquitectura y el sistema de navegación de tu app. - **Presentación modal** ## Componente React \{#react-component\} Para insertar un onboarding dentro de tu árbol de componentes existente, usa el componente `AdaptyOnboardingView` directamente en la jerarquía de componentes de React Native. El componente embebido te permite integrarlo en la arquitectura y el sistema de navegación de tu app. :::note En Android, recomendamos configuración adicional para `AdaptyOnboardingView` para evitar un artefacto visual de renderizado. Consulta [La interfaz del sistema se superpone al contenido del onboarding en Android](#system-ui-overlaps-onboarding-content-on-android). :::
Luego, puedes usar este ID en tu código y gestionarlo como una acción personalizada. Por ejemplo, si el usuario pulsa un botón personalizado, como **Login** o **Allow notifications**, el manejador de eventos se activará con el parámetro `actionId` que coincide con el **Action ID** del builder. Puedes crear tus propios IDs, como "allowNotifications".
:::important
Ten en cuenta que debes gestionar qué ocurre cuando el usuario cierra el onboarding. Por ejemplo, debes dejar de mostrar el propio onboarding.
:::
2. Haz clic en el nombre del grupo de suscripción. Verás tus productos listados en la sección **Subscriptions**.
3. Asegúrate de que el producto que estás probando esté marcado como **Ready to Submit**.
4. Compara el ID de producto de la tabla con el que aparece en la pestaña [**Products**](https://app.adapty.io/products) del Adapty Dashboard. Si los IDs no coinciden, copia el ID del producto de la tabla y [crea un producto](create-product) con ese ID en el Adapty Dashboard.
## Paso 3. Verifica la disponibilidad del producto \{#step-4-check-product-availability\}
1. Vuelve a **App Store Connect** y abre la misma sección **Subscriptions**.
2. Haz clic en el nombre del grupo de suscripción para ver tus productos.
3. Selecciona el producto que estás probando.
4. Desplázate hasta la sección **Availability** y comprueba que todos los países y regiones necesarios aparecen en la lista.
## Paso 4. Verifica los precios del producto \{#step-5-check-product-prices\}
1. De nuevo, ve a la sección **Monetization** → **Subscriptions** en **App Store Connect**.
2. Haz clic en el nombre del grupo de suscripción.
3. Selecciona el producto que estás probando.
4. Desplázate hacia abajo hasta **Subscription Pricing** y despliega la sección **Current Pricing for New Subscribers**.
5. Asegúrate de que todos los precios necesarios aparecen en la lista.
## Paso 5. Verifica que el estado de pago de la app, la cuenta bancaria y los formularios fiscales estén activos \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\}
1. En la página de inicio de [**App Store Connect**](https://appstoreconnect.apple.com/), haz clic en **Business**.
2. Selecciona el nombre de tu empresa.
3. Desplázate hacia abajo y comprueba que tu **Paid Apps Agreement**, **Bank Account** y **Tax forms** muestran el estado **Active**.
Siguiendo estos pasos deberías poder resolver la advertencia `InvalidProductIdentifiers` y publicar tus productos en el store.
## Paso 6. Recrea el producto si está bloqueado \{#step-6-recreate-the-product-if-its-stuck\}
Los pasos 1 a 5 pueden superarse correctamente —estado `Approved`, Bundle ID coincidente, API key válida— y aun así el SDK devuelve `1000 noProductIDsFound`. En ese caso, es posible que el producto esté bloqueado en el registro de Apple. El registro de productos de Apple puede entrar ocasionalmente en un estado en el que un producto existe en la interfaz de App Store Connect pero no está expuesto en la ruta de búsqueda de StoreKit.
Elimina el producto en App Store Connect y vuelve a crearlo con el mismo ID de producto. Espera hasta 24 horas tras la recreación para que los cambios se propaguen.
---
# File: cantMakePayments-react-native
---
---
title: "Solución para el error Code-1003 cantMakePayment en el SDK de React Native"
description: "Resuelve el error de pago al gestionar suscripciones en Adapty."
---
El error 1003, `cantMakePayments`, indica que no es posible realizar compras in-app en este dispositivo.
Si encuentras el error `cantMakePayments`, normalmente se debe a una de estas razones:
- Restricciones del dispositivo: El error no está relacionado con Adapty. Consulta las soluciones más abajo.
- Configuración del modo Observer: El método `makePurchase` y el modo Observer no pueden usarse al mismo tiempo. Consulta la sección más abajo.
## Problema: Restricciones del dispositivo \{#issue-device-restrictions\}
| Problema | Solución |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| Restricciones de Screen Time | Desactiva las restricciones de compras in-app en [Screen Time](https://support.apple.com/en-us/102470) |
| Cuenta suspendida | Contacta con el soporte de Apple para resolver problemas con la cuenta |
| Restricciones regionales | Usa una cuenta de App Store de una región compatible |
## Problema: Usar el modo Observer y makePurchase a la vez \{#issue-using-both-observer-mode-and-makepurchase\}
Si usas `makePurchases` para gestionar las compras, no necesitas el modo Observer. El [modo Observer](observer-vs-full-mode) solo es necesario si implementas la lógica de compra tú mismo.
Por lo tanto, si usas `makePurchase`, puedes eliminar sin problema la activación del modo Observer del código de inicialización del SDK.
---
# File: migration-to-react-native-sdk-v4
---
---
title: "Migrar el SDK de React Native de Adapty a la versión 4.0"
description: "Migra al SDK de React Native de Adapty v4.0 (beta) reemplazando las APIs de paywall por APIs de flow, compatibles tanto con Flow Builder como con Paywall Builder."
---
El SDK de React Native de Adapty 4.0 (beta) introduce los flows y cambia el nombre de las APIs de paywall en consecuencia. Las nuevas APIs funcionan tanto con el nuevo Flow Builder como con el Paywall Builder existente — no se requieren cambios de configuración en el Adapty Dashboard.
## Referencia rápida \{#quick-reference\}
| v3 | v4 |
|---|---|
| `adapty.getPaywall(placementId, locale?, params?)` | `adapty.getFlow(placementId, params?)` |
| `adapty.getPaywallForDefaultAudience(placementId, locale?, params?)` | `adapty.getFlowForDefaultAudience(placementId, params?)` |
| `adapty.getPaywallProducts(paywall)` | `adapty.getPaywallProducts(flow)` |
| `adapty.logShowPaywall(paywall)` | `adapty.logShowFlow(flow)` |
| `AdaptyPaywall` (tipo) | `AdaptyFlow` |
| `createPaywallView(paywall)` | `createFlowView(flow)` |
| `AdaptyPaywallView` (componente) | `AdaptyFlowView` |
| `EventHandlers` (tipo) | `FlowEventHandlers` |
| `onPaywallShown` | `onAppeared` |
| `onPaywallClosed` | `onDisappeared` |
| `onRenderingFailed` | `onError` |
`AdaptyPaywallProduct` mantiene su nombre — los productos siguen perteneciendo a un flow, y `getPaywallProducts` ahora acepta un `AdaptyFlow`. Los métodos `getFlow` y `getFlowForDefaultAudience` ya no reciben un parámetro `locale`. Los métodos de vista `present`, `dismiss`, `setEventHandlers` y `showDialog`, y los manejadores de eventos `onCloseButtonPress`, `onUrlPress`, `onCustomAction`, `onProductSelected`, `onPurchaseStarted`, `onPurchaseCompleted`, `onPurchaseFailed`, `onRestoreStarted`, `onRestoreCompleted`, `onRestoreFailed`, `onLoadingProductsFailed`, `onWebPaymentNavigationFinished` y `onAndroidSystemBack` conservan los mismos nombres que en v3. Algunos comportamientos predeterminados han cambiado — consulta [Cambios en el comportamiento predeterminado](#default-behavior-changes).
## Versión mínima de iOS \{#minimum-ios-version\}
Adapty React Native SDK 4.0 eleva el deployment target mínimo de iOS 13.0 a **iOS 15.0**. Establece tu deployment target de iOS en 15.0 o superior antes de actualizar.
## Instalación \{#installation\}
### Actualizar el paquete \{#update-the-package\}
v4.0 es una versión previa al lanzamiento, así que fija la versión exacta: npm no selecciona versiones pre-release mediante rangos con caret/tilde:
```bash showLineNumbers
npm install react-native-adapty@4.0.0
# or
yarn add react-native-adapty@4.0.0
```
### iOS: los SDKs nativos ahora se obtienen a través de Swift Package Manager \{#ios-native-sdks-now-come-through-swift-package-manager\}
[El repositorio de specs de CocoaPods pasará a ser de solo lectura en diciembre de 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/), por lo que a partir de la v4 los SDKs nativos `Adapty`, `AdaptyUI` y `AdaptyPlugin` **ya no se descargan como sub-dependencias de CocoaPods** — el podspec los obtiene a través de **Swift Package Manager** (mediante el helper `spm_dependency`). Esto requiere dos cosas:
- **React Native 0.75 o posterior** — necesario para el helper `spm_dependency` del podspec. Con una versión anterior, `pod install` falla con un error explícito; actualiza React Native primero, o quédate con `react-native-adapty` 3.x.
- **Frameworks dinámicos** — las dependencias SPM requieren enlace dinámico. La forma de habilitarlo difiere entre Expo y React Native sin configuración adicional.
#### Expo
Añade el plugin de configuración [`expo-build-properties`](https://docs.expo.dev/versions/latest/sdk/build-properties/) y establece los frameworks de iOS como dinámicos en `app.json` (o `app.config.js`):
```json showLineNumbers title="app.json"
{
"expo": {
"plugins": [
[
"expo-build-properties",
{
"ios": {
"useFrameworks": "dynamic"
}
}
]
]
}
}
```
Luego instala el plugin y regenera el proyecto nativo:
```bash showLineNumbers
npx expo install expo-build-properties
npx expo prebuild --clean
```
#### Bare React Native
Añade los frameworks dinámicos a tu target de iOS y reinstala los pods:
```ruby showLineNumbers title="ios/Podfile"
use_frameworks! :linkage => :dynamic
```
```bash showLineNumbers
cd ios && pod install --repo-update
```
Si anteriormente incluiste `Adapty`, `AdaptyUI` o `AdaptyPlugin` como sub-dependencias de CocoaPods, elimina primero cualquier línea `pod 'Adapty'`, `pod 'AdaptyUI'` o `pod 'AdaptyPlugin'` de tu `Podfile`.
:::warning
Cambiar del enlace estático predeterminado a frameworks dinámicos puede entrar en conflicto con bibliotecas que aún no admiten encabezados modulares y es incompatible con Flipper. Si encuentras problemas de compilación, consulta este [artículo sobre cómo integrar Swift Package Manager con bibliotecas de React Native](https://www.callstack.com/blog/integrating-swift-package-manager-with-react-native-libraries).
:::
Consulta [Instalar el SDK de Adapty](sdk-installation-reactnative) para ver la configuración completa.
## Obtención de flows \{#fetching-flows\}
### getPaywall → getFlow
El tipo devuelto cambia de `AdaptyPaywall` a `AdaptyFlow`, y se elimina el parámetro `locale` — cuando renderizas un flow, el idioma se resuelve automáticamente; para paywalls personalizados, todos los idiomas están disponibles en `flow.remoteConfigs`:
```diff showLineNumbers
- const paywall = await adapty.getPaywall('YOUR_PLACEMENT_ID', 'en');
+ const flow = await adapty.getFlow('YOUR_PLACEMENT_ID');
```
`getPaywallForDefaultAudience` se renombra de la misma forma:
```diff showLineNumbers
- const paywall = await adapty.getPaywallForDefaultAudience('YOUR_PLACEMENT_ID', 'en');
+ const flow = await adapty.getFlowForDefaultAudience('YOUR_PLACEMENT_ID');
```
### getPaywallProducts(paywall) → getPaywallProducts(flow)
`getPaywallProducts` mantiene su nombre pero ahora recibe un `AdaptyFlow`:
```diff showLineNumbers
- const products = await adapty.getPaywallProducts(paywall);
+ const products = await adapty.getPaywallProducts(flow);
```
## Modelo de datos \{#data-model\}
`getFlow` devuelve un `AdaptyFlow` en lugar de un `AdaptyPaywall`, y la forma del objeto ha cambiado:
| Campo de v3 `AdaptyPaywall` | Campo de v4 `AdaptyFlow` | Acción |
|---|---|---|
| `remoteConfig?` (único) | `remoteConfigs?: AdaptyRemoteConfig[]` (array) | Un flow lleva un Remote Config por idioma configurado. Lee el que corresponde al usuario: `flow.remoteConfigs?.find((c) => c.lang === 'en')`. |
| `products` | `flow.paywalls[i].productIdentifiers` | Los identificadores de producto ahora están en cada variación del flow, no en el flow en sí. |
| `webPurchaseUrl?` | `flow.paywalls[i].webPurchaseUrl` | Se ha movido del flow a cada variación de paywall. |
| `version?: number` | `flowVersionId?: string` | Renombrado, y el tipo ha cambiado de `number` a `string`. |
| `hasViewConfiguration` | eliminado | Elimina cualquier comprobación de `hasViewConfiguration` de tu código. |
| `requestLocale` | eliminado | La configuración regional ya no forma parte del modelo. |
| _(nuevo)_ | `paywalls: AdaptyFlowPaywall[]` | Cada entrada es una variación de paywall dentro del flow. |
| _(nuevo)_ | `responseCreatedAt: number` | Marca de tiempo de la respuesta del servidor, en milisegundos. |
Product identifiers moved from the flow to each variation:
```diff showLineNumbers
- const ids = paywall.products;
+ const ids = flow.paywalls[0].productIdentifiers;
```
## Métodos de paywall web \{#web-paywall-methods\}
`openWebPaywall` y `createWebPaywallUrl` mantienen sus nombres, pero el primer argumento es ahora un `AdaptyFlowPaywall` (una variante de flow) en lugar de un `AdaptyPaywall`. Puedes seguir pasando un `AdaptyPaywallProduct`.
```diff showLineNumbers
const flow = await adapty.getFlow('YOUR_PLACEMENT_ID');
- await adapty.openWebPaywall(paywall);
+ await adapty.openWebPaywall(flow.paywalls[0]);
```
## Seguimiento de visualizaciones de flows \{#tracking-flow-views\}
### logShowPaywall → logShowFlow
`logShowPaywall` ha pasado a llamarse `logShowFlow` y ahora recibe un `AdaptyFlow`. El evento se sigue registrando contra la misma variación, por lo que las métricas de embudo y las pruebas A/B existentes siguen funcionando sin cambios en el dashboard.
```diff showLineNumbers
- await adapty.logShowPaywall(paywall);
+ await adapty.logShowFlow(flow);
```
Al igual que en v3, no es necesario llamar a este método cuando se muestran flows o paywalls renderizados por el [Flow Builder](adapty-flow-builder) o el [Paywall Builder](adapty-paywall-builder) — Adapty registra esas vistas automáticamente.
## Mostrar flows \{#displaying-flows\}
### createPaywallView → createFlowView
Renombra la función de fábrica y pasa el `AdaptyFlow`. Los métodos del controlador devuelto (`present`, `dismiss`, `setEventHandlers`, `showDialog`) no cambian:
```diff showLineNumbers
- import { createPaywallView } from 'react-native-adapty';
+ import { createFlowView } from 'react-native-adapty';
- const view = await createPaywallView(paywall);
+ const view = await createFlowView(flow);
await view.present();
```
### AdaptyPaywallView → AdaptyFlowView
Si renderizas con el componente React, renómbralo y pasa el prop `flow`:
```diff showLineNumbers
- import { AdaptyPaywallView } from 'react-native-adapty';
+ import { AdaptyFlowView } from 'react-native-adapty';
- ```diff showLineNumbers - subscriptionDetails?: AdaptySubscriptionDetails; + subscription?: AdaptySubscriptionDetails; ``` 2. [AdaptySubscriptionDetails](https://react-native.adapty.io/interfaces/adaptysubscriptiondetails): - `promotionalOffer` ha sido eliminado. Ahora la oferta promocional se entrega dentro de la propiedad `offer` solo si está disponible. En ese caso, `offer?.identifier?.type` será `'promotional'`. - `introductoryOfferEligibility` ha sido eliminado (las ofertas solo se devuelven si el usuario es elegible). - `offerId` ha sido eliminado. El ID de la oferta ahora se almacena en `AdaptySubscriptionOffer.identifier`. - `offerTags` se ha movido a `AdaptySubscriptionOffer.android`.
```diff showLineNumbers - introductoryOffers?: AdaptyDiscountPhase[]; + offer?: AdaptySubscriptionOffer; ios?: { - promotionalOffer?: AdaptyDiscountPhase; subscriptionGroupIdentifier?: string; }; android?: { - offerId?: string; basePlanId: string; - introductoryOfferEligibility: OfferEligibility; - offerTags?: string[]; renewalType?: 'prepaid' | 'autorenewable'; }; } ``` 3. [AdaptyDiscountPhase](https://react-native.adapty.io/interfaces/adaptydiscountphase): - El campo `identifier` se ha eliminado del modelo `AdaptyDiscountPhase`. El identificador de oferta ahora se almacena en `AdaptySubscriptionOffer.identifier`.
```diff showLineNumbers - ios?: { - readonly identifier?: string; - }; ``` ### Modelos eliminados \{#remove-models\} 1. `AttributionSource`: - Ahora se usa un string en los lugares donde antes se usaba `AttributionSource`. 2. `OfferEligibility`: - Este modelo se ha eliminado porque ya no es necesario. Ahora, una oferta solo se devuelve si el usuario es elegible. ## Elimina el método `getProductsIntroductoryOfferEligibility` \{#remove-getproductsintroductoryoffereligibility-method\} Antes del SDK de Adapty 3.3.1, los objetos de producto siempre incluían las ofertas, incluso si el usuario no era elegible. Esto requería verificar la elegibilidad manualmente antes de usar la oferta. A partir de la versión 3.3.1, el objeto de producto incluye ofertas solo si el usuario es elegible. Esto simplifica el proceso, ya que puedes asumir que el usuario es elegible si hay una oferta presente. ## Actualizar la realización de compras \{#update-making-purchase\} En versiones anteriores, las compras canceladas y pendientes se trataban como errores y devolvían los códigos `2: 'paymentCancelled'` y `25: 'pendingPurchase'`, respectivamente. A partir de la versión 3.3.1, las compras canceladas y pendientes se consideran resultados exitosos y deben gestionarse en consecuencia: ```typescript showLineNumbers try { const purchaseResult = await adapty.makePurchase(product); switch (purchaseResult.type) { case 'success': const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features } break; case 'user_cancelled': // Handle the case where the user canceled the purchase break; case 'pending': // Handle deferred purchases (e.g., the user will pay offline with cash) break; } } catch (error) { // Handle the error } ``` ## Actualiza la presentación de paywalls del Paywall Builder \{#update-paywall-builder-paywall-presentation\} Para ver ejemplos actualizados, consulta la documentación [Presentar paywalls nuevos del Paywall Builder en React Native](react-native-present-paywalls). ```diff showLineNumbers - import { createPaywallView } from '@adapty/react-native-ui'; + import { createPaywallView } from 'react-native-adapty/dist/ui'; const view = await createPaywallView(paywall); view.registerEventHandlers(); // handle close press, etc try { await view.present(); } catch (error) { // handle the error } ``` ## Actualiza la implementación del temporizador definido por el desarrollador \{#update-developer-defined-timer-implementation\} Renombra el parámetro `timerInfo` a `customTimers`: ```diff showLineNumbers - let timerInfo = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } + let customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } //and then you can pass it to createPaywallView as follows: - view = await createPaywallView(paywall, { timerInfo }) + view = await createPaywallView(paywall, { customTimers }) ``` ## Modificar eventos de compra del Paywall Builder \{#modify-paywall-builder-purchase-events\} Anteriormente: - Las compras canceladas activaban el callback `onPurchaseCancelled`. - Las compras pendientes devolvían el código de error `25: 'pendingPurchase'`. Ahora: - Ambos casos se gestionan mediante el callback `onPurchaseCompleted`. #### Pasos para migrar: \{#steps-to-migrate\} 1. Elimina el callback `onPurchaseCancelled`. 2. Elimina el manejo del código de error `25: 'pendingPurchase'`. 3. Actualiza el callback `onPurchaseCompleted`: ```typescript showLineNumbers const view = await createPaywallView(paywall); const unsubscribe = view.registerEventHandlers({ // ... other optional callbacks onPurchaseCompleted(purchaseResult, product) { switch (purchaseResult.type) { case 'success': const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features } break; // highlight-start case 'user_cancelled': // Handle the case where the user canceled the purchase break; case 'pending': // Handle deferred purchases (e.g., the user will pay offline with cash) break; // highlight-end } // highlight-start return purchaseResult.type !== 'user_cancelled'; // highlight-end }, }); ``` ## Modifica los eventos de acción personalizada del Paywall Builder \{#modify-paywall-builder-custom-action-events\} Callbacks eliminados: - `onAction` - `onCustomEvent` Callback añadido: - Nuevo callback `onCustomAction(actionId)`. Úsalo para acciones personalizadas. ## Modifica el callback `onProductSelected` \{#modify-onproductselected-callback\} Antes, `onProductSelected` requería el objeto `product`. Ahora requiere `productId` como string. ## Elimina los parámetros de integración de terceros del método `updateProfile` \{#remove-third-party-integration-parameters-from-updateprofile-method\} Los identificadores de integración de terceros ahora se configuran con el método `setIntegrationIdentifier`. El método `updateProfile` ya no los acepta. ## Actualiza la configuración del SDK de integraciones de terceros \{#update-third-party-integration-sdk-configuration\} Para garantizar que las integraciones funcionen correctamente con el SDK de Adapty React Native 3.3.1 y versiones posteriores, actualiza las configuraciones de tu SDK para las siguientes integraciones según se describe en las secciones a continuación. Además, si usabas `AttributionSource` para obtener el identificador de atribución, cambia tu código para proporcionar el identificador requerido como string. ### Adjust Actualiza el código de tu app para móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con Adjust](adjust#connect-your-app-to-adjust). ```diff showLineNumbers import { Adjust, AdjustConfig } from "react-native-adjust"; import { adapty } from "react-native-adapty"; var adjustConfig = new AdjustConfig(appToken, environment); // Before submiting Adjust config... adjustConfig.setAttributionCallbackListener(attribution => { // Make sure Adapty SDK is activated at this point // You may want to lock this thread awaiting of `activate` adapty.updateAttribution(attribution, "adjust"); }); // ... Adjust.create(adjustConfig); + Adjust.getAdid((adid) => { + if (adid) + adapty.setIntegrationIdentifier("adjust_device_id", adid); + }); ``` ### AirBridge \{#airbridge\} Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con AirBridge](airbridge#connect-your-app-to-airbridge). ```diff showLineNumbers import Airbridge from 'airbridge-react-native-sdk'; import { adapty } from 'react-native-adapty'; try { const deviceId = await Airbridge.state.deviceUUID(); - await adapty.updateProfile({ - airbridgeDeviceId: deviceId, - }); + await adapty.setIntegrationIdentifier("airbridge_device_id", deviceId); } catch (error) { // handle `AdaptyError` } ``` ### Amplitude \{#amplitude\} Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con Amplitude](amplitude#sdk-configuration). ```diff showLineNumbers import { adapty } from 'react-native-adapty'; try { - await adapty.updateProfile({ - amplitudeDeviceId: deviceId, - amplitudeUserId: userId, - }); + await adapty.setIntegrationIdentifier("amplitude_device_id", deviceId); + await adapty.setIntegrationIdentifier("amplitude_user_id", userId); } catch (error) { // handle `AdaptyError` } ``` ### AppMetrica Actualiza el código de tu app como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con AppMetrica](appmetrica#sdk-configuration). ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import AppMetrica, { DEVICE_ID_KEY, StartupParams, StartupParamsReason } from '@appmetrica/react-native-analytics'; // ... const startupParamsCallback = async ( params?: StartupParams, reason?: StartupParamsReason ) => { const deviceId = params?.deviceId if (deviceId) { try { - await adapty.updateProfile({ - appmetricaProfileId: 'YOUR_ADAPTY_CUSTOMER_USER_ID', - appmetricaDeviceId: deviceId, - }); + await adapty.setIntegrationIdentifier("appmetrica_profile_id", 'YOUR_ADAPTY_CUSTOMER_USER_ID'); + await adapty.setIntegrationIdentifier("appmetrica_device_id", deviceId); } catch (error) { // handle `AdaptyError` } } } AppMetrica.requestStartupParams(startupParamsCallback, [DEVICE_ID_KEY]) ``` ### AppsFlyer Actualiza el código de tu aplicación móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con AppsFlyer](appsflyer#connect-your-app-to-appsflyer). ```diff showLineNumbers import { adapty, AttributionSource } from 'react-native-adapty'; import appsFlyer from 'react-native-appsflyer'; appsFlyer.onInstallConversionData(installData => { try { - const networkUserId = appsFlyer.getAppsFlyerUID(); - adapty.updateAttribution(installData, AttributionSource.AppsFlyer, networkUserId); + const uid = appsFlyer.getAppsFlyerUID(); + adapty.setIntegrationIdentifier("appsflyer_id", uid); + adapty.updateAttribution(installData, "appsflyer"); } catch (error) { // handle the error } }); // ... appsFlyer.initSdk(/*...*/); ``` ### Branch \{#branch\} Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con Branch](branch#connect-your-app-to-branch). ```diff showLineNumbers import { adapty, AttributionSource } from 'react-native-adapty'; import branch from 'react-native-branch'; branch.subscribe({ enComplete: ({ params, }) => { - adapty.updateAttribution(params, AttributionSource.Branch); + adapty.updateAttribution(params, "branch"); }, }); ``` ### Facebook Ads Actualiza el código de tu aplicación móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con Facebook Ads](facebook-ads#connect-your-app-to-facebook-ads). ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import { AppEventsLogger } from 'react-native-fbsdk-next'; try { const anonymousId = await AppEventsLogger.getAnonymousID(); - await adapty.updateProfile({ - facebookAnonymousId: anonymousId, - }); + await adapty.setIntegrationIdentifier("facebook_anonymous_id", anonymousId); } catch (error) { // handle `AdaptyError` } ``` ### Firebase y Google Analytics \{#firebase-and-google-analytics\} Actualiza el código de tu aplicación móvil como se indica a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con Firebase y Google Analytics](firebase-and-google-analytics). ```diff showLineNumbers import analytics from '@react-native-firebase/analytics'; import { adapty } from 'react-native-adapty'; try { const appInstanceId = await analytics().getAppInstanceId(); - await adapty.updateProfile({ - firebaseAppInstanceId: appInstanceId, - }); + await adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId); } catch (error) { // handle `AdaptyError` } ``` ### Mixpanel \{#mixpanel\} Actualiza el código de tu app móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con Mixpanel](mixpanel#sdk-configuration). ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import { Mixpanel } from 'mixpanel-react-native'; // ... try { - await adapty.updateProfile({ - mixpanelUserId: mixpanelUserId, - }); + await adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelUserId); } catch (error) { // handle `AdaptyError` } ``` ### OneSignal Actualiza el código de tu aplicación móvil como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con OneSignal](onesignal#sdk-configuration).
:::important
**Los siguientes pasos dependen de si ya tienes productos en el App Store y/o Google Play:**
:::
5. Haz clic en **Save & Continue** y cambia a la pestaña **App Store** o **Google Play** para rellenar los detalles del producto para la store.
Renderizarás este paywall en el código de tu app.
En el código de tu app solo tienes que escribir los IDs de los placements. Todo lo demás — qué paywall se muestra, qué productos vende, el Remote Config — se configura en el Adapty Dashboard y puede cambiarse en cualquier momento sin actualizar la app.
:::tip
Adapty te permite mostrar diferentes paywalls a distintos grupos de usuarios y analizar el rendimiento. Más información sobre [audiencias](audience) y [pruebas A/B](ab-tests).
:::
## Próximos pasos \{#next-steps\}
¡Felicidades por completar el onboarding de Adapty! Ya estás listo para hacer crecer tus compras in-app.
Prepárate para el lanzamiento en producción:
O puedes continuar con lo siguiente:
- **[Pruebas A/B](ab-tests)**: Experimenta con distintos precios, duraciones de suscripción, períodos de prueba y elementos visuales para identificar las combinaciones más efectivas.
- **[Analíticas](how-adapty-analytics-works)**: Explora métricas de monetización detalladas para entender el comportamiento de los usuarios y optimizar el rendimiento de los ingresos.
- **Integraciones**: Adapty envía [eventos de suscripción](events) a herramientas de analítica y atribución de terceros, como [Amplitude](amplitude), [AppsFlyer](appsflyer), [Adjust](adjust), [Branch](branch), [Mixpanel](mixpanel), [Facebook Ads](facebook-ads), [AppMetrica](appmetrica) y un [Webhook](webhook) personalizado.
:::tip
¿Tienes preguntas o estás teniendo algún problema? Consulta nuestro [foro de soporte](https://adapty.featurebase.app/) donde encontrarás respuestas a preguntas frecuentes o podrás plantear las tuyas. ¡Nuestro equipo y la comunidad están aquí para ayudarte!
:::
---
# File: release-checklist
---
---
title: "Lista de verificación para el lanzamiento"
description: "Sigue la lista de verificación de Adapty para garantizar un proceso de actualización de tu app sin problemas."
---
¡Nos alegra que hayas elegido Adapty! Esperamos que la implementación haya ido bien. Esta guía te llevará paso a paso para asegurarte de que tu app esté lista para publicarse en los stores y de que el flujo de monetización funcione correctamente.
## Elementos esenciales antes del lanzamiento \{#pre-flight-essentials\}
Lo que necesitas antes de empezar la validación:
- Un dispositivo real con una cuenta sandbox
- Acceso al Adapty Dashboard
- Acceso a App Store Connect / Google Play Console
:::note
Aunque las compras sandbox pueden ejecutarse en simuladores, necesitas dispositivos reales para probar todos los flujos, incluidos los diálogos de pago y las solicitudes biométricas.
:::
## Validaciones universales \{#universal-validations\}
- [ ] **Conexión con el store**: Asegúrate de haber conectado Adapty a App Store y/o Google Play:
- [ ] [App Store](initial_ios)
- [ ] [Google Play](initial-android)
- [ ] **Entrega de eventos de suscripción**: Confirma que las notificaciones del servidor están configuradas:
- [ ] [Notificaciones del servidor de App Store](enable-app-store-server-notifications)
- [ ] [Notificaciones en tiempo real para desarrolladores (RTDN)](enable-real-time-developer-notifications-rtdn)
- [ ] **Identificación de perfiles**: Valida la lógica de identificación de usuarios y asegúrate de que las compras se asocien al perfil correcto:
- [ ] [Comprueba que la lógica de identificación en el código de tu app coincide con tu caso de uso](ios-quickstart-identify)
- [ ] [Asegúrate de entender la lógica de padre/heredero para compartir el acceso de pago entre perfiles de usuario](sharing-paid-access-between-user-accounts)
- [ ] **Ofertas**: Si tienes ofertas promocionales de App Store en la app, asegúrate de haber [añadido tu clave de compra in-app](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers) tanto en el campo principal como en la sección **App Store promotional offers**.
- [ ] **Recopilación de datos**: Garantiza el cumplimiento de la privacidad:
- [ ] Si necesitas cumplir con normativas de privacidad como GDPR o CCPA, o tu app está destinada a niños, controla si [habilitas la recopilación y el uso compartido del IDFA e IP](sdk-installation-ios#data-policies).
- [ ] Si tu app usa AppTrackingTransparency, asegúrate de [enviar el estado de autorización a Adapty](ios-deal-with-att).
- [ ] **Etiquetas de privacidad**: [Más información](apple-app-privacy) sobre los datos que recopila Adapty y qué indicadores tendrás que configurar para la revisión.
## Validación de compras \{#purchase-validations\}
:::tip
¿Tienes preguntas o estás teniendo algún problema? Consulta nuestro [foro de soporte](https://adapty.featurebase.app/) donde encontrarás respuestas a preguntas frecuentes o podrás plantear las tuyas. ¡Nuestro equipo y la comunidad están aquí para ayudarte!
:::
Antes de publicar tu app, asegúrate de que las compras funcionan correctamente y de que tu paywall está listo para la revisión de la store.
La forma de validar las compras in-app depende de cómo las hayas implementado:
- Muestras un paywall creado en el Adapty Paywall Builder
- Has implementado tu propio paywall y usas el método `makePurchase` dentro de él para gestionar las compras
- Usas Adapty en modo observador (ya sea con el Adapty Paywall Builder o con tu paywall personalizado)
Viable, pero requiere una cantidad significativa de código y configuración adicionales, más que en el modo completo.
| ✅ | | **Tiempo de implementación** |Para analítica e integraciones: menos de una hora
Con pruebas A/B: hasta una semana con pruebas exhaustivas
| Varias horas | ## Cómo funciona el modo Observer \{#how-observer-mode-works\} En el modo Observer, tú reportas las nuevas transacciones de Apple/Google al SDK de Adapty, y el SDK las reenvía al backend de Adapty. Eres responsable de gestionar el acceso al contenido de pago en tu app, completar las transacciones, gestionar las renovaciones, resolver los problemas de facturación, etc. ## Cómo configurar el modo Observer \{#how-to-set-up-observer-mode\} 1. Configura la integración inicial de Adapty [con Google Play](initial-android) y [con App Store](initial_ios). 2. Actívalo al configurar el SDK de Adapty estableciendo el parámetro `observerMode` en `true`. Sigue las instrucciones de configuración para [iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk), [Android](sdk-installation-android#activate-adapty-module-of-adapty-sdk), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform#activate-adapty-sdk) y [Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). 3. [Reporta las transacciones](report-transactions-observer-mode) desde tu infraestructura de compras existente a Adapty para iOS y frameworks multiplataforma basados en iOS. 4. (opcional) Si quieres usar integraciones con terceros, configúralas como se describe en el artículo [Configurar integraciones con terceros](configuration). :::warning Al operar en modo Observer, el SDK de Adapty no finaliza las transacciones, así que asegúrate de gestionar este aspecto tú mismo. ::: ## Cómo usar paywalls y pruebas A/B en el modo Observer \{#how-to-use-paywalls-and-ab-tests-in-observer-mode\} En el modo Observer, el SDK de Adapty no puede determinar el origen de las compras, ya que estas se realizan en tu propia infraestructura. Por lo tanto, si pretendes usar paywalls y/o pruebas A/B en el modo Observer, debes asociar la transacción procedente de tu store con el paywall correspondiente en el código de tu app móvil al reportar una transacción. Además, los paywalls diseñados con el Paywall Builder deben mostrarse de una forma especial cuando se usa el modo Observer: - Muestra paywalls en el modo Observer para [iOS](implement-observer-mode) o [Android](android-present-paywall-builder-paywalls-in-observer-mode). - [Asocia paywalls a transacciones de compra](report-transactions-observer-mode) al reportar transacciones en el modo Observer. --- # File: migration-from-revenuecat --- --- title: "Migración desde RevenueCat" description: "Migra de RevenueCat a Adapty con nuestra guía paso a paso." --- Tu plan de migración tiene 5 pasos lógicos y dura una media de 2 horas. El 90 % de todas las migraciones se completan en menos de un día laborable. 1. Aprende las diferencias clave y crea y prepara una cuenta de Adapty _(5 minutos)_; 2. Instala el SDK de Adapty para tu plataforma ([iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity)) en lugar del SDK de RevenueCat _(1 hora)_; 3. Configura las [notificaciones de servidor de Apple App Store](enable-app-store-server-notifications) para Adapty y (opcionalmente) el [reenvío de eventos sin procesar](enable-app-store-server-notifications#raw-events-forwarding) _(5 minutos)_; 4. Prueba y publica la actualización de tu app _(30 minutos)_; 5. (Opcional) Solicita al soporte de RevenueCat los datos históricos en formato CSV _(5 minutos)_; 6. (Opcional) Importa los datos históricos a través del soporte de Adapty _(30 minutos)_. :::info Tus suscriptores migrarán automáticamente Todos los usuarios que alguna vez hayan activado una suscripción pasarán a Adapty automáticamente en cuanto abran la nueva versión de tu app con el SDK de Adapty. La validación del estado de la suscripción y el acceso premium se restaurarán de forma automática. ::: Antes de publicar una nueva versión de tu app con el SDK de Adapty, asegúrate de revisar nuestra [lista de verificación para el lanzamiento](release-checklist). ## Aprende las diferencias clave y crea y prepara una cuenta de Adapty \{#learn-the-core-differences-create-and-prepare-an-adapty-account\} Los SDKs de Adapty y RevenueCat tienen un diseño similar. La mayor diferencia está en el uso de red y la velocidad: el SDK de Adapty está diseñado para proporcionarte información lo más rápido posible cuando la solicitas. Por ejemplo, al pedir un paywall, primero recibes el [Remote Config](customize-paywall-with-remote-config) para precomponer tu onboarding o paywall, y luego solicitas los productos en una petición separada. Los nombres son ligeramente distintos: | RevenueCat | Adapty | | :---------- | :-------------- | | Package | Product | | Offering | Paywall | | Paywall | Paywall Builder | | Entitlement | Access level | Adapty tiene el concepto de [placement](placements). Es un lugar lógico dentro de tu app donde el usuario puede realizar una compra. En la mayoría de los casos, tendrás uno o dos placements: - Onboarding (ya que el 80 % de todas las compras se realizan ahí); - General (se muestra en los ajustes o dentro de la app después del onboarding).
## Instala el SDK de Adapty y reemplaza el SDK de RevenueCat \{#install-adapty-sdk-and-replace-revenuecat-sdk\}
Instala el SDK de Adapty para tu plataforma ([iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity)) en tu app.
Necesitas reemplazar algunos métodos del SDK en el lado de la app. Veamos las funciones más comunes y cómo sustituirlas por las del SDK de Adapty.
### Activación del SDK \{#sdk-activation\}
Reemplaza `Purchases.configure` con `Adapty.activate`.
### Obtener paywalls (offerings) \{#getting-paywalls-offerings\}
Reemplaza `Purchases.shared.getOfferings` con [`Adapty.getPaywall`](fetch-paywalls-and-products#fetch-paywall-information).
En Adapty, siempre solicitas el paywall mediante el [placement id](placements). En la práctica, solo obtienes 1 o 2 paywalls como máximo, así que lo hemos diseñado así a propósito para acelerar el SDK y reducir el uso de red.
### Obtener un usuario (perfil del cliente) \{#getting-a-user-customer-profile\}
Reemplaza `Purchases.shared.getCustomerInfo` con `Adapty.getProfile`.
### Obtener productos \{#getting-products\}
En RevenueCat, usas la siguiente estructura: `Purchases.shared.getOfferings` y luego `self.offering?.availablePackages`.
En Adapty, primero solicitas un paywall (ver arriba) para acceder de inmediato al [Remote Config](customize-paywall-with-remote-config) de Adapty, y luego obtienes los productos con [`Adapty.getPaywallProducts`](fetch-paywalls-and-products#fetch-products).
### Realizar una compra \{#making-a-purchase\}
Reemplaza `Purchases.shared.purchase` con [`Adapty.makePurchase`](making-purchases#make-purchase).
### Verificar el nivel de acceso (entitlement) \{#checking-access-level-entitlement\}
Obtén el perfil del cliente (lee el apartado anterior primero) y luego reemplaza
`customerInfo?.entitlements["premium"]?.isActive == true`
con
[`profile.accessLevels["premium"]?.isActive == true`](subscription-status#retrieving-the-access-level-from-the-server).
### Restaurar una compra \{#restore-purchase\}
Reemplaza `Purchases.shared.restorePurchases` con [`Adapty.restorePurchases`](restore-purchase).
### Comprobar si el usuario ha iniciado sesión \{#check-if-the-user-is-logged-in\}
Reemplaza `Purchases.shared.isAnonymous` con `if profile.customerUserId == nil`.
### Iniciar sesión con un usuario \{#log-in-user\}
Reemplaza `Purchases.shared.logIn` con [`Adapty.identify`](identifying-users#set-customer-user-id-after-configuration).
### Cerrar sesión de un usuario \{#log-out-user\}
Reemplaza `Purchases.shared.logOut` con [`Adapty.logout`](identifying-users#logging-out-and-logging-in).
## Cambia las notificaciones del servidor de App Store a Adapty \{#switch-app-store-server-side-notifications-to-adapty\}
Lee cómo hacerlo [aquí](migrate-to-adapty-from-another-solutions#changing-apple-server-notifications).
## Prueba y publica una nueva versión de tu app \{#test-and-release-a-new-version-of-your-app\}
Si estás leyendo esto, ya has:
- [x] Configurado el Adapty Dashboard
- [x] Instalado el SDK de Adapty
- [x] Reemplazado la lógica del SDK con las funciones de Adapty
- [x] Cambiado las notificaciones del servidor de App Store a Adapty y, opcionalmente, activado el reenvío de eventos sin procesar a RevenueCat
- [ ] Realizado una compra en sandbox
- [ ] Publicado una nueva versión de la app
Si has marcado los puntos anteriores, haz una compra de prueba en el Sandbox y luego publica la app.
:::info
Repasa la [lista de verificación para el lanzamiento](release-checklist).
Haz la revisión final con nuestra lista para validar la integración existente o añadir funciones adicionales como integraciones de [atribución](attribution-integration) o [análisis](analytics-integration).
:::
## (Opcional) Exporta tus datos históricos de RevenueCat en formato CSV \{#optional-export-your-revenuecat-historical-data-in-csv-format\}
:::warning
No te precipites con la importación de datos históricos
Deberías esperar al menos una semana después de publicar la versión con el SDK antes de importar los datos históricos. Durante ese tiempo recopilaremos toda la información sobre los precios de compra desde el SDK, por lo que los datos que importes serán más relevantes.
:::
Exporta tus datos históricos de RevenueCat en formato CSV siguiendo las instrucciones de la [documentación oficial de RevenueCat](https://www.revenuecat.com/docs/integrations/scheduled-data-exports).
## (Opcional) Solicita al soporte de RevenueCat los tokens de compra de Google \{#optional-ask-revenuecat-support-for-google-purchase-tokens\}
Si necesitas importar transacciones de Google Play, contacta con el soporte de RevenueCat para obtener un archivo CSV con los Google Purchase Tokens a través de su [página de soporte](https://app.revenuecat.com/settings/support). El Google Purchase Token es un identificador único que proporciona Google Play para cada transacción, imprescindible para rastrear y verificar las compras con precisión en Adapty. Esta información no se incluye en el archivo de exportación estándar. El archivo contiene las siguientes tres columnas:
- `user_id`
- `google_purchase_token`
- `google_product_id`
## Escríbenos para importar tus datos históricos \{#write-us-to-import-your-historical-data\}
Contáctanos a través del chat del sitio web o envíanos un correo a [support@adapty.io](mailto:support@adapty.io) con tus archivos CSV.
1. Envía el archivo CSV que exportaste de RevenueCat directamente a nuestro equipo de soporte.
2. Si vas a importar transacciones de Google Play, incluye el archivo CSV con los Google Purchase Tokens que recibiste del soporte de RevenueCat.
3. Indícanos qué ID de usuario debe usarse como Customer User ID (el identificador principal de usuario en Adapty): `rc_original_app_user_id` o `rc_last_seen_app_user_id_alias`.
Nuestro equipo de soporte importará tus transacciones a Adapty. Se importarán los siguientes datos para cada transacción:
| Parámetro | Descripción |
| ----------------------------- | ------------------------------------------------------------ |
| user_id | Customer User ID, el identificador principal de tu usuario en Adapty y en tu sistema. |
| apple_original_transaction_id | Para cadenas de suscripciones, esta es la fecha de compra de la transacción original, vinculada por `store_original_transaction_id`. |
| google_product_id | El ID del producto en Google Play Store. |
| google_purchase_token | Un identificador único proporcionado por Google Play para cada transacción, necesario para la validación. |
| country | El país del usuario. |
| created_at | La fecha y hora de creación del usuario. |
| subscription_expiration_date | La fecha y hora en que expira la suscripción. |
| email | El correo electrónico del usuario final. |
| phone_number | El número de teléfono del usuario final. |
| idfa | El Identificador para Anunciantes (IDFA), asignado por Apple al dispositivo de un usuario. |
| idfv | El Identificador para Proveedores (IDFV), un código asignado a todas las apps de un mismo desarrollador y compartido entre esas apps en un dispositivo. |
| advertising_id | Un identificador único proporcionado por el sistema operativo Android que los anunciantes pueden usar para el seguimiento. |
| attribution_channel | El nombre del canal de marketing. |
| attribution_campaign | El nombre de la campaña de marketing. |
| attribution_ad_group | El grupo de anuncios de atribución. |
| attribution_ad_set | El conjunto de anuncios de atribución. |
| attribution_creative | La palabra clave creativa de atribución. |
Además, se importarán los identificadores de integración para las siguientes integraciones: Amplitude, Mixpanel, AppsFlyer, Adjust y FacebookAds.
## Preguntas frecuentes \{#faq\}
### Instalé el SDK de Adapty correctamente y publiqué una nueva versión de la app. ¿Qué pasará con mis suscriptores existentes que no actualicen a la versión con el SDK de Adapty? \{#i-successfully-installed-adapty-sdk-and-released-a-new-app-version-with-it-what-will-happen-to-my-legacy-subscribers-who-did-not-update-to-a-version-with-adapty-sdk\}
La mayoría de los usuarios cargan sus teléfonos por la noche, que es cuando App Store suele actualizar automáticamente todas sus apps, por lo que no debería ser un problema. Puede que quede un pequeño número de suscriptores de pago que no hayan actualizado, pero seguirán teniendo acceso al contenido premium. No tienes que preocuparte por ello ni forzarlos a actualizar.
### ¿Necesito exportar mis datos históricos de RevenueCat lo antes posible o los perderé? \{#do-i-need-to-export-my-historical-data-from-revenuecat-as-quickly-as-possible-or-will-i-lose-it\}
No hace falta hacerlo con prisa; primero publica la versión con el SDK de Adapty y luego compártenos tus datos históricos. Restauraremos el historial de pagos de tus usuarios y completaremos los [perfiles](profiles-crm) y los [gráficos](charts).
### Uso MMP (AppsFlyer, Adjust, etc.) y herramientas de análisis (Mixpanel, Amplitude, etc.). ¿Cómo me aseguro de que todo funcionará correctamente? \{#i-use-mmp-appsflyer-adjust-etc-and-analytics-mixpanel-amplitude-etc-how-do-i-make-sure-that-everything-will-work\}
Primero tienes que pasarnos los IDs de esos servicios de terceros a través de nuestro SDK para que podamos enviarles datos. Lee la guía de [integración de atribución](attribution-integration) y de [integración de análisis](analytics-integration). Para los datos históricos y los usuarios existentes, **asegúrate de pasarnos esos IDs a partir de los datos que exportaste de RevenueCat.**
---
# File: migration-from-superwall
---
---
title: "Migración desde Superwall"
description: "Migra de Superwall a Adapty con una guía paso a paso que mapea cada llamada al SDK y cada concepto."
---
La mayoría de las migraciones desde Superwall a Adapty llevan unas dos horas. Cambias el SDK, apuntas las notificaciones del servidor de la store a Adapty y publicas una nueva versión de la app. Tus suscriptores de pago conservan su acceso — Adapty lo restaura desde los recibos de App Store y Google Play en el primer arranque.
:::info
Tus suscriptores migrarán automáticamente
Todos los usuarios que alguna vez hayan activado una suscripción pasan a Adapty en cuanto abran una nueva versión de tu app con el SDK de Adapty. La validación del estado de la suscripción y el acceso premium se restauran automáticamente.
:::
## Cómo está organizada esta guía \{#how-this-guide-is-organized\}
La migración tiene seis pasos:
1. [Mapea los conceptos de Superwall a Adapty](#map-your-superwall-concepts-to-adapty)
2. [Instala el SDK de Adapty](#install-the-adapty-sdk)
3. [Reemplaza las llamadas al SDK](#replace-sdk-calls)
4. [Cambia las notificaciones del servidor de App Store y Google Play](#switch-app-store-and-google-play-server-notifications)
5. [Prueba y publica](#test-and-release)
6. [(Opcional) Importa datos históricos](#optional-import-historical-data)
## Mapea los conceptos de Superwall a Adapty \{#map-your-superwall-concepts-to-adapty\}
La mayoría de los conceptos de Superwall tienen un equivalente directo en Adapty:
| Superwall | Adapty | Qué cambia |
| :------------------- | :------------------------------------------------ | :--------------------------------------------------------------------------- |
| Campaign | [Placement](placements) + [Audience](audience) | La lógica de la campaña se divide en un placement (la ubicación) y una audiencia (la regla). |
| Placement | [Placement](placements) | Mismo concepto, mismo nombre. |
| Audience filter | [Audience](audience) | Los conjuntos de reglas viven dentro de un placement. |
| Entitlement | [Nivel de acceso](access-level) | Identificador con nombre (por ejemplo, `premium`). |
| WebView paywall | [Paywall de Paywall Builder](adapty-paywall-builder) | Renderizado por el SDK de Adapty de forma nativa en lugar de un `WKWebView`. |
| `PurchaseController` | Integrado | No hay protocolo que implementar — Adapty gestiona las compras. |
| Feature gating | Comprobación de [nivel de acceso](access-level) | Comprueba `profile.accessLevels["premium"]?.isActive`. |
Hay dos cambios conceptuales que vale la pena tener en cuenta antes de tocar el código:
- **Obtener y presentar son pasos separados**: El método `register` de Superwall obtiene el paywall, evalúa la campaña y presenta la interfaz en una sola llamada. Adapty divide estos pasos — obtienes el paywall, su configuración de vista y luego lo presentas. Esto añade unas pocas líneas, pero te permite precargar configuraciones, mostrar un estado de carga personalizado o cancelar la presentación según tu propia lógica.
- **El estado de la suscripción es por nivel de acceso**: Superwall expone una sola propiedad publicada `subscriptionStatus`. Adapty devuelve un [`AdaptyProfile`](https://swift.adapty.io/documentation/adapty/adaptyprofile) con niveles de acceso con nombre, de modo que un usuario puede tener los niveles de acceso `sports` y `science` de forma independiente. Para lecturas síncronas, guarda en caché el perfil del `AdaptyDelegate` en lugar de llamar a `getProfile()` en cada carga de vista.
## Instala el SDK de Adapty \{#install-the-adapty-sdk\}
Instala el SDK de Adapty para tu plataforma — [iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity) o [Capacitor](sdk-installation-capacitor) — y elimina SuperwallKit de tu proyecto al mismo tiempo.
## Reemplaza las llamadas al SDK \{#replace-sdk-calls\}
Revisa cada área de tu integración y sustituye la llamada de Superwall por su equivalente en Adapty. Los enlaces al final de cada subsección cubren los siete SDKs de plataforma — sigue el que corresponda a tu app.
### Inicializa el SDK \{#initialize-the-sdk\}
Reemplaza `Superwall.configure` con `Adapty.activate`.
Consulta la guía de instalación para tu plataforma — [iOS](sdk-installation-ios), [Android](sdk-installation-android), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter), [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform), [Unity](sdk-installation-unity) o [Capacitor](sdk-installation-capacitor).
### Identifica y desconecta usuarios \{#identify-and-log-out-users\}
Reemplaza `Superwall.shared.identify` con `Adapty.identify` y `Superwall.shared.reset` con `Adapty.logout`. Ambos SDKs generan un perfil anónimo en el primer arranque, por lo que estas llamadas solo son necesarias cuando un usuario inicia o cierra sesión. Vuelve a obtener los paywalls después de identificar — el nuevo usuario puede resolverse a una audiencia diferente.
Consulta la guía de identificación para tu plataforma — [iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), [Kotlin Multiplatform](kmp-identifying-users), [Unity](unity-identifying-users) o [Capacitor](capacitor-identifying-users).
### Obtén y presenta un paywall \{#fetch-and-present-a-paywall\}
Reemplaza `Superwall.shared.register` con un flujo de dos pasos: obtén el paywall con `Adapty.getPaywall`, carga su configuración de vista con `AdaptyUI.getPaywallConfiguration` y luego preséntalo.
Dos diferencias a destacar:
- **El feature gating reemplaza el closure `feature:`**: Después de que se cierre el paywall, comprueba el nivel de acceso activo en el perfil devuelto (o en `Adapty.getProfile`) y ramifica desde ahí.
- **Los paywalls son renderizados por el SDK**: Superwall renderiza los paywalls dentro de un `WKWebView`. Adapty renderiza los paywalls del Paywall Builder de forma nativa — las fuentes, la información del producto y los botones los dibuja el SDK.
Consulta la guía de inicio rápido de paywalls para tu plataforma — [iOS](ios-quickstart-paywalls), [Android](android-quickstart-paywalls), [React Native](react-native-quickstart-paywalls), [Flutter](flutter-quickstart-paywalls), [Kotlin Multiplatform](kmp-quickstart-paywalls), [Unity](unity-quickstart-paywalls) o [Capacitor](capacitor-quickstart-paywalls).
### Comprueba el estado de la suscripción \{#check-subscription-status\}
Reemplaza `Superwall.shared.subscriptionStatus` con una comprobación del nivel de acceso con nombre en el perfil: `profile.accessLevels["premium"]?.isActive`. Observa los cambios mediante `AdaptyDelegate.didLoadLatestProfile(_:)` en lugar del patrón de propiedad `@Published`, y guarda el perfil en caché en tu lado para lecturas síncronas.
Consulta la guía de estado de suscripción para tu plataforma — [iOS](ios-check-subscription-status), [Android](android-check-subscription-status), [React Native](react-native-check-subscription-status), [Flutter](flutter-check-subscription-status), [Kotlin Multiplatform](kmp-check-subscription-status), [Unity](unity-check-subscription-status) o [Capacitor](capacitor-check-subscription-status).
### Gestiona compras y restauraciones \{#handle-purchases-and-restores\}
Con el Paywall Builder, ambos SDKs procesan las compras automáticamente dentro de la interfaz del paywall — **puedes saltarte este paso**.
Para paywalls personalizados, Superwall requiere una implementación de `PurchaseController`. Adapty no: reemplaza `PurchaseController.purchase` con `Adapty.makePurchase` y `PurchaseController.restorePurchases` con `Adapty.restorePurchases`. El SDK gestiona la validación por su cuenta.
Consulta la guía de inicio rápido de paywall personalizado para tu plataforma — [iOS](ios-quickstart-manual), [Android](android-quickstart-manual), [React Native](react-native-quickstart-manual), [Flutter](flutter-quickstart-manual), [Kotlin Multiplatform](kmp-quickstart-manual), [Unity](unity-quickstart-manual) o [Capacitor](capacitor-quickstart-manual).
### Configura atributos de usuario \{#set-user-attributes\}
Reemplaza `Superwall.shared.setUserAttributes` con `Adapty.updateProfile`.
Consulta la guía de atributos de usuario para tu plataforma — [iOS](setting-user-attributes), [Android](android-setting-user-attributes), [React Native](react-native-setting-user-attributes), [Flutter](flutter-setting-user-attributes), [Kotlin Multiplatform](kmp-setting-user-attributes), [Unity](unity-setting-user-attributes) o [Capacitor](capacitor-setting-user-attributes).
## Cambia las notificaciones del servidor de App Store y Google Play \{#switch-app-store-and-google-play-server-notifications\}
Apunta las notificaciones del servidor de la store a Adapty. Adapty funciona sin ellas, pero las analíticas, las integraciones de terceros y las métricas de pruebas A/B dependen de ellas:
- **App Store**: Sigue [Habilitar notificaciones del servidor de App Store](enable-app-store-server-notifications).
- **Google Play**: Sigue [Habilitar notificaciones en tiempo real para desarrolladores](enable-real-time-developer-notifications-rtdn).
Si quieres ejecutar Superwall y Adapty en paralelo durante el lanzamiento, usa el [reenvío de eventos sin procesar](enable-app-store-server-notifications#raw-events-forwarding) — Adapty reenvía los eventos de la store a Superwall mientras verificas la nueva integración.
## Prueba y publica \{#test-and-release\}
Antes de publicar, comprueba cada elemento:
- [x] Configurado el Adapty Dashboard (productos, paywalls, placements, niveles de acceso)
- [x] Instalado el SDK de Adapty
- [x] Reemplazadas las llamadas al SDK de Superwall por sus equivalentes en Adapty
- [x] Apuntadas las notificaciones del servidor de App Store y Google Play a Adapty
- [ ] Realizada una compra en sandbox
- [ ] Enviada una nueva versión de la app
Revisa el [checklist de lanzamiento](release-checklist) para una validación final.
## (Opcional) Importa datos históricos \{#optional-import-historical-data\}
Superwall no es dueño de tu estado de suscripción — lo son App Store y Google Play. Adapty valida los recibos en el primer arranque, por lo que los usuarios de pago conservan su acceso sin necesidad de ninguna importación.
Si quieres que las transacciones históricas queden registradas en las analíticas de Adapty, sigue [Importar datos históricos a Adapty](importing-historical-data-to-adapty). Espera al menos una semana después del lanzamiento del SDK para que tenga tiempo de recopilar precios de compra actualizados.
## Preguntas frecuentes \{#faq\}
### ¿Qué pasa con los suscriptores que no actualizan la app? \{#what-happens-to-subscribers-who-dont-update-the-app\}
La mayoría de los usuarios actualizan sus apps automáticamente durante la noche, por lo que la proporción de usuarios en la versión anterior disminuye rápidamente. Los suscriptores en la versión antigua conservan su acceso directamente a través de App Store o Google Play — no es necesario forzar una actualización.
### ¿Las audiencias de mis campañas de Superwall se migran? \{#do-my-superwall-campaign-audiences-carry-over\}
No. Los filtros de audiencia de Superwall y las audiencias de Adapty se configuran en dashboards diferentes y usan identificadores distintos. Recrea tu segmentación como [audiencias](audience) dentro de los [placements](placements) de Adapty. La mayoría de las apps tienen uno o dos placements (onboarding y un trigger general dentro de la app), por lo que la reconstrucción suele ser rápida.
### ¿Tiene Adapty un equivalente a `getPresentationResult`? \{#does-adapty-have-an-equivalent-to-getpresentationresult\}
No como una sola llamada. Para comprobar si un placement mostraría un paywall, llama a `Adapty.getPaywall(placementId:)` y ramifica según el resultado. Si la llamada tiene éxito, hay un paywall asignado para la audiencia de ese usuario. Si falla porque no hay ningún paywall configurado, omite la presentación y ejecuta tu lógica de respaldo.
---
# File: importing-historical-data-to-adapty
---
---
title: "Importar datos históricos en Adapty"
description: "Importa datos históricos en Adapty para obtener analíticas detalladas."
---
Después de instalar el SDK de Adapty y publicar tu app, puedes acceder a tus usuarios y suscriptores en la sección [Profiles](profiles-crm). Pero ¿qué pasa si tienes una infraestructura legacy y necesitas migrar a Adapty, o simplemente quieres ver tus datos existentes en Adapty?
:::note
La importación de datos no es obligatoria
Adapty otorgará automáticamente niveles de acceso a los usuarios históricos y restaurará sus eventos de compra en cuanto abran la app con el SDK de Adapty integrado. Para este caso de uso, importar datos históricos no es necesario. Sin embargo, importar los datos garantiza unas analíticas precisas si tienes un volumen significativo de transacciones históricas, aunque en general no es un requisito para la migración.
:::
Para importar datos en Adapty:
1. Exporta tus transacciones a un archivo CSV (se deben proporcionar archivos separados para iOS, Android y Stripe). Consulta la sección [Formato del archivo de importación](importing-historical-data-to-adapty#import-file-format) más abajo para conocer los requisitos detallados.
2. Si algún archivo supera 1 GB, prepara una muestra de datos con aproximadamente 100 líneas.
3. Sube todos los archivos a Google Drive (puedes comprimirlos, pero mantenlos separados).
4. Para las transacciones de iOS, asegúrate de que la sección **In-app purchase API** en [**App settings**](https://app.adapty.io/settings/ios-sdk) esté completada con el **Issuer ID**, **Key ID** y la **Private key** (archivo .P8), incluso si usas StoreKit 1. Consulta las secciones [Provide Issuer ID and Key ID](app-store-connection-configuration#step-2-provide-issuer-id-and-key-id) y [Upload In-App Purchase Key file](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file) para obtener instrucciones detalladas.
5. Comparte los enlaces con nuestro equipo a través de [correo electrónico](mailto:support@adapty.io) o del chat en línea en el Adapty Dashboard.
No te preocupes: importar datos históricos no creará duplicados, aunque esos datos se solapen con entradas ya existentes en Adapty.
## Limitaciones conocidas para Android \{#known-limitations-for-android\}
1. Solo se restaurarán las suscripciones activas; las transacciones expiradas no se restaurarán.
2. Solo se restaurarán las renovaciones más recientes de una suscripción; no se restaurará toda la cadena de compras.
3. Si el precio del producto ha cambiado desde la compra, se utilizará el precio actual, lo que puede dar lugar a precios incorrectos.
:::note
Si tienes un gran volumen de transacciones de Android, es posible que necesites [solicitar un aumento de cuota de la Google Play Developer API](google-play-quota-increase) antes de comenzar la importación para evitar superar el límite predeterminado de la API.
:::
## Formato del archivo de importación \{#import-file-format\}
:::tip
Si estás migrando desde RevenueCat, puedes enviar el archivo de exportación de RevenueCat directamente, sin necesidad de convertirlo. Consulta la [documentación de RevenueCat](https://www.revenuecat.com/docs/integrations/scheduled-data-exports) para obtener instrucciones de exportación.
:::
Prepara tus datos en uno o varios archivos que cumplan las siguientes reglas:
- [ ] El formato del archivo es .CSV.
- [ ] Archivos separados para importaciones de Android, iOS y Stripe.
- [ ] Cada archivo de importación contiene todas las [columnas requeridas](importing-historical-data-to-adapty#required-fields).
- [ ] Las columnas de los archivos de importación tienen encabezados.
- [ ] Los encabezados de columna coinciden exactamente con los de la columna **Column name** de la tabla de abajo. Comprueba que no haya errores tipográficos.
- [ ] Las columnas que no son obligatorias pueden estar ausentes del archivo. No añadas columnas vacías para datos que no tengas.
- [ ] Los archivos de importación no deben tener columnas adicionales que no se mencionen en la tabla. Si las hay, elimínalas.
- [ ] Los valores están separados por comas.
- [ ] Los valores no están entre comillas.
- [ ] Si hay varios **apple_original_transaction_id** para un mismo usuario, añádelos todos como líneas separadas para cada **apple_original_transaction_id**. De lo contrario, es posible que no podamos restaurar las compras consumibles.
Usa los siguientes archivos como ejemplos para [iOS](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/adapty_import_ios_sample.csv) y [Android](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/adapty_import_android_sample.csv).
### Columnas disponibles en el archivo de importación \{#available-import-file-columns\}
| Nombre de columna | Presencia | Descripción |
|-----------|--------|-----------|
| **user_id** | obligatorio | ID de tu usuario |
| **apple_original_transaction_id** | obligatorio para iOS | El ID de transacción original u OTID ([más información](https://developer.apple.com/documentation/appstoreserverapi/originaltransactionid)), utilizado en el mecanismo de importación de StoreKit 2. Como un usuario puede tener varios OTID, basta con proporcionar al menos uno para una importación exitosa.
**Nota:** Para esta importación es necesario que las credenciales de la In-app purchase API estén configuradas en tu Adapty Dashboard. Aprende cómo hacerlo [aquí](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file).
| | **google_product_id** | obligatorio para Google | ID del producto en la Google Play Store. | | **google_purchase_token** | obligatorio para Google | Identificador único que representa al usuario y el ID del producto de la compra in-app que realizó | | **google_is_subscription** | obligatorio para Google | Los valores posibles son `1` \| `0` | | **stripe_token** | obligatorio para Stripe | Token de un objeto de Stripe que representa una compra única. Puede ser el token de una Suscripción de Stripe (`sub_...`) o de un Payment Intent (`pi_...`). | | **subscription_expiration_date** | opcional | La fecha de expiración de la suscripción, es decir, la próxima fecha de cobro, con fecha y hora con zona horaria (2020-12-31T23:59:59-06:00) | | **created_at** | opcional | Fecha y hora de creación del perfil (2019-12-31 23:59:59-06:00) | | **birthday** | opcional | La fecha de nacimiento del usuario en formato 2000-12-31 | | **email** | opcional | El correo electrónico de tu usuario | | **gender** | opcional | El género del usuario | | **phone_number** | opcional | El número de teléfono de tu usuario | | **country** | opcional | formato [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) | | **first_name** | opcional | El nombre de tu usuario | | **last_name** | opcional | El apellido de tu usuario | | **last_seen** | opcional | La fecha y hora con zona horaria (2020-12-31T23:59:59-06:00) | | **idfa** | opcional | El identificador para anunciantes (IDFA) es un identificador de dispositivo aleatorio que Apple asigna al dispositivo del usuario. Solo aplicable a apps de iOS | | **idfv** | opcional | El identificador para proveedores (IDFV) es un código único asignado a todas las apps desarrolladas por un mismo desarrollador, en este caso las tuyas. Solo aplicable a apps de iOS | | **advertising_id** | opcional | El Advertising ID es un código único asignado por el sistema operativo Android que los anunciantes pueden usar para identificar de forma única el dispositivo de un usuario | | **amplitude_user_id** | opcional | El ID de usuario de Amplitude | | **amplitude_device_id** | opcional | El ID de dispositivo de Amplitude | | **mixpanel_user_id** | opcional | ID de usuario de Mixpanel | | **appmetrica_profile_id** | opcional | ID de perfil de usuario de AppMetrica | | **appmetrica_device_id** | opcional | El ID de dispositivo de AppMetrica | | **appsflyer_id** | opcional | Identificador único de AppsFlyer | | **adjust_device_id** | opcional | El ID de dispositivo de Adjust | | **facebook_anonymous_id** | opcional | Identificador único generado por Facebook para usuarios que interactúan con tu app o sitio web de forma anónima, es decir, sin haber iniciado sesión en Facebook | | **branch_id** | opcional | Identificador único de Branch | | **attribution_source** | opcional | La integración de origen de la atribución, por ejemplo, appsflyer | | **attribution_status** | opcional | organic | | **attribution_channel** | opcional | El canal de atribución que trajo la transacción | | **attribution_campaign** | opcional | La campaña de atribución que trajo la transacción | | **attribution_ad_group** | opcional | El grupo de anuncios de atribución que trajo la transacción | | **attribution_ad_set** | opcional | El conjunto de anuncios de atribución que trajo la transacción | | **attribution_creative** | opcional | Elementos visuales o textuales específicos utilizados en un anuncio o campaña de marketing que se rastrean para determinar su efectividad a la hora de generar acciones deseadas, como clics, conversiones o instalaciones | | **custom_attributes** | opcional | Define hasta 30 atributos personalizados como un diccionario JSON en formato clave-valor:Formato: `"{'string_value': 'some_value', 'float_value': 123.0, 'int_value': 456}"`.
Ten en cuenta el uso de comillas dobles y simples en el formato. Los valores booleanos y enteros se convertirán a float.
| ### Campos obligatorios \{#required-fields\} Hay 2 grupos de campos obligatorios para cada plataforma: **user_id** y los datos que identifican las compras específicas de la plataforma correspondiente. Consulta la tabla a continuación para conocer los campos obligatorios por plataforma. | Plataforma | Campos obligatorios | |--------|---------------| | iOS |user_id
apple_original_transaction_id
| | Android |user_id
google_product_id
google_purchase_token
google_is_subscription
| | Stripe |user_id
stripe_token
| Sin estos campos, Adapty no podrá obtener las transacciones. Para unas analíticas de cohorte precisas, especifica `created_at`. Si no se proporciona, asumiremos que la fecha de instalación coincide con la fecha de la primera compra. ### Importar datos en Adapty \{#import-data-to-adapty\} Ponte en contacto con nosotros y comparte tus archivos de importación a través de [support@adapty.io](mailto:support@adapty.io) o del chat en línea en el [Adapty Dashboard](https://app.adapty.io/overview). --- # File: migrate-integrations-to-adapty --- --- title: "Migrar integraciones a Adapty" description: "Cambia las integraciones de analytics y atribución de una solución legacy a Adapty sin duplicar eventos ni interrumpir campañas." --- Migrar a Adapty requiere algo más que cambiar el SDK. Tus integraciones de analytics y atribución con terceros — herramientas como Amplitude y Adjust — también necesitan una transición coordinada. Si se hace con cuidado, el cambio genera muy pocos eventos duplicados o perdidos y no interrumpe tus campañas. ## Mapea tus eventos \{#map-your-events\} Los nombres de eventos son personalizables en la mayoría de las integraciones de Adapty. Puedes configurarlos para que coincidan con los nombres que ya usas en tus dashboards y campañas. Tanto tus informes de analytics como los de campañas seguirán funcionando con los mismos nombres de eventos tras el cambio. Para ver la lista completa de eventos disponibles en Adapty, consulta [Eventos](events). En el caso de Adjust, la integración utiliza IDs de eventos en lugar de nombres de eventos personalizados. Transfiere tus IDs de eventos existentes desde el dashboard de Adjust a la configuración de la integración de Adapty. Consulta la [guía de integración de Adjust](adjust) para más detalles. ## Cómo crea Adapty los eventos de integración \{#how-adapty-creates-integration-events\} Para enviar un evento a una integración, Adapty necesita tener un perfil de usuario. Un perfil se crea de una de estas dos formas: - **Importación histórica**: el perfil se crea cuando [importas datos históricos de transacciones](importing-historical-data-to-adapty) antes de que el SDK entre en funcionamiento. - **Interacción con el SDK**: el perfil se crea automáticamente cuando el usuario abre la app con el SDK de Adapty por primera vez. Adapty se entera de las compras realizadas en el sistema legacy en tiempo real. Sin embargo, solo puede enviar un evento de integración una vez que el perfil del comprador existe. Ese perfil se crea cuando el usuario abre la app con el SDK de Adapty. Los usuarios que no actualicen a la nueva versión no generarán eventos de integración. ## Prepárate antes del día de la migración \{#prepare-before-migration-day\} ### Excluye los eventos históricos \{#exclude-historical-events\} Activa **Exclude Historical Events** en los [ajustes de tu integración](configuration). Esto impide que los eventos anteriores a la primera sesión del usuario con el SDK de Adapty se envíen a la integración. Esta configuración es especialmente importante durante la [importación histórica](importing-historical-data-to-adapty), cuando Adapty procesa un gran volumen de transacciones pasadas de una vez. Sin ella, esas transacciones generarán un gran volumen de eventos en tu herramienta de analytics. ### Configura la integración con antelación \{#set-up-the-integration-in-advance\} Adapty te permite configurar y probar una integración mientras la mantienes desactivada. Puedes establecer credenciales, mapeo de eventos y filtros sin activar la integración hasta que estés listo. La configuración se guarda cuando la activas, así que no se pierde nada por mantenerla desactivada hasta el día de la migración. Para encontrar tu integración, consulta [Integraciones de atribución](attribution-integration), [Integraciones de analytics](analytics-integration), [Integraciones de servicios de mensajería](messaging) o [Integraciones de Webhook y ETL](webhook-and-etl). ## Realiza el cambio el día de la migración \{#switch-on-migration-day\} Desactiva la integración en tu solución legacy y actívala en Adapty al mismo tiempo. Ejecutar ambas simultáneamente generará eventos duplicados. Pausa las campañas de adquisición grandes el día de la migración. Esto reduce el riesgo de errores en la optimización de campañas causados por eventos en la ventana de solapamiento. ## Qué esperar \{#what-to-expect\} Algunos eventos de integración perdidos o duplicados durante la migración son inevitables. Cuando el cambio se realiza correctamente, el número de eventos afectados es insignificante. La principal fuente de huecos es el momento descrito anteriormente: Adapty solo puede enviar eventos de integración para una compra después de que exista el perfil del usuario. Las compras realizadas en el sistema legacy no generan eventos de integración en Adapty hasta que el comprador abre la app con el SDK de Adapty. ## Integraciones frente a notificaciones server-to-server \{#integrations-vs-server-to-server-notifications\} Adapty recomienda usar integraciones en lugar de reenviar las notificaciones server-to-server sin procesar del store directamente a tus herramientas de analytics o atribución. Con las integraciones: - **Formato unificado**: los eventos de todos los stores — App Store, Google Play, Stripe — utilizan el mismo formato de evento. - **Datos enriquecidos**: los eventos incluyen datos que Adapty recopila, como el estado de la suscripción y los atributos del usuario. Las notificaciones sin procesar no incluyen esto. --- # File: whats-new --- --- title: "Novedades" description: "Mantente al día con las últimas funciones y mejoras de Adapty" --- Descubre las últimas funciones, mejoras, actualizaciones del SDK y mejoras en la documentación que te ayudan a optimizar la estrategia de monetización de tu app. Esta página destaca los lanzamientos más importantes de cada mes. :::note ¿Tienes comentarios sobre las nuevas funciones? ¡Nos encantaría escucharte! Contáctanos a través del [tablón de comentarios sobre el producto](https://adapty.featurebase.app/en?b=69831ba5e82e7a3391632ec2). ::: ## Julio 2026 \{#july-2026\} - **Monedas virtuales**: Define monedas dentro de la app como tokens, monedas o gemas, asigna y rastrea el saldo de cada usuario, y consulta esos saldos desde tu servidor a través de la API server-side. [Más información](virtual-currencies) - **Agente de IA en Apple Ads Manager**: Consulta a un agente de chat sobre el rendimiento de tus Apple Ads y obtén respuestas basadas en los datos de tus campañas, sin necesidad de crear informes manualmente. [Más información](ads-manager-ai-agent) - **Nuevas automatizaciones en Apple Ads Manager**: Automatiza cambios a nivel de campaña y grupo de anuncios con dos nuevos tipos de reglas, junto a las automatizaciones existentes de palabras clave y términos de búsqueda. [Reglas de campaña](ads-manager-automations-campaign-rules) | [Reglas de grupo de anuncios](ads-manager-automations-ad-group-rules) - **Perfiles en Adapty Mail**: Una vista por suscriptor que muestra el recorrido de cada usuario, el estado actual de la suscripción y el estado de cancelación de suscripción en un solo lugar. [Más información](mail-profiles) - **SDK v4 para React Native, Flutter, Capacitor y Kotlin Multiplatform**: Los SDKs v4 con soporte para Flows ya están disponibles. React Native, Flutter y Capacitor alcanzaron disponibilidad general, y Kotlin Multiplatform v4 se ha lanzado — cada uno con su propia guía de migración. [React Native](migration-to-react-native-sdk-v4) | [Flutter](migration-to-flutter-sdk-v4) | [Capacitor](migration-to-capacitor-sdk-v4) | [Kotlin Multiplatform](migration-to-kmp-sdk-v4) - **Nuevos campos en webhooks**: Los payloads de los webhooks ahora incluyen el precio original y el descuento de cada transacción, para que puedas rastrear las ofertas promocionales e introductorias. Estos campos están disponibles únicamente en webhooks. [Más información](webhook-event-types-and-fields) - **Precios tachados en flows**: Muestra el precio original tachado junto al precio con descuento, con una insignia de descuento, directamente en el Flow Builder. [Más información](strikethrough-price) - **Galería de plantillas de flow**: Empieza un nuevo flow desde una plantilla diseñada por profesionales en lugar de un lienzo en blanco y personalízala para que encaje con tu app. [Más información](paywall-builder-templates) - **Botón Install tools**: Ahora todos los artículos de documentación tienen un botón **Install tools** en la cabecera. Al pulsarlo, se abre un modal con comandos listos para copiar e instalar la skill de integración del SDK de Adapty en Claude Code, Copilot CLI, Gemini CLI, Codex y otros asistentes de programación con IA. [Más información](adapty-sdk-integration-skill) - **Nuevo método de instalación del SDK de Unity**: Ahora puedes instalar el SDK de Unity a través de Swift Package Manager, con orientación adicional para solucionar problemas comunes de configuración. [Más información](sdk-installation-unity) - **Contenedor de pie de página en el Flow Builder**: Un panel inferior fijo que permanece anclado mientras el resto de la pantalla se desplaza — ideal para botones de CTA, texto legal y enlaces. [Más información](builder-containers#footer) - **Nuevos tutoriales en vídeo del Flow Builder**: Una lista de reproducción de YouTube en crecimiento con guías paso a paso para construir flows, ahora integrada en las guías del Flow Builder. [Más información](adapty-flow-builder) ## Junio 2026 \{#june-2026\} - **Los flows ahora funcionan en Android**: El editor visual sin código para paywalls y onboardings ya está disponible en Android SDK v4 y superiores, además de iOS. Las pantallas se renderizan de forma nativa, sin web views. [Más información](adapty-flow-builder) - **Pruebas A/B de CPP en Apple Ads Manager**: Compara páginas de producto personalizadas entre sí dentro de Apple Ads. Elige entre 2 y 4 páginas — incluida tu página predeterminada actual — y Apple Ads distribuye el tráfico entre ellas e informa sobre cuál convierte mejor. [Más información](ads-manager-cpp-ab-tests) - **Adapty Mail API**: Envía perfiles de usuario y transacciones a Adapty Mail directamente desde tu servidor, sin pasar los datos por el SDK. Úsala para crear una base de suscriptores, reutilizar suscriptores de otras apps o mantener tu backend como fuente de verdad. [Más información](mail-send-data-via-api) - **Mostrar un paywall dirigido por Apple Ads en el primer lanzamiento**: la atribución de Apple Ads llega después de que el SDK se activa, por lo que un paywall solicitado demasiado pronto no alcanza tu audiencia de Apple Ads. Usa `AdaptyProfile.appliedAttributionSources` para mostrar el paywall dirigido por Apple Ads en cuanto lleguen los datos de atribución. [iOS](ios-show-aa-targeted-paywall) | [React Native](react-native-show-aa-targeted-paywall) | [Capacitor](capacitor-show-aa-targeted-paywall) - **Autoguardado en el Flow Builder**: El Flow Builder ahora guarda tu progreso automáticamente cada minuto, por lo que ya no perderás trabajo sin guardar al salir de la página. También puedes guardar un borrador manualmente con **Cmd/Ctrl + S**. [Más información](builder-save-publish) - **Nuevos tutoriales en vídeo del Flow Builder**: Dos nuevos recorridos explican cómo crear navegación entre pantallas del flow y cómo diseñar estados de elementos como seleccionado, activo y desactivado. [Navegación en flows](onboarding-navigation-branching) | [Estados de elementos](builder-element-states) - **Documentación en japonés y vietnamita**: La documentación de Adapty ya está disponible en japonés (日本語) y vietnamita (Tiếng Việt). Cambia de idioma con el selector de idioma en la navegación superior. ## Mayo 2026 \{#may-2026\} - **Flows (Beta)**: Crea secuencias de pantallas completas en un editor visual sin código — paywalls de una sola pantalla, onboardings de varios pasos y todo lo que hay entre medias, todo en un flow. Las pantallas se renderizan de forma nativa sin web views, y puedes actualizar textos, diseño y lógica sin publicar una nueva versión de la app. Actualmente es compatible con iOS, Android, React Native, Flutter y Capacitor SDK v4 en adelante. [Más información](adapty-flow-builder) - **Autopilot ahora se adapta a tus resultados**: Actuando como un gestor de crecimiento con IA, actualiza el plan de crecimiento tras cada ronda completada. La siguiente hipótesis se construye a partir de los experimentos que has ejecutado, cuáles ganaron y qué direcciones siguen valiendo la pena explorar, en lugar de seguir una secuencia fija. [Más información](autopilot-how-it-works#how-ai-growth-advisor-decides-what-to-recommend) - **ARPU de activación en Autopilot Market Insights**: Un nuevo gráfico compara el ingreso promedio por instalación nueva de tu app con la media de la categoría. Combínalo con el embudo de conversión: una conversión alta junto con un ARPU de activación bajo puede indicar que las ofertas tienen un precio demasiado bajo. [Más información](autopilot-analysis#activation-arpu) - **Analytics en Adapty Mail**: Compara métricas de entrega e ingresos atribuidos al email para cada campaña en una sola vista. Agrupa, desglosa y filtra por campaña, segmento, variante de prueba A/B, mensaje o trigger, y profundiza en cualquier fila. [Más información](mail-analytics) - **Perfil de marca en Adapty Mail**: Un perfil centralizado que define el contenido de los correos, el tono, los elementos visuales y el contenido del paywall web. Adapty lo genera a partir de la ficha de tu app en el store, la página de aterrizaje, las páginas legales y los perfiles sociales, y puedes revisar o ajustar cada sección directamente. [Más información](mail-brand) - **Predicciones en Adapty UA**: Ingresos previstos, ROAS, beneficio publicitario, ARPU y ARPPU para cada cohorte, para que puedas comparar campañas antes de que maduren. Las predicciones se construyen a partir de los datos históricos de cohortes de tu propia app, se actualizan diariamente y están disponibles para períodos de cohorte desde D0 hasta D360 o un día personalizado. [Más información](ua-predicted-metrics) - **Nuevos campos en la exportación personalizada S3 de Adapty UA**: La exportación personalizada a S3 ahora incluye `bundle_id`, `device_brand`, `device_model`, `os_version`, `app_version` y `sdk_version`. Segmenta y combina datos de atribución por dispositivo y versión de app en tus sistemas downstream. [Más información](ua-custom-s3) - **Audiencias de placement en la CLI**: Los comandos `adapty placements create` y `adapty placements update` ahora aceptan el flag `--audiences` — un array JSON de entradas `{segment_ids, paywall_id, priority}` — para que puedas dirigir distintos paywalls a distintos segmentos desde el terminal. El nuevo comando `adapty paywalls placements` lista todos los placements que usan un paywall concreto, para que puedas previsualizar el impacto antes de cambiarlo. [Más información](developer-cli-reference#placements) - **Documentación en español**: La documentación de Adapty ya está disponible en español. Cambia de idioma usando el selector de idioma en la navegación superior. ## Abril 2026 \{#april-2026\} - **Adapty Mail**: Campañas de email generadas por IA que convierten a usuarios en prueba en suscriptores de pago. Crea, envía y atribuye campañas desde tu proyecto de Adapty sin necesidad de ninguna plataforma de email independiente. [Más información](adapty-mail) - **Diagnóstico de paywall en Autopilot**: Descubre qué mejorar en tu paywall antes de crear una prueba. Sube una captura de pantalla y Autopilot te devuelve recomendaciones basadas en benchmarks de las apps con mejor rendimiento en tu categoría, además de sugerencias de diseño y texto generadas por IA. Las recomendaciones con benchmark se convierten en rondas de prueba A/B en tu plan de crecimiento. [Más información](autopilot-analysis#paywall-analysis) - **Orientación más clara para cada sugerencia de Autopilot**: Cada hipótesis ahora explica por qué es importante (una explicación basada en datos sobre cómo tu paywall se desvía de los patrones establecidos), qué cambiar y cómo configurar la prueba A/B, y qué métricas vigilar en una nueva sección "Cómo interpretar tus resultados". [Más información](autopilot-execute-plan#step-1-view-the-hypothesis) - **Mantén actualizado tu plan de crecimiento Autopilot**: Actualiza el análisis para obtener los datos de mercado más recientes y nuevas sugerencias, y revisa las sugerencias anteriores en el historial de versiones si las nuevas no se ajustan a lo que buscas. Las hipótesis se agrupan en las pestañas Top priority, All, Pricing, Visual, Geo-pricing y Archived. [Más información](autopilot-growth-plan) - **Distribución de ingresos por duración en Autopilot**: Comprueba si tus ingresos están sobreconcentrados en una duración de suscripción. Un nuevo gráfico de Market Insights muestra la composición de tus ingresos por duración junto con la media del sector para tu categoría y país. [Más información](autopilot-analysis#revenue-distribution-by-duration) - **LTV y predicciones de ingresos actualizadas**: El LTV predicho y los ingresos ahora utilizan los datos de retención de cohortes de tu propia app cuando hay suficiente historial, y promedios entre apps en caso contrario — así incluso las apps más nuevas obtienen predicciones utilizables en análisis y pruebas A/B. [Más información](predicted-ltv-and-revenue) - **Enviar todos los eventos en Adapty UA**: Dale a Meta y TikTok una visión más completa de las conversiones para un modelado de audiencias más preciso. Adapty ahora permite reenviar instalaciones y transacciones de usuarios orgánicos y no atribuidos a tu píxel, no solo de usuarios vinculados a una campaña. [Meta](ua-facebook#send-all-events) | [TikTok](ua-tiktok#send-all-events) - **Documentación en ruso y turco**: La documentación de Adapty ya está disponible en ruso (Русский) y turco (Türkçe). Cambia de idioma usando el selector de idioma en la navegación superior. ## Marzo 2026 \{#march-2026\} - **CLI para desarrolladores**: Gestiona tu cuenta de Adapty desde la terminal sin abrir el Dashboard. El CLI te permite crear apps, definir niveles de acceso, configurar productos, crear paywalls y configurar placements — todo scriptable para entornos automatizados. También hay disponible una [skill de Adapty CLI](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) para ayudar a los asistentes de programación con IA a trabajar con el CLI. [Más información](developer-cli) - **Página general en Apple Ads Manager**: Consulta todas las métricas clave de Apple Ads en un solo lugar, cada una con un gráfico de tendencias. Filtra por app mediante el desplegable del encabezado, personaliza qué métricas se muestran y ajusta el tipo de gráfico y la visualización de ingresos. [Más información](ads-manager-overview) - **Inteligencia de mercado en Apple Ads Manager**: Descubre en qué palabras clave publican anuncios tus competidores en más de 50 países y añade las palabras clave de mejor rendimiento directamente a tus campañas. [Más información](ads-manager-market-intelligence) - **Automatizaciones de palabras clave de ciclo completo en Apple Ads Manager**: Ajusta pujas automáticamente, pausa o activa palabras clave y muévelas entre grupos de anuncios según las reglas de rendimiento que definas. [Más información](ads-manager-automations-keyword-rules) - **Historial de pujas en Apple Ads Manager**: Consulta el registro completo de cambios de la puja CPT de cualquier palabra clave: cuándo ocurrió cada cambio, los valores anterior y nuevo, y qué regla de automatización lo desencadenó. [Más información](ads-manager-manage-keywords#bid-history) - **Rondas visuales en Autopilot**: Las sugerencias de diseño de paywall ahora son rondas de primera clase en tu plan de crecimiento — aparecen en la barra lateral junto a las rondas de monetización. Cada ronda visual incluye un mockup de diseño, una descripción de cuándo funciona mejor ese patrón y las métricas clave que tiene como objetivo. [Más información](autopilot-growth-plan#view-the-growth-plan) - **Añade tu propia hipótesis a Autopilot**: Amplía tu plan de crecimiento con rondas personalizadas. Añade un título, descripción, tipo de ronda (monetización o visual), métricas objetivo y — en el caso de rondas de monetización — los productos involucrados. [Más información](autopilot-growth-plan#add-your-own-hypothesis) - **Reordena las rondas de Autopilot**: Arrastra y reordena las etapas de tu plan de crecimiento para ejecutar los experimentos en el orden que mejor se adapte a tu estrategia. [Más información](autopilot) - **Precios geográficos en Autopilot**: Prueba cambios de precio por país como un nuevo tipo de ronda en tu plan de crecimiento. A partir de los datos de Market Insights, Autopilot recomienda si aumentar, reducir o mantener los precios en cada país. Añade una recomendación como ronda de precios geográficos para ejecutarla como prueba A/B — se pueden ejecutar hasta 5 simultáneamente. [Más información](autopilot-growth-plan#geo-pricing-hypotheses) - **Automatizaciones de términos de búsqueda en Apple Ads Manager**: Promociona automáticamente los términos de búsqueda ganadores a palabras clave de coincidencia exacta y niégalos en el origen, sin necesidad de descargar informes manualmente. Las reglas se pueden crear desde plantillas o construir desde cero con condiciones y programaciones personalizadas. [Más información](ads-manager-automations-search-terms) - **Puja de Maximizar Conversiones en Apple Ads Manager**: Al crear campañas, ahora puedes seleccionar Maximizar Conversiones como estrategia de puja. El algoritmo de Apple maximiza las descargas dentro de tu presupuesto, guiado por un CPA objetivo opcional. [Más información](ads-manager-create-campaign) - **Integración con FunnelFox en Adapty UA**: Ya está disponible la nueva integración con FunnelFox en Adapty UA. [FunnelFox](ua-funnelfox) - **Documentación en chino**: La documentación de Adapty ya está disponible en chino (中文). Cambia de idioma con el selector de idioma en la navegación superior. ## Febrero de 2026 \{#february-2026\} - **Precios de productos por país**: Establece precios distintos por país directamente en el Adapty Dashboard — Adapty sincroniza los cambios con App Store Connect y Google Play de forma automática. Cada actualización de precios queda registrada en el registro de auditoría, sin que ningún cambio pase desapercibido. [Más información](edit-product) - **Precios de la competencia por país en Autopilot**: Compara los precios de tu suscripción con los de la competencia en tus mercados principales. [Más información](autopilot-analysis#market-and-competitor-analysis) - **Control de versiones de onboarding**: Lleva un seguimiento y gestiona las versiones de tus onboardings con un historial completo de versiones. Revisa los cambios y haz rollback cuando lo necesites. - **Gráficos de conversión de paywall en análisis**: Dos nuevos gráficos de conversión — Paywall view → Trial y Paywall view → Paid — muestran cómo tus paywalls convierten visitantes en suscriptores. [Más información](analytics-conversion) - **Segmentos duplicados**: Copia un segmento existente con todos sus filtros en lugar de reconstruir uno similar desde cero. Útil cuando se gestionan varias campañas o pruebas A/B con audiencias superpuestas. [Más información](segments#duplicate-segments) - **Notificaciones push en la app móvil de Adapty**: Configura notificaciones push para 14 tipos de eventos directamente en la app de Adapty para iOS y mantente al tanto de la actividad de suscripciones sin abrir el dashboard. [Más información](push-notifications) - **Kotlin Multiplatform SDK 3.15**: Añade soporte para onboardings, paywalls web y mejoras en la API. [Más información](migration-to-kmp-315) - **Capacitor SDK 3.16**: Añade soporte para Capacitor 8. Los proyectos que usen Capacitor 7 deben quedarse en el SDK v3.15. [Más información](migration-to-capacitor-316) - **Guías de integración del SDK asistidas por LLM**: Guías paso a paso para integrar Adapty con la ayuda de asistentes de código IA. Cada guía lleva a tu LLM por toda la implementación, desde la configuración del dashboard hasta las compras. [iOS](adapty-cursor) | [Android](adapty-cursor-android) | [React Native](adapty-cursor-react-native) | [Flutter](adapty-cursor-flutter) | [Unity](adapty-cursor-unity) | [Kotlin Multiplatform](adapty-cursor-kmp) | [Capacitor](adapty-cursor-capacitor). Para un flow automatizado en un solo comando, prueba el nuevo **adapty-sdk-integration skill** (beta): [iOS](adapty-sdk-integration-skill) | [Android](adapty-sdk-integration-skill-android) | [React Native](adapty-sdk-integration-skill-react-native) | [Flutter](adapty-sdk-integration-skill-flutter) | [Unity](adapty-sdk-integration-skill-unity) | [Kotlin Multiplatform](adapty-sdk-integration-skill-kmp) | [Capacitor](adapty-sdk-integration-skill-capacitor) ## Enero de 2026 \{#january-2026\} - **SDK de Capacitor publicado oficialmente**: El SDK de Capacitor ya está listo para producción tras un exhaustivo proceso de pruebas. Crea apps de suscripción para iOS y Android con Capacitor y soporte completo de integración con Adapty. [Más información](capacitor-sdk-overview) - **Autopilot para apps nuevas**: El análisis de Autopilot ya está disponible aunque tu app no tenga un historial extenso de transacciones. Obtén recomendaciones de optimización de precios basadas en datos y crea tu plan de crecimiento desde el primer día. [Más información](autopilot) - **Oportunidades de precios globales en Autopilot**: Identifica el potencial de ingresos en tus mercados más rentables con recomendaciones de precios por país. Autopilot analiza las tasas de conversión y el poder adquisitivo de tus 5 principales países, y te ofrece información basada en datos sobre si conviene subir, bajar o mantener los precios según el Índice de Precios de Adapty. [Más información](autopilot) - **Métricas de conversión de recuperación de facturación**: Nuevos gráficos de análisis rastrean los ingresos recuperados por problemas de facturación y períodos de gracia. Monitoriza "Billing issue converted", "Billing issue converted revenue", "Grace period converted" y "Grace period converted revenue" para medir tus esfuerzos de retención y recuperación. - **Gestión de anuncios directa en Apple Ads Manager**: Crea y gestiona tus campañas de Apple Ads directamente desde Adapty sin cambiar de plataforma. [Más información](ads-manager-manage-ads) - **Análisis de Apple Ads Manager**: Accede a métricas de rendimiento detalladas a nivel de anuncio y datos de atribución dentro de Adapty. Consulta el rendimiento de campañas, análisis de grupos de anuncios e información de atribución en un dashboard unificado. [Más información](adapty-ads-manager-analytics) - **Gráficos de atribución de Apple Ads**: Combina múltiples métricas de atribución en gráficos personalizables para analizar el rendimiento de tus Apple Ads junto con los datos de suscripción. [Más información](adapty-ads-manager-analytics#charts) - **Segmentos de atribución de Apple Ads**: Crea segmentos de usuarios basados en datos de atribución de Apple Ads con un flujo de trabajo simplificado de dos clics. Dirige tus campañas a usuarios por campaña, grupo de anuncios o palabra clave para análisis y experimentos más precisos. [Más información](ads-manager-create-segments) - **Nueva plataforma de documentación**: El sitio de documentación ha migrado a una nueva plataforma, lo que permite actualizaciones de funciones más rápidas y una experiencia de usuario mejorada con búsqueda, navegación y organización de contenido optimizadas. ## Diciembre 2025 \{#december-2025\} - **Documentación de Apple Ads Manager**: Combina los datos de tus campañas de Apple Search Ads con métricas de ingresos en un único dashboard de análisis. La nueva documentación cubre la creación de campañas, la gestión de grupos de anuncios y las formas de hacer seguimiento del ROI de tu inversión publicitaria junto al rendimiento de las suscripciones. [Más información](ads-manager) - **Paywalls web in-app**: Muestra paywalls basados en web dentro de tu app usando un navegador in-app, ofreciendo una experiencia fluida sin redirecciones externas. [iOS](ios-web-paywall#open-web-paywalls-in-an-in-app-browser) | [Android](android-web-paywall#open-web-paywalls-in-an-in-app-browser) | [React Native](react-native-web-paywall#open-web-paywalls-in-an-in-app-browser) | [Flutter](flutter-web-paywall#open-web-paywalls-in-an-in-app-browser) - **Segmentos dinámicos**: Crea segmentos de audiencia dinámicos que se actualizan automáticamente en función de ventanas de tiempo móviles. Por ejemplo, crea un segmento de "usuarios que instalaron la app en los últimos 7 días" que se refresca continuamente para mostrar siempre a tus clientes más recientes. [Más información](segments#available-attributes) - **Guías de configuración de campañas en Meta y TikTok**: Documentación paso a paso para crear y rastrear campañas en Meta (Facebook e Instagram) y TikTok, con seguimiento de conversiones e integración de analíticas. [Meta](meta-create-campaign) | [TikTok](tiktok-create-campaign) - **Guías de inicio rápido para implementación manual de paywalls**: Implementa compras in-app más rápido con guías paso a paso que muestran cómo integrar el SDK de Adapty en tu UI de paywall personalizada. [iOS](ios-implement-paywalls-manually) | [Android](android-implement-paywalls-manually) | [React Native](react-native-implement-paywalls-manually) | [Flutter](flutter-implement-paywalls-manually) | [Unity](unity-implement-paywalls-manually) | [Kotlin Multiplatform](kmp-quickstart-manual) | [Capacitor](capacitor-quickstart-manual) - **Navegador integrado para los enlaces del onboarding**: Los enlaces externos en los onboardings se abren ahora por defecto en un navegador integrado, manteniendo a los usuarios dentro de la app. Puedes personalizar este comportamiento para usar navegadores externos si lo necesitas. [iOS](ios-present-onboardings#customize-how-links-open-in-onboardings) | [Android](android-present-onboardings#customize-how-links-open-in-onboardings) | [React Native](react-native-present-onboardings#customize-how-links-open-in-onboardings) - **Sugerencias mejoradas de Autopilot**: Autopilot ahora ofrece mejores recomendaciones de optimización de precios basadas en un análisis más detallado de los datos de tu suscripción. [Prueba Autopilot](autopilot) - **Modo oscuro en la documentación**: La documentación ahora es compatible con el modo oscuro, con detección automática de las preferencias del sistema o activación manual desde la esquina superior derecha. --- # File: adapty-ecosystem --- --- title: "El ecosistema de Adapty" description: "Adapty es una plataforma de compras in-app para aplicaciones móviles. Conoce qué hace cada producto y cómo se conectan." --- Adapty es una plataforma de compras in-app para aplicaciones móviles, creada con una sola misión: hacer que las apps sean rentables. Te da todo lo que necesitas para aumentar los ingresos: captar usuarios, convertirlos, mantenerlos suscritos y recuperar a los que se van. Con un solo registro tienes acceso a todo el ecosistema de Adapty desde el primer día. Haz clic en el logo de Adapty para cambiar entre productos: - **Core** — procesa compras sin tocar StoreKit ni Google Play Billing, diseña paywalls sin código y haz seguimiento de ingresos en tiempo real. El resto de productos se construyen sobre esta base. - **Adapty Ads Manager** — ejecuta y optimiza Apple Ads, medidos frente a ingresos reales de suscripciones. - **Adapty Attribution** — descubre qué canales de publicidad generan ingresos de verdad, sin necesidad de MMP. - **Adapty Mail** — convierte trials y recupera usuarios que se dieron de baja con emails automatizados. Otros dos productos complementan los cuatro principales: **FunnelFox** (funnels de web a app y checkout alojado) y **Adapty Finance** (anticipos sobre ingresos futuros por suscripciones). ## Cómo encajan los productos entre sí \{#how-the-products-fit-together\} Cada producto interviene en un punto distinto del ciclo de vida del cliente. Pasa el cursor sobre cualquier funcionalidad enlazada para ver una definición rápida, o haz clic para ir a su documentación.
3. En la ventana **Generate In-App Purchase Key** que se abre, introduce el nombre de la clave para tu referencia futura. No se utilizará en Adapty.
4. Haz clic en el botón **Generate**. Una vez que se cierre la ventana **Generate in-App Purchase Key**, verás la clave creada en la lista **Active**.
5. Una vez generada tu clave de API, haz clic en el botón **Download In-App Purchase Key** para obtener la clave como archivo.
6. En la ventana **Download in-App Purchase Key**, haz clic en el botón **Download**. El archivo se guardará en tu ordenador.
Es fundamental mantener este archivo seguro para subirlo al Adapty Dashboard en el futuro. Ten en cuenta que el archivo generado solo se puede descargar una vez, así que asegúrate de guardarlo en un lugar seguro hasta que lo subas. La clave .p8 generada desde la sección **In-App Purchase** se utilizará al [configurar la integración inicial de Adapty con el App Store](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file).
**Próximos pasos:**
- [Configurar la integración con App Store](app-store-connection-configuration)
---
# File: app-store-connection-configuration
---
---
title: "Configurar la integración con App Store"
description: "Configura tu conexión con App Store para un seguimiento de suscripciones sin interrupciones."
---
3. Copia el **Issuer ID** y pégalo en el campo **In-app purchase Issuer ID** del Adapty Dashboard.
4. Copia el **Key ID** y pégalo en el campo **In-app purchase Key ID** del Adapty Dashboard.
## Paso 3. Sube el archivo de clave de compra in-app \{#step-3-upload-in-app-purchase-key-file\}
Sube el archivo de **In-App Purchase Key** que descargaste en la sección [Generar la clave de compra in-app en App Store Connect](generate-in-app-purchase-key)
en el campo **Private key (.p8 file)** del Adapty Dashboard.
## Paso 4. Para pruebas y ofertas especiales: configura las ofertas promocionales \{#step-4-for-trials-and-special-offers--set-up-promotional-offers\}
:::important
Este paso es obligatorio si tu app tiene [pruebas u otras ofertas promocionales](offers).
:::
1. Copia el mismo ID de clave que usaste en el [Paso 2](#step-2-provide-issuer-id-and-key-id) en el campo **Subscription key ID** de la sección **App Store promotional offers**.
2. Sube el mismo archivo **In-App Purchase Key** que usaste en el [Paso 3](#step-3-upload-in-app-purchase-key-file) al área **Subscription key (.p8 file)** de la sección **App Store promotional offers**.
## Paso 5. Introduce el App Store shared secret \{#step-5-enter-app-store-shared-secret\}
El **App Store shared secret**, también conocido como App Store Connect Shared Secret, es una cadena hexadecimal de 32 caracteres que se utiliza para la validación de recibos de compras in-app y suscripciones.
1. Abre [App Store Connect](https://appstoreconnect.apple.com/apps). Selecciona tu app y ve a la sección **General** → **App Information**.
2. Desplázate hasta la subsección **App-Specific Shared Secret**.
:::info
Si la subsección **App-Specific Shared Secret** no aparece, asegúrate de tener el rol de Account Holder o Admin. Si tienes el rol de Admin y aun así no ves la subsección **App-Specific Shared Secret**, pide al Account Holder de la app (la persona que creó la aplicación en App Store Connect) que genere el shared secret de la app. Después de eso, la subsección también será visible para los Admins.
:::
3. Haz clic en el botón **Manage**.
4. En la ventana **App-Specific Shared Secret** que se abre, copia el **Shared Secret**. Si no ves ningún shared secret, haz clic primero en el botón **Manage** o **Generate** (el que esté disponible) y luego copia el **Shared Secret**.
5. Pega el **Shared Secret** copiado en el campo **App Store shared secret** del Adapty Dashboard.
6. Haz clic en el botón **Save** del Adapty Dashboard para confirmar los cambios.
## Paso 6. Añade la clave de API de App Store Connect \{#step-6-add-app-store-connect-api-key\}
Genera una clave de API de App Store Connect y añádela a Adapty para poder [gestionar tus productos en el App Store desde el Adapty Dashboard](create-product#create-product-and-push-to-store):
1. En App Store Connect, ve a [**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api) y haz clic en **+**.
2. En la ventana **Generate API key window**, introduce un nombre para la clave y otórgale acceso **Admin**.
3. Haz clic en **Download** junto a tu clave. Ten en cuenta que solo puedes descargarla una vez.
4. En el Adapty Dashboard, ve a [**App settings > iOS SDK**](https://app.adapty.io/settings/ios-sdk) y haz clic en **Connect API key**.
5. Rellena los campos en la ventana:
- **Issuer ID**: Cópialo desde [**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api). Está encima de la tabla **API keys**.
- **Key ID**: Cópialo desde [**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api). Está en la tabla **API keys** junto a tu clave.
- **API key**: Sube el archivo de clave API que has descargado desde App Store Connect.
6. Haz clic en **Connect**.
**Qué hacer a continuación**
- [Activar las notificaciones del servidor de App Store](enable-app-store-server-notifications)
---
# File: enable-app-store-server-notifications
---
---
title: "Activar notificaciones de servidor de App Store"
description: "Activa las notificaciones de servidor de App Store para rastrear eventos de suscripción en tiempo real."
---
Configurar las notificaciones de servidor de App Store es fundamental para garantizar la precisión de los datos, ya que te permite recibir actualizaciones en tiempo real desde App Store, incluyendo información sobre reembolsos y otros eventos.
:::important
Se requiere Adapty iOS SDK 2.10.0 o posterior para soporte completo de App Store Server Notifications V2.
:::
1. Copia la **URL for App Store server notification** en el Adapty Dashboard.
2. Abre [App Store Connect](https://appstoreconnect.apple.com/apps). Selecciona tu aplicación y ve a la sección **General** → **App Information**, subsección **App Store Server Notifications**.
3. Pega la **URL for App Store server notification** copiada en los campos **Production Server URL** y **Sandbox Server URL**.
## Reenvío de eventos sin procesar \{#raw-events-forwarding\}
En algunos casos, puede que quieras seguir recibiendo eventos S2S sin procesar desde Apple. Para continuar recibiéndolos mientras usas Adapty, simplemente añade tu endpoint al campo **URL for forwarding raw Apple events** y te enviaremos los eventos tal como los recibimos de Apple.
**Siguientes pasos**
Configura el SDK de Adapty para:
- [iOS](sdk-installation-ios)
- [React Native](sdk-installation-reactnative)
- [Flutter](sdk-installation-flutter)
- [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)
- [Unity](sdk-installation-unity)
---
# File: troubleshoot-app-store-integration
---
---
title: "Solucionar problemas de integración con App Store"
description: "Resuelve los problemas más comunes de configuración con la App Store de Apple: acuerdos pendientes, retrasos en notificaciones del servidor y discrepancias de precios."
---
Este artículo cubre los problemas más comunes de integración con App Store. Cada sección describe los síntomas, la causa raíz y la solución.
## Los productos no aparecen \{#products-dont-appear\}
Dos síntomas distintos apuntan a la misma causa raíz:
- La clave API de App Store Connect está configurada correctamente, pero Adapty no puede obtener los productos.
- Los productos existen en App Store Connect pero no aparecen en Adapty, o aparecen menos de los esperados. El SDK reporta "Product Id not found" al intentar realizar una compra.
La causa más común es que los **acuerdos de Apple estén sin firmar** — el acuerdo de pago, los formularios fiscales o los formularios bancarios en estado pendiente o sin firmar. Cuando los acuerdos están pendientes, la API de App Store Connect devuelve silenciosamente un 403 en los endpoints relacionados con productos. No se muestra ningún error claro en Adapty; los productos simplemente se descartan sin aviso.
Ve a **App Store Connect → Agreements, Tax, and Banking** y firma todos los acuerdos pendientes. Luego vuelve a sincronizar en **App settings → iOS SDK** de Adapty.
## Las notificaciones del servidor de App Store muestran "Delayed" \{#app-store-server-notifications-show-delayed\}
En App Store Connect, el estado de las App Store Server Notifications puede aparecer como **Delayed**. Esto significa que Apple tiene retraso en el envío de notificaciones de eventos de suscripción: renovaciones, cancelaciones y problemas de facturación se acumulan en cola y llegan tarde.
Las estadísticas de instalaciones no se ven afectadas. Adapty contabiliza las instalaciones desde el primer lanzamiento de la app, no a partir de notificaciones del servidor.
Si los datos de renovación o cancelación van por detrás, el estado Delayed es la causa más probable. El estado suele desaparecer automáticamente a medida que Apple procesa el backlog.
## Los precios en Adapty no coinciden con App Store \{#prices-in-adapty-dont-match-app-store\}
El campo **price** en la página de edición de productos de Adapty se comporta de forma distinta según cómo se haya añadido el producto.
Si creas un producto en Adapty y lo publicas en la store desde el dashboard, este precio se utiliza como precio inicial en la store.
Si añades un producto que ya existe en la store, este precio es un marcador de posición. Las analíticas, integraciones y SDK de Adapty utilizan los precios reales obtenidos de App Store, independientemente de este valor. Los cambios en los precios de App Store no se sincronizan para actualizar el marcador de posición, y por ahora no es posible editar ese marcador desde el dashboard.
## La exportación de precios en CSV está vacía \{#csv-price-export-is-empty\}
Si tu exportación de precios en CSV solo devolvió las cabeceras de columna, significa que la clave API de App Store Connect no está completamente configurada. Consulta [Paso 6 — Añadir clave API de App Store Connect](app-store-connection-configuration#step-6-add-app-store-connect-api-key).
## No se pueden publicar nuevos productos en App Store \{#cant-push-new-products-to-app-store\}
Adapty puede publicar nuevos productos en App Store Connect cuando los creas en el dashboard. La opción de publicar queda bloqueada si la integración con App Store no está completamente configurada. Se requieren dos ajustes:
- **Apple app ID**: Configúralo en [Paso 1 — Proporcionar Bundle ID y Apple app ID](app-store-connection-configuration#step-1-provide-bundle-id-and-apple-app-id).
- **App Store Connect API key**: Configúrala en [Paso 6 — Añadir clave API de App Store Connect](app-store-connection-configuration#step-6-add-app-store-connect-api-key).
---
# File: enabling-of-devepoler-api
---
---
title: "Habilitar las APIs de desarrollador en Google Play Console"
description: "Habilita la API de desarrollador de Adapty para automatizar y simplificar la gestión de suscripciones en tu app."
---
3. Abre la página de la [**Google Play Android Developer API**](https://console.cloud.google.com/apis/library/androidpublisher.googleapis.com).
4. Haz clic en el botón **Enable** y espera a que aparezca el estado **Enabled**. Esto indica que la Google Android Developer API está habilitada.
5. Abre la página de la [**Google Play Developer Reporting API**](https://console.cloud.google.com/apis/library/playdeveloperreporting.googleapis.com).
6. Haz clic en el botón **Enable** y espera a que aparezca el estado **Enabled**.
7. Abre la página de la [**Cloud Pub/Sub API**](https://console.cloud.google.com/marketplace/product/google/pubsub.googleapis.com).
8. Haz clic en el botón **Enable** y espera a que aparezca el estado **Enabled**.
Las APIs de desarrollador están habilitadas.
Puedes verificarlo en la página [**APIs & Services**](https://console.cloud.google.com/apis/dashboard) de la Google Cloud Console. Desplázate hacia abajo por la página y comprueba que la tabla al final contiene las 3 APIs:
- Google Play Android Developer API
- Google Play Developer Reporting API
- Cloud Pub/Sub API
**Siguiente paso**
- [Crear una cuenta de servicio en la Google Cloud Console](create-service-account)
---
# File: create-service-account
---
---
title: "Crear una cuenta de servicio en Google Cloud Console"
description: "Aprende a crear una cuenta de servicio para el acceso seguro a la API en Adapty."
---
Para que Adapty pueda automatizar el acceso a los datos, es necesario crear una cuenta de servicio en Google Play Console.
1. Abre la sección [**IAM & Admin** -> **Service accounts**](https://console.cloud.google.com/iam-admin/serviceaccounts) de Google Cloud Console. Asegúrate de estar usando el proyecto correcto.
2. En la ventana **Service accounts**, haz clic en el botón **Create service account**.
3. En la subsección **Service account details** de la ventana **Create service account**, introduce el **Service Account Name** que quieras. Te recomendamos incluir "Adapty" en el nombre para indicar el propósito de esta cuenta. El **Service account ID** se generará automáticamente.
4. Copia la dirección de correo electrónico de la cuenta de servicio y guárdala para usarla más adelante.
5. Haz clic en el botón **Create and continue**.
6. En la lista desplegable **Select a role** de la subsección **Grant this service account access to project**, selecciona **Pub/Sub -> Pub/Sub Admin**. Este rol es necesario para habilitar las notificaciones en tiempo real para desarrolladores.
7. Haz clic en el botón **Add another role**.
8. En la nueva lista desplegable **Role**, selecciona **Monitoring -> Monitoring Viewer**. Este rol es necesario para permitir la monitorización de la cola de notificaciones.
9. Haz clic en el botón **Continue**.
10. Haz clic en el botón **Done** sin realizar ningún cambio. Se abrirá la ventana **Service accounts**.
**Siguiente paso**
- [Conceder permisos a la cuenta de servicio en Google Play Console](grant-permissions-to-service-account)
---
# File: grant-permissions-to-service-account
---
---
title: "Conceder permisos a la cuenta de servicio en la Google Play Console"
description: "Concede permisos a las cuentas de servicio para un acceso seguro y eficiente a la API."
---
Concede los permisos necesarios a la cuenta de servicio que Adapty utilizará para gestionar suscripciones y validar compras.
1. Abre la página [**Users and permissions**](https://play.google.com/console/u/0/developers/8970033217728091060/users-and-permissions) en la Google Play Console y haz clic en el botón **Invite new users**.
2. En la página **Invite user**, introduce el correo electrónico de los usuarios de servicio que has creado.
3. Cambia a la pestaña **Account permissions**.
4. Selecciona los siguientes permisos:
- View app information and download bulk reports (read-only)
- View financial data, orders, and cancellation survey responses
- Manage orders and subscriptions
- Manage store presence
5. Haz clic en el botón **Invite user**.
6. En la ventana **Send invite?**, haz clic en el botón **Send invite**. La cuenta de servicio aparecerá en la lista de usuarios.
**Siguientes pasos**
- [Genera el archivo de clave de la cuenta de servicio en la Google Play Console](create-service-account-key-file)
---
# File: create-service-account-key-file
---
---
title: "Generar el archivo de clave de cuenta de servicio en Google Play Console"
description: "Aprende a crear un archivo de clave de cuenta de servicio para una integración fluida con Adapty."
---
Para vincular tu app móvil en Play Store con Adapty, necesitarás generar archivos especiales de clave de cuenta de servicio en Google Play Console y subirlos a Adapty. Estos archivos ayudan a proteger tu app y evitan accesos no autorizados.
:::warning
Por lo general, la nueva cuenta de servicio tarda al menos 24 horas en activarse. Sin embargo, existe un [truco](https://stackoverflow.com/a/60691844). Tras crear la cuenta de servicio en [Google Play Console](https://play.google.com/apps/publish/), abre cualquier aplicación y ve a **Monetize** -> **Products** -> **Subscriptions/In-app products**. Edita la descripción de cualquier producto y guarda los cambios. Esto debería activar la cuenta de servicio de inmediato, y luego puedes revertir los cambios.
:::
1. Abre la sección [**Service accounts**](https://console.cloud.google.com/iam-admin/serviceaccounts) en Google Play Console. Asegúrate de haber seleccionado el proyecto correcto.
2. En la ventana que se abre, haz clic en **Add key** y elige **Create new key** en el menú desplegable.
3. En la ventana **Create private key for [Your_project_name]**, haz clic en **Create**. Tu clave privada se guardará en tu ordenador como un archivo JSON. Puedes encontrarlo usando el nombre de archivo que aparece en la ventana **Private key saved to your computer**.
4. En la ventana **Create private key for Your_project_name**, haz clic en el botón **Create**. Esta acción guardará tu clave privada en tu ordenador como un archivo JSON. Puedes usar el nombre del archivo que aparece en la ventana **Private key saved to your computer** para localizarlo si lo necesitas.
Necesitarás este archivo cuando [configures la integración con Google Play Store](google-play-store-connection-configuration).
:::warning
Por lo general, la nueva cuenta de servicio tarda al menos 24 horas en activarse. Sin embargo, existe un [truco](https://stackoverflow.com/a/60691844). Tras crear la cuenta de servicio en [Google Play Console](https://play.google.com/apps/publish/), abre cualquier aplicación y ve a **Monetize** -> **Products** -> **Subscriptions/In-app products**. Edita la descripción de cualquier producto y guarda los cambios. Esto debería activar la cuenta de servicio de inmediato, y luego puedes revertir los cambios.
:::
**Siguientes pasos**
- [Configurar la integración con Google Play Store](google-play-store-connection-configuration)
---
# File: google-play-store-connection-configuration
---
---
title: "Configurar la integración con Google Play Store"
description: "Configura la conexión con Google Play Store en Adapty para gestionar las compras in-app sin problemas."
---
Esta sección describe el proceso de integración de tu aplicación móvil distribuida a través de Google Play con Adapty. Tendrás que introducir los datos de configuración de tu app desde la Play Store en el Adapty Dashboard. Este paso es fundamental para validar las compras y recibir actualizaciones de suscripciones desde la Play Store dentro de Adapty.
Puedes completar este proceso durante el onboarding inicial o realizar cambios posteriormente en los **App Settings** del Adapty Dashboard.
:::danger
Los cambios de configuración solo son válidos antes de publicar tu aplicación móvil con los paywalls de Adapty integrados. Modificar la configuración tras el lanzamiento romperá la integración y los paywalls dejarán de mostrarse en tu aplicación.
:::
## Paso 1. Proporciona el Package name \{#step-1-provide-package-name\}
El Package name es el identificador único de tu app en Google Play Store. Es necesario para el funcionamiento básico de Adapty, como el procesamiento de suscripciones.
1. Abre la [Google Play Developer Console](https://play.google.com/console/u/0/developers).
2. Selecciona la app cuyo ID necesitas. Se abrirá la ventana **Dashboard**.
3. Busca el ID del producto bajo el nombre de la aplicación y cópialo.
4. Abre los [**App settings**](https://app.adapty.io/settings/android-sdk) desde el menú superior de Adapty.
5. En la pestaña **Android SDK** de la ventana **App settings**, pega el **Package name** copiado.
## Paso 2. Sube el archivo de clave de cuenta \{#step-2-upload-the-account-key-file\}
1. Sube el archivo de clave privada de cuenta de servicio en formato JSON que creaste en el paso [Crear archivo de clave de cuenta de servicio](create-service-account) en el área **Service account key file**.
No olvides hacer clic en el botón **Save** para confirmar los cambios.
**Próximos pasos**
- [Activar las notificaciones en tiempo real para desarrolladores (RTDN) en la Google Play Console](enable-real-time-developer-notifications-rtdn)
---
# File: enable-real-time-developer-notifications-rtdn
---
---
title: "Habilitar notificaciones en tiempo real para desarrolladores (RTDN) en Google Play Console"
description: "Mantente informado sobre eventos críticos y garantiza la exactitud de los datos habilitando las Notificaciones en Tiempo Real para Desarrolladores (RTDN) en Google Play Console para Adapty. Aprende a configurar RTDN para recibir actualizaciones instantáneas sobre reembolsos y otros eventos importantes de la Play Store"
---
Configurar las notificaciones en tiempo real para desarrolladores (RTDN) es fundamental para garantizar la exactitud de los datos, ya que te permite recibir actualizaciones al instante desde la Play Store, incluyendo información sobre reembolsos y otros eventos.
## Habilitar notificaciones \{#enable-notifications\}
1. Asegúrate de tener **Google Cloud Pub/Sub** habilitado. Abre [este enlace](https://console.cloud.google.com/flows/enableapi?apiid=pubsub) y selecciona el proyecto de tu app. Si todavía no has habilitado **Google Cloud Pub/Sub**, debes hacerlo aquí.
2. Ve a [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) desde el menú superior de Adapty y copia el contenido del campo **Enable Pub/Sub API** que aparece junto al título **Google Play RTDN topic name**.
:::note Si el contenido del campo **Enable Pub/Sub API** tiene un formato incorrecto (el formato correcto empieza por `projects/...`), consulta la sección [Corregir el formato incorrecto en el campo Enable Pub/Sub API](enable-real-time-developer-notifications-rtdn#fixing-incorrect-format-in-enable-pubsub-api-field) para obtener ayuda. ::: 3. Abre la [Google Play Console](https://play.google.com/console/), elige tu app y ve a **Monetize with Play** -> **Monetization setup**. En la sección **Google Play Billing**, marca la casilla **Enable real-time notifications**. 4. Pega el contenido del campo **Enable Pub/Sub API** que copiaste en los **App Settings** de Adapty en el campo **Topic name**. 5. Haz clic en **Save changes** en la Google Play Console.
## Probar las notificaciones \{#test-notifications\}
Para comprobar si te has suscrito correctamente a las notificaciones en tiempo real para desarrolladores:
1. Guarda los cambios en la configuración de Google Play Console.
2. Debajo del campo **Topic name** en Google Play Console, haz clic en **Send test notification**.
3. Ve a [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) en Adapty. Si se ha enviado una notificación de prueba, verás su estado encima del nombre del topic.
## Corregir el formato incorrecto en el campo Enable Pub/Sub API \{#fixing-incorrect-format-in-enable-pubsub-api-field\}
Si el contenido del campo **Enable Pub/Sub API** tiene un formato incorrecto (el formato correcto empieza por `projects/...`), sigue estos pasos para solucionar el problema:
### 1. Verificar la habilitación de la API y los permisos \{#1-verify-api-enablement-and-permissions\}
Comprueba detenidamente que todas las APIs necesarias estén habilitadas y que los permisos estén correctamente concedidos a la cuenta de servicio. Aunque ya hayas completado estos pasos, es importante revisarlos de nuevo para asegurarte de que no se omitió ninguno. Repite los pasos de las siguientes secciones:
1. [Habilitar las APIs de desarrollador en Google Play Console](enabling-of-devepoler-api)
2. [Crear una cuenta de servicio en Google Cloud Console](create-service-account)
3. [Conceder permisos a la cuenta de servicio en Google Play Console](grant-permissions-to-service-account)
4. [Generar el archivo de clave de la cuenta de servicio en Google Play Console](create-service-account-key-file)
5. [Configurar la integración con Google Play Store](google-play-store-connection-configuration)
### 2. Ajustar las políticas de dominio \{#2-adjust-domain-policies\}
Cambia las políticas **Domain restricted contacts** y **Domain restricted sharing**:
1. Abre la [Google Cloud Console](https://console.cloud.google.com/) y selecciona el proyecto donde creaste la cuenta de servicio para gestionar tu app.
2. En la sección **Quick Access**, elige **IAM & Admin**.
3. En el panel izquierdo, elige **Organization Policies**.
4. Busca la política **Domain restricted contacts**.
5. Haz clic en el botón de puntos suspensivos en la columna **Actions** y elige **Edit policy**.
6. En la ventana de edición de la política:
1. En **Policy source**, selecciona el botón de opción **Override parent's policy**.
2. En **Policy enforcement**, selecciona el botón de opción **Replace**.
3. En **Rules**, haz clic en el botón **ADD A RULE**.
4. En **New rule** -> **Policy values**, elige **Allow All**.
5. Haz clic en **SET POLICY**.
7. Repite los pasos 4-6 para la política **Domain restricted sharing**.
Por último, vuelve a generar el contenido del campo **Enable Pub/Sub API** situado junto al título **Google Play RTDN topic name**. El campo tendrá ahora el formato correcto.
Asegúrate de cambiar **Policy source** de vuelta a **Inherit parent's policy** para las políticas actualizadas una vez que hayas habilitado correctamente las Notificaciones en Tiempo Real para Desarrolladores (RTDN).
## Reenvío de eventos sin procesar \{#raw-events-forwarding\}
En algunos casos, puede que quieras seguir recibiendo eventos S2S sin procesar de Google. Para continuar recibiéndolos mientras usas Adapty, simplemente añade tu endpoint en el campo **URL for forwarding raw Google events** y enviaremos los eventos tal cual los recibimos de Google.
---
**Próximos pasos**
Configura el SDK de Adapty para:
- [Android](sdk-installation-android)
- [React Native](sdk-installation-reactnative)
- [Flutter](sdk-installation-flutter)
- [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)
- [Unity](sdk-installation-unity)
---
# File: stripe
---
---
title: "Integración inicial con Stripe"
description: "Integra Stripe con Adapty para procesar pagos de suscripciones sin problemas."
---
Adapty admite flujos de suscripción web2app mediante el seguimiento de pagos y suscripciones realizados a través de [Stripe](https://stripe.com/).
Esta integración cubre compras iniciadas desde la web (Stripe Checkout, páginas de pago alojadas o flujos web personalizados) y las sincroniza con el acceso a la app móvil y la analítica.
Es útil en los siguientes escenarios:
- Proporcionar acceso automático a funciones de pago para usuarios que compraron en la web pero luego instalaron la app e iniciaron sesión en su cuenta
- Tener toda la analítica de suscripciones en un único Adapty Dashboard (incluyendo cohortes, predicciones y el resto de herramientas de analítica)
Aunque las compras web son cada vez más populares para las apps, el App Store de Apple permite un sistema diferente al de las compras in-app para productos digitales únicamente en EE. UU. Asegúrate de no promocionar tus suscripciones web dentro de tu app para otros países. De lo contrario, tu app podría ser rechazada o vetada.
Los pasos a continuación describen cómo configurar la integración con Stripe.
:::important
Esta integración se centra en el seguimiento y sincronización de compras web de Stripe. Si necesitas enviar usuarios desde la app a un checkout web, consulta [Web paywalls](web-paywall).
:::
## 1\. Conecta Stripe a Adapty \{#1-connect-stripe-to-adapty\}
Esta integración se basa principalmente en que Adapty obtenga datos de suscripción de Stripe a través del webhook. Por lo tanto, necesitas conectar tu cuenta de Adapty a tu cuenta de Stripe proporcionando las claves API y usando la URL del webhook de Adapty en Stripe. Para automatizar la configuración del webhook, instala la app de Adapty en Stripe:
:::note
Los pasos a continuación son los mismos para los modos de Producción y Prueba de Stripe, pero necesitarás usar claves API diferentes para cada uno.
:::
0. Determina si vas a conectar Stripe en modo de prueba o en modo en vivo. Si lo haces inicialmente en modo de prueba, tendrás que repetir los pasos a continuación para el modo en vivo también.
1. Ve al [Stripe App Marketplace](https://marketplace.stripe.com/apps/adapty) e instala la app de Adapty. Ten en cuenta que el modo sandbox no admite la instalación de apps. Solo puedes hacerlo en modo de producción o de prueba.
2. Otorga los permisos necesarios a la app. Esto permitirá que Adapty acceda a los datos e historial de suscripciones. Luego, haz clic en **Continue to app settings** para continuar.
En la parte inferior del pop-up de permisos, puedes seleccionar si instalar la app en modo en vivo o de prueba.
3. En el pop-up, genera una nueva clave restringida. Tendrás que verificar tu identidad mediante tu correo electrónico, Touch ID o clave de seguridad. Una vez que generes una clave, no podrás volver a verla, así que guárdala de forma segura en un gestor de contraseñas o un almacén de secretos.
4. Copia la clave generada del pop-up y ve a [App Settings → Stripe](https://app.adapty.io/settings/stripe) en Adapty. Pega la clave en la sección **Stripe App Restricted API Key** según tu modo. Ten en cuenta que debes generar claves diferentes para los modos de prueba y en vivo.
¡Todo listo! A continuación, crea tus productos en Stripe y añádelos a Adapty.
2. Haz clic en el botón **Reveal live (test) key** junto al título **Secret key**, cópiala y ve a [App Settings → Stripe](https://app.adapty.io/settings/stripe) en Adapty. Pega la clave aquí:
3. A continuación, copia la URL del webhook que aparece en la parte inferior de la misma página en Adapty. Ve a [**Developers** → **Webhooks**](https://dashboard.stripe.com/webhooks) en Stripe y haz clic en el botón **Add endpoint**:
4. Pega la URL del webhook de Adapty en el campo **Endpoint URL**. Luego elige **Latest API version** en el campo **Version** del webhook. A continuación, selecciona los siguientes eventos:
- charge.refunded
- customer.subscription.created
- customer.subscription.deleted
- customer.subscription.paused
- customer.subscription.resumed
- customer.subscription.updated
- invoice.created
- invoice.updated
- payment_intent.succeeded
5. Pulsa "Add endpoint" y luego pulsa "Reveal" bajo "Signing secret". Esta es la clave que se usa para decodificar los datos del webhook en el lado de Adapty; cópiala después de revelarla:
6. Por último, pega esta clave en App Settings → Stripe de Adapty, bajo "Stripe Webhook Secret":
:::warning
Por el momento, Adapty solo admite precios de **Tarifa plana** ($9,99/mes) o **Precio por paquete** ($9,99/10 unidades), ya que se comportan de manera similar a las tiendas de apps. Las opciones **Precio escalonado**, **Tarifa basada en uso** y **El cliente elige el precio** no están disponibles.
:::
## 3\. Añade productos de Stripe a Adapty \{#3-add-stripe-products-to-adapty\}
:::warning
¡Los productos son obligatorios! Asegúrate de crear tus productos de Stripe en el Adapty Dashboard. Adapty solo realiza el seguimiento de eventos para transacciones vinculadas a estos productos, así que no omitas este paso; de lo contrario, no se crearán eventos de transacción.
:::
Tratamos Stripe igual que el App Store y Google Play: es simplemente otra store donde vendes tus productos digitales. Por eso se configura de forma similar: simplemente añade productos de Stripe (concretamente su `product_id` y `price_id`) a la sección de Productos de Adapty:
Los IDs de producto en Stripe tienen el formato `prod_...` y los IDs de precio tienen el formato `price_...`. Son fáciles de encontrar para cada producto en el [Catálogo de productos](https://dashboard.stripe.com/products?active=true) de Stripe, una vez que abres cualquier producto:
Una vez que hayas añadido todos los productos necesarios, el siguiente paso es informar a Stripe sobre qué usuario está realizando la compra, para que Adapty pueda identificarlo.
## 4\. Enriquece las compras web con tu ID de usuario \{#4-enrich-purchases-made-on-the-web-with-your-user-id\}
Adapty depende de los webhooks de Stripe para proporcionar y actualizar los niveles de acceso de los usuarios como única fuente de información. Pero debes proporcionar información adicional desde tu lado cuando trabajas con Stripe para que esta integración funcione correctamente.
Para que los niveles de acceso sean consistentes entre plataformas (web o móvil), debes asegurarte de que haya un único ID de usuario en el que confiar y que Adapty pueda reconocer a partir de los webhooks. Podría ser el correo electrónico del usuario, su número de teléfono o cualquier otro ID del sistema de autorización que estés utilizando.
Determina qué ID deseas usar para identificar a tus usuarios. Luego, accede a la parte de tu código que inicializa el pago a través de Stripe y añade este ID de usuario al objeto `metadata` de [Stripe Subscription](https://docs.stripe.com/api/subscriptions/object#subscription_object-metadata) (`sub_...`) o del objeto [Checkout Session](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-metadata) (`ses_...`) como `customer_user_id`, así:
```json showLineNumbers title="Stripe Metadata contents"
{'customer_user_id': "YOUR_USER_ID"}
```
Esta sencilla adición es lo único que tienes que hacer en tu código. Después de eso, Adapty analizará todos los webhooks que reciba de Stripe, extraerá estos `metadata` y asociará correctamente las suscripciones con tus clientes.
:::warning
El ID de usuario es obligatorio
De lo contrario, no tenemos forma de identificar a este usuario y proporcionarle el nivel de acceso en el móvil.
Si no proporcionas `customer_user_id` en los `metadata`, tendrás la opción de hacer que Adapty busque `customer_user_id` en otros lugares: bien en el `email` del objeto Customer de Stripe, bien en el `client_reference_id` de la Session de Stripe.
Obtén más información sobre cómo configurar el comportamiento de creación de perfiles [a continuación](stripe#profile-creation-behavior)
:::
:::note
El Customer de Stripe también es obligatorio
Si estás usando Checkout Sessions, [asegúrate de crear un Customer de Stripe](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-customer_creation) estableciendo `customer_creation` en `always`.
:::
## 5\. Proporciona acceso a los usuarios en el móvil \{#5-provide-access-to-users-on-the-mobile\}
Para asegurarte de que los usuarios móviles que llegan desde la web puedan acceder a las funciones de pago, simplemente llama a `Adapty.activate()` o `Adapty.identify()` con el mismo `customer_user_id` que proporcionaste en el paso anterior (consulta
2. Dale un nombre a la clave y establece la fecha de expiración. Para que la clave API funcione con Adapty, necesitas concederle el permiso **Read** para todas las entidades. Haz clic en **Save**.
3. Haz clic en **Copy key**.
4. En Adapty, ve a [App Settings → Paddle](https://app.adapty.io/settings/paddle) y pega la clave en la sección **Paddle API key**.
:::warning
Si estableciste una fecha de vencimiento para tu clave de API de Paddle, debes generar manualmente una nueva clave y actualizarla en Adapty antes de que expire. La integración dejará de funcionar sin previo aviso cuando la clave caduque, y los usuarios no podrán realizar compras.
:::
### 1.2. Añadir eventos que se enviarán a Adapty \{#add-events-that-will-be-sent-to-adapty\}
1. Copia la **Webhook URL** de la misma página de **Paddle** en Adapty.
2. En Paddle, ve a [**Developer Tools → Notifications**](https://vendors.paddle.com/notifications-v2) y haz clic en **New destination** para añadir un webhook.
3. Introduce un nombre descriptivo para el webhook. Te recomendamos incluir "Adapty" en él para que puedas encontrarlo fácilmente cuando lo necesites.
4. Pega la **Webhook URL** de Adapty en el campo **URL**. Asegúrate de usar el webhook para el entorno correcto.
5. Establece **Notification type** en **Webhook**.
6. Selecciona los siguientes eventos:
- `subscription.created`
- `subscription.updated`
- `transaction.created`
- `transaction.updated`
- `adjustment.created`
- `adjustment.updated`
7. Haz clic en **Save destination** para finalizar la configuración del webhook.
### 1.3. Obtener y añadir la clave secreta del webhook \{#retrieve-and-add-the-webhook-secret-key\}
1. En la ventana **Notifications**, haz clic en los tres puntos junto al webhook que acabas de crear y selecciona **Edit destination**.
2. Aparecerá un nuevo campo llamado **Secret key** en el panel **Edit destination**. Cópialo.
3. En Adapty, ve a [App Settings → Paddle](https://app.adapty.io/settings/paddle) y pega la clave en el campo **Notification secret key**. Esta clave se usa para verificar los datos del webhook en Adapty.
### 1.4. Vincula los clientes de Paddle con los perfiles de Adapty \{#14-match-paddle-customers-with-adapty-profiles\}
Adapty necesita vincular cada compra a un [perfil de cliente](profiles-crm) para que pueda usarse en tu app. De forma predeterminada, los perfiles se crean automáticamente cuando Adapty recibe webhooks de Paddle. Puedes elegir qué valor usar como `customer_user_id` en Adapty:
1. **Predeterminado y recomendado:** El `customer_user_id` que pasas en el campo `custom_data` (ver [documentación de Paddle](https://developer.paddle.com/build/transactions/custom-data))
2. El `email` del objeto Paddle Customer (ver [documentación de Paddle](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open/#parameters))
3. El ID de cliente de Paddle en formato `ctm-...` (ver [documentación de Paddle](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open/#parameters))
4. No crear perfiles. Elige esta opción si quieres tener mayor control sobre los perfiles de tus clientes y gestionarlos tú mismo.
Puedes configurar qué valor usar en el campo **Profile creation behavior** en [App Settings → Paddle](https://app.adapty.io/settings/paddle).
## 2. Añade productos de Paddle a Adapty \{#2-add-paddle-products-to-adapty\}
:::warning
Asegúrate de añadir tus productos de Paddle al Adapty Dashboard o de agregar un ID de producto de Paddle a tus productos existentes. Adapty solo registra eventos para transacciones vinculadas a estos productos. Si omites este paso, no se crearán eventos de transacción.
:::
Paddle funciona en Adapty igual que App Store y Google Play: es otra plataforma donde vendes productos digitales. Para configurarlo, añade los valores de `product_id` y `price_id` correspondientes de Paddle en la sección [Products](https://app.adapty.io/products) de Adapty.
En Paddle, los IDs de producto tienen el formato `pro_...` y los IDs de precio `pri_...`. Los encontrarás en tu [catálogo de productos de Paddle](https://vendors.paddle.com/products-v2) una vez que abras un producto específico:
Una vez añadidos tus productos, el siguiente paso es asegurarte de que Adapty pueda vincular la compra al usuario correcto.
## 3\. Dar acceso a los usuarios en el móvil \{#provide-access-to-users-on-the-mobile\}
Para asegurarte de que los usuarios que compran en la web obtengan acceso en el móvil, llama a `Adapty.activate()` o `Adapty.identify()` usando el mismo `customer_user_id` que pasaste al realizar la compra. Consulta [Identificar usuarios](identifying-users) para más detalles.
## 4\. Probar tu integración \{#test-your-integration\}
Una vez que todo esté configurado, puedes probar tu integración. Las transacciones realizadas en el entorno de Test de Paddle aparecerán como **Test** en Adapty. Las transacciones del entorno de Producción aparecerán como **Production**.
Tu integración ya está completa. Los usuarios pueden comprar suscripciones en tu sitio web y acceder automáticamente a las funciones premium en tu aplicación móvil, mientras tú haces seguimiento de todos los análisis de suscripciones desde tu Adapty Dashboard unificado.
## Consideraciones importantes \{#important-considerations\}
- En las analíticas de Adapty, los importes de las transacciones incluyen impuestos y comisiones de Paddle, lo que difiere del dashboard de Paddle, donde los importes se muestran después de impuestos y comisiones. Esto significa que las cifras que ves en Adapty serán más altas que las de tu dashboard de Paddle.
- A diferencia de otros stores, los reembolsos en Paddle solo afectan a la transacción específica que se reembolsa y no cancelan automáticamente la suscripción. La suscripción seguirá activa a menos que se cancele de forma explícita.
- También puedes incluir `variation_id` en el campo `custom_data` para atribuir compras a instancias de paywall específicas. Adapty procesará estos datos desde los webhooks y los incluirá en las analíticas.
### Períodos de prueba de pago \{#paid-trials\}
Al trabajar con períodos de prueba de pago en Paddle, necesitas crear dos productos en Adapty:
1. Crea un producto que no sea suscripción y vincúlalo al precio de Paddle que cobra por el período de prueba.
2. Luego crea un producto de suscripción (mensual, semanal, etc.) y vincúlalo al precio de Paddle que tiene el componente de prueba gratuita.
Desde el punto de vista de Paddle, se trata de un único producto con dos precios en una sola transacción: un precio para el cargo del período de prueba (p. ej., $0,99) y otro precio para la prueba gratuita ($0,00).
Desde la perspectiva de Adapty, esto genera dos eventos separados: una compra única por el pago de la prueba y un evento de inicio de prueba para el producto de suscripción.
Por ejemplo, cuando un usuario inicia una prueba de pago de $0,99 para una suscripción de $9,99/mes, Paddle crea una sola transacción con ambos precios, mientras que Adapty lo procesa como una compra única de $0,99 (pago inmediato) y un evento de inicio de prueba a $0,00 (suscripción futura a $9,99/mes).
:::note
Cuando los usuarios cancelan una prueba de pago, recibirás los eventos **Trial expired** y **Trial renewal canceled**.
:::
## Saca más partido a tus datos de Paddle \{#get-more-from-your-paddle-data\}
:::important
Para que tus eventos de Paddle funcionen con las integraciones, tus usuarios deben haber iniciado sesión en la app con su cuenta de App Store/Google Play al menos una vez.
:::
Una vez que te integres con Paddle, Adapty está listo para ofrecer información de inmediato. Para aprovechar al máximo tus datos de Paddle, puedes configurar integraciones adicionales de Adapty para reenviar eventos de Paddle, centralizando todos tus análisis de suscripciones en un único Adapty Dashboard.
Integraciones que puedes usar para reenviar y analizar tus eventos de Paddle:
- [AppsFlyer](appsflyer)
- [Webhook](webhook)
- [Posthog](posthog)
## Limitaciones actuales \{#current-limitations\}
- **Cancelaciones**: Paddle tiene dos opciones de cancelación de suscripción:
1. Cancelación inmediata: La suscripción se cancela de inmediato.
2. Cancelación al final del período: La suscripción se cancela al final del período de facturación actual (similar a las suscripciones in-app en los stores).
- **Reembolsos**: Adapty registra los reembolsos totales y parciales.
- **Período de gracia**: Por defecto, Paddle aplica un período de gracia fijo de 30 días para problemas de facturación, durante el cual la suscripción permanece activa. Puedes [personalizar la duración del período de gracia y la acción al final del mismo (pausar o cancelar la suscripción)](https://developer.paddle.com/build/retain/configure-payment-recovery-dunning#prerequisites).
**Pruebas**: Si el cobro falla al finalizar una prueba, el estado de la suscripción cambia a `past_due`. En producción, Paddle Retain aplica una ventana de gestión de impagos para intentar recuperar el pago antes de cancelar o pausar la suscripción. En sandbox, Retain no está disponible, por lo que no se realizan reintentos de pago y la suscripción permanece en `past_due` indefinidamente.
---
**Ver también:**
- [Validar una compra en Paddle, obtener un nivel de acceso e importar el historial de transacciones desde Paddle con la API del lado del servidor](api-adapty/operations/validatePaddlePurchase)
---
# File: custom-store
---
---
title: "Integración inicial con otras stores"
description: "Integración inicial de Adapty con App Store: Guía rápida"
---
¡Nos alegra mucho tenerte con nosotros en Adapty! Nuestra prioridad es ayudarte a ponerte en marcha cuanto antes y obtener los mejores resultados posibles para tu app.
La integración inicial solo es necesaria para [App Store](initial_ios), [Google Play](initial-android), [Stripe](stripe) y [Paddle](paddle), ya que Adapty verifica tus apps, productos y ofertas con estas stores.
Adapty no valida datos con otras app stores ni procesa las compras realizadas a través de ellas. Sin embargo, puedes marcar los productos vendidos en otras stores para que Adapty conceda acceso al contenido de pago tras una compra exitosa, refleje las transacciones en tus analíticas y las comparta mediante integraciones.
:::important Asegúrate de que tu backend procese la compra y envíe la transacción a Adapty mediante la [API server-side de Adapty](getting-started-with-server-side-api). Adapty solo concederá acceso, disparará un evento de transacción, lo enviará a las integraciones y lo reflejará en las analíticas una vez que se reciba la transacción. ::: Para marcar un producto como vendido a través de una app store personalizada, selecciona la app store al crear el producto. Si la store que necesitas no aparece en la lista, así es como puedes crearla: 1. En la página **Products**, abre el producto que quieres vender a través de una app store personalizada. 2. Elige la app store a través de la que quieres vender. Si no aparece en la lista, haz clic en el botón **Create Custom Store**.
3. Introduce el **Title** y el **Store ID** de la store.
4. Haz clic en el botón **Create store**.
Si tu backend está configurado correctamente, Adapty recibirá las transacciones de productos de esta store personalizada, las reflejará en las analíticas, en el [**Event Feed**](event-feed) y en las [integraciones](https://app.adapty.io/integrations), y concederá acceso según corresponda.
## Saca más partido a los datos de tu store personalizada \{#get-more-from-your-custom-store-data\}
:::important
Para que los eventos de tu store personalizada funcionen con las integraciones, tus usuarios deben haber iniciado sesión en la app con su cuenta de App Store/Google Play al menos una vez.
:::
Una vez que configures la integración con tu store personalizada, Adapty está listo para ofrecerte información de inmediato. Para aprovechar al máximo tus datos, puedes configurar integraciones adicionales de Adapty para reenviar los eventos de la store personalizada y reunir todas tus analíticas de suscripciones en un único Adapty Dashboard.
Integraciones que puedes usar para reenviar y analizar los eventos de tu store personalizada:
- [AppsFlyer](appsflyer)
- [Webhook](webhook)
- [Posthog](posthog)
---
# File: transfer-apps
---
---
title: "Transferir tu app a una cuenta diferente"
description: "Cambia el propietario de la app en Adapty"
---
Transfiere tu app a un propietario diferente cuando tu empresa sea adquirida, estés vendiendo tu app o reorganizando entidades empresariales. El proceso de transferencia implica coordinar cambios en Adapty, App Store Connect y Google Play Console para garantizar la continuidad del servicio.
## Transferir la propiedad de la app \{#transfer-app-ownership\}
Completa primero la transferencia en la store y luego transfiere la app en Adapty. Este orden garantiza que las compras sigan funcionando durante toda la transición.
:::note
No elimines ni vuelvas a crear productos durante el proceso de transferencia. No cambies los IDs de los productos hasta después de verificar que la transferencia se completó correctamente.
:::
### Transferencia en App Store (iOS) \{#app-store-ios-transfer\}
:::important
Las claves API de App Store Connect (Issuer ID, Key ID, archivo .p8) tienen alcance de cuenta, no de app. Tras la transferencia, debes generar nuevas claves API desde la cuenta del nuevo propietario y actualizarlas en Adapty.
El secreto compartido específico de la app sigue validando recibos durante el periodo de transferencia, pero el nuevo propietario también debe regenerarlo y actualizarlo en Adapty una vez completada la transferencia.
:::
1. **Nuevo propietario:** Crea una cuenta de Adapty en [app.adapty.io](https://app.adapty.io) si aún no tienes una.
2. **Propietario anterior:** Inicia la transferencia de la app en App Store Connect siguiendo la [guía de transferencia](https://developer.apple.com/help/app-store-connect/transfer-an-app/overview-of-app-transfer) de Apple.
3. **Nuevo propietario:** Acepta la transferencia en App Store Connect.
4. **Propietario anterior:** Envía un correo a [support@adapty.io](mailto:support@adapty.io) para transferir la app en Adapty. Incluye el nombre de la app y la dirección de correo electrónico del nuevo propietario.
5. **Nuevo propietario:** Tras recibir la app en Adapty, completa la [guía de integración con App Store](initial_ios) para generar y configurar todas las credenciales en tu cuenta.
### Transferencia de Google Play (Android) \{#google-play-android-transfer\}
1. **Nuevo propietario:** Crea una cuenta en Adapty en [app.adapty.io](https://app.adapty.io) si aún no tienes una.
2. **Ambos propietarios:** Asegúrate de que ambas cuentas de Google Play Developer estén completamente registradas.
3. **Propietario anterior:** Envía una solicitud de transferencia a través de Google Play Console o el soporte de Google Play Developer. Google puede solicitar documentación adicional, como números DUNS, contratos o justificantes de venta.
4. **Nuevo propietario:** Revisa y aprueba la solicitud de transferencia.
5. **Google:** El equipo de soporte de Google procesa la transferencia, normalmente en unos pocos días hábiles, aunque puede tardar más según la verificación de la cuenta, la complejidad de las suscripciones y la configuración de pagos.
6. **Propietario anterior:** Cuando Google complete la transferencia, envía un correo a [support@adapty.io](mailto:support@adapty.io) para transferir la app en Adapty. Indica el nombre de la app y la dirección de correo del nuevo propietario.
7. **Nuevo propietario:** Una vez recibida la app en Adapty, completa la [guía de integración de Google Play](initial-android) para generar y configurar todas las credenciales bajo tu cuenta.
La transferencia incluye usuarios, suscripciones, estadísticas, valoraciones y la ficha de la store. La continuidad de facturación se mantiene para los suscriptores existentes, pero los pagos pasan a la cuenta del nuevo propietario solo después de que se complete la transferencia. Los informes de pagos y pedidos anteriores a la transferencia permanecen en la cuenta original. Consulta la [guía de transferencia](https://support.google.com/googleplay/android-developer/answer/6230247) de Google para conocer los requisitos detallados.
## Mitigación de riesgos y tiempos \{#risk-mitigation-and-timing\}
**Qué sigue funcionando durante la transferencia:**
- Las compras y renovaciones (el shared secret específico de la app sigue validando los recibos durante el periodo de transferencia)
- El acceso de los suscriptores existentes
- El SDK sigue funcionando
**Qué deja de funcionar temporalmente:**
- Las llamadas a la API de App Store Connect (hasta que se configuren las nuevas claves)
- Las notificaciones del servidor (hasta que se reconfigure el endpoint)
- Es posible que los datos de análisis tengan lagunas durante la transición de credenciales
**Momento recomendado:**
- Completa las transferencias durante los períodos de poco tráfico (3:00–6:00 en la zona horaria principal de tus usuarios)
- Ten al nuevo propietario listo para configurar las credenciales justo después de aceptar la transferencia en el store
- Reserva entre 15 y 30 minutos entre la aceptación de la transferencia y la finalización de la integración con Adapty
**Tras completar la transferencia:**
- Prueba la validación de recibos de inmediato
- Supervisa las tasas de éxito de renovación automática durante 48 horas
- Verifica que las notificaciones del servidor están llegando a tus sistemas
- Comprueba que las nuevas compras se están registrando correctamente
## Verificar que la transferencia se completó correctamente \{#verify-transfer-completed-successfully\}
Tras completar tanto la transferencia en Adapty como en la store:
1. **Comprobar el acceso al Dashboard**: El nuevo propietario debe ver la app en su Adapty Dashboard.
2. **Verificar la conexión de la clave de API**: Comprueba que la nueva clave de API de App Store Connect o la cuenta de servicio de Google Play se conecta correctamente en Adapty.
3. **Probar la conexión del SDK**: Ejecuta tu app y verifica que el SDK de Adapty se inicializa sin errores.
---
# File: installation-of-adapty-sdks
---
---
title: "Instalación del SDK de Adapty"
description: "Instala los SDKs de Adapty para iOS, Android y apps multiplataforma."
---
Tienes tres formas de empezar según tus preferencias:
- **Sigue las guías de inicio rápido por plataforma**: Las guías incluyen fragmentos de código listos para producción, así que la implementación no lleva mucho tiempo.
- [iOS](ios-sdk-overview)
- [Android](android-sdk-overview)
- [React Native](react-native-sdk-overview)
- [Flutter](flutter-sdk-overview)
- [Unity](unity-sdk-overview)
- [Kotlin Multiplatform](kmp-sdk-overview)
- [Capacitor](capacitor-sdk-overview)
- **Usa LLMs**: Nuestra documentación es compatible con LLMs. Lee nuestra [guía](adapty-cursor) sobre cómo sacar el máximo partido a los LLMs con la documentación de Adapty.
- **Explora las apps de ejemplo**:
- [iOS (Swift)](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples)
- [Android (Kotlin)](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app)
- [React Native (Ejemplo básico en RN puro)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/BasicExample)
- [React Native (Ejemplo avanzado – útil para desarrollo, ya que permite trabajar con casos más complejos)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/AdaptyDevtools)
- [React Native (Build de desarrollo con Expo)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo)
- [React Native (Expo Go y Web)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock)
- [Flutter (Dart)](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example)
- [Unity (C#)](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets)
- [Kotlin Multiplatform](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example)
- [Capacitor](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples)
---
# File: sample-apps
---
---
title: "Apps de ejemplo"
description: ""
---
Para ayudarte a empezar con el SDK de Adapty, hemos preparado apps de ejemplo que muestran cómo integrar y usar sus funciones principales. Estas apps incluyen implementaciones listas para usar de paywalls, compras y seguimiento de analíticas.
## ¿Por qué usar las apps de ejemplo? \{#why-use-sample-apps\}
- **Integración rápida:** Descubre cómo funciona el SDK de Adapty en una app real.
- **Buenas prácticas:** Sigue los patrones de implementación recomendados.
- **Depuración y pruebas:** Usa las apps de ejemplo para resolver problemas y experimentar antes de integrar Adapty en tu propio proyecto.
## Apps de ejemplo disponibles \{#available-sample-apps\}
- [iOS (Swift)](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples)
- [Android (Kotlin)](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app)
- [React Native (Ejemplo básico en RN puro)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/BasicExample)
- [React Native (Ejemplo avanzado — útil para desarrollo, ya que permite trabajar con casos más complejos)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/AdaptyDevtools)
- [React Native (Expo dev build)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo)
- [React Native (Expo Go & Web)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock)
- [Flutter (Dart)](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example)
- [Unity (C#)](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets)
- [Kotlin Multiplatform](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example)
- [Capacitor (React)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-react-example)
- [Capacitor (Vue.js)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-vue-example)
- [Capacitor (Angular)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-angular-example)
- [Capacitor (Herramientas de desarrollo avanzadas)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/adapty-devtools)
---
# File: paywall-builder-templates
---
---
title: "Crear un flow"
description: "Comienza un nuevo flow a partir de una plantilla de galería personalizada o un inicio mínimo."
---
Puedes crear un flow a partir de una plantilla o desde cero.
:::link
¿Quieres aprender más sobre cómo crear flows? Mira tutoriales en vídeo paso a paso en nuestra [lista de reproducción de YouTube](https://www.youtube.com/playlist?list=PLMksWqaZiWtM).
:::
## Crear un flow \{#create-flow\}
1. Abre la página **Flows**.
2. Haz clic en **Create flow**.
3. Elige una opción:
- **Browse templates** (abre la biblioteca de plantillas)
- **Start from scratch** (crea un flow vacío)
4. Cambia el nombre del flow en el editor. Haz clic en el nombre del flow en la cabecera e introduce uno nuevo.
:::warning
Adapty permite nombres de flow duplicados. Renombra cada nuevo flow, o acabarás creando varios flows **Untitled** difíciles de distinguir.
:::
### Usar una plantilla
La biblioteca de plantillas contiene varias plantillas que sirven como punto de partida para tu flow. Cada una es un flow completo con múltiples pantallas, elementos interactivos y navegación funcional. Puedes editar cualquier elemento para personalizarlo.
Para aplicar una plantilla:
1. En la biblioteca de plantillas, navega por las tarjetas de plantillas. Cada tarjeta muestra capturas de pantalla previas de un flow.
2. Haz clic en **Use as template** en la tarjeta que quieras.
La plantilla se carga en el builder. Desde aquí puedes cambiar cualquier elemento, pantalla o propiedad.
### Comenzar desde cero \{#start-from-scratch\}
Comenzar desde cero crea un flow con una sola pantalla en blanco. Diseña la pantalla con elementos de la [biblioteca de elementos](builder-elements).
## Cambiar la plantilla \{#change-the-template\}
Puedes cambiar de plantilla desde el propio editor. Abre el panel Screens y haz clic en el botón **Templates** Templates para volver a abrir la biblioteca de plantillas y elegir una nueva.
:::warning
Aplicar una nueva plantilla reemplaza el borrador actual de tu flow. Adapty te pedirá que confirmes: haz clic en **Use template** para continuar, o en **Cancel** para conservar tu borrador. Una vez confirmado, el borrador anterior no se puede recuperar. El flow publicado sigue activo y no se ve afectado.
:::
## Fuentes personalizadas en plantillas \{#custom-fonts-in-templates\}
:::link
Artículo principal: [Fuentes personalizadas en el Flow Builder](using-custom-fonts-in-flow-builder)
:::
Las plantillas marcadas con el chip **Custom font** utilizan fuentes personalizadas. Estas fuentes no se incluyen con el SDK. Pasa el cursor sobre el chip para ver qué fuentes usa la plantilla.
Para ver la tipografía prevista en el dispositivo, añade los archivos de fuente al bundle de tu app. Las versiones anteriores de la app que no incluyan la fuente recurrirán a una fuente del sistema.
Para cambiar una fuente sin afectar versiones anteriores, duplica el flow, cambia la fuente en la copia y restringe esa copia a [usuarios con versiones de la app que incluyan la fuente](segments).
---
# File: builder-ui
---
---
title: "Interfaz del Flow Builder"
description: "Descripción general de la interfaz y el espacio de trabajo del Flow Builder."
---
La interfaz principal del Flow Builder incluye todas las herramientas necesarias para añadir elementos visuales, editar sus propiedades y modificar la lógica del flow. Este artículo cubre cada área de la interfaz: qué hace y dónde encontrarla.
:::link
¿Quieres aprender más sobre cómo crear flows? Mira tutoriales en vídeo paso a paso en nuestra [lista de reproducción de YouTube](https://www.youtube.com/playlist?list=PLMksWqaZiWtM).
:::
## Controles del proyecto y atajos útiles (barra de herramientas superior) \{#project-controls-and-useful-shortcuts-top-toolbar\}
* **Close** Close: Salir del editor de flow y volver a la página de flows.
* **App name** App: Identifica la app a la que pertenece el flow.
* **All flows** Flows: Abre la lista de todos los flows de esta app.
* **Flow status**: El icono a la izquierda del nombre del flow indica el [estado actual del flow](builder-save-publish#flow-status):
- **Draft** Draft
- **Publishing** (indicador giratorio)
- **Failed** Failed
- o **Live** Live.
* **Rename the flow**: Haz clic en el nombre del flow para cambiarlo. Varios flows pueden tener el mismo nombre: [dale a cada nuevo flow un nombre único](paywall-builder-templates#create-flow).
* **View mode toggle**: Cambia entre la vista de diseño Cursor y la [vista de Remote Config](customize-flow-with-remote-config)Remote Config.
* **Undo/Redo**: Haz clic en los iconos de flecha para deshacer Undo o rehacer Redo los cambios del flow. También puedes usar ⌘Z / Ctrl+Z para deshacer.
* **Save draft / Publish**: Haz clic en **Save draft** para guardar el progreso sin publicar (⌘ / Ctrl+S). Abre el desplegable Open dropdown para acceder al botón [**Publish**](builder-save-publish). Solo podrás añadir el flow a un [placement](create-placement) después de publicarlo.
## Área de vista previa (centro) \{#preview-area-center\}
El área central del espacio de trabajo simula cómo se verá tu flow en un dispositivo móvil.
* Para seleccionar un elemento y editar sus propiedades, haz clic en él. Para seleccionar un elemento hijo dentro de un contenedor, primero haz clic en el contenedor y luego en el elemento hijo.
* Para editar las propiedades de la pantalla en sí, haz clic fuera de cualquier elemento o selecciona la pantalla en el panel Screens and Layers.
* Para cambiar el orden de un elemento, arrastra su entrada hacia arriba o hacia abajo en el panel Screens and Layers.
:::warning
El editor de flows está diseñado para crear layouts adaptables. Por eso, **no puedes cambiar manualmente la posición de los elementos** — solo puedes cambiar su orden. La configuración de layout de cada contenedor determina cómo se distribuyen los elementos dentro de él.
:::
### Barra de pantalla activa (encima de la previsualización del dispositivo) \{#active-screen-bar-above-the-device-preview\}
- **Screen name** — una etiqueta con el nombre de la pantalla actual.
- **Toggle animations** Toggle animations — activa o desactiva las vistas previas de animaciones de los elementos; se reproducen de forma continua hasta que se desactivan. Solo aparece cuando la pantalla activa contiene al menos una [animación](builder-styling#animation). No afecta a la visibilidad de las animaciones en el dispositivo real.
- **Add element** Plus — abre la [biblioteca de elementos](builder-elements) en la pantalla actual. Es equivalente al **+** situado en la parte superior del panel Screens and Layers, y resulta útil cuando dicho panel está contraído.
### Controles de visualización (barra de herramientas inferior) \{#view-controls-bottom-toolbar\}
Las herramientas de la barra inferior te permiten controlar la vista previa.
* **Device**: Selecciona uno de los modelos de iPhone o Android disponibles para cambiar las dimensiones del viewport y el contorno del dispositivo.
* **Screen orientation**: Alterna entre los modos vertical Portrait y horizontal Landscape para previsualizar tu flow en distintas orientaciones.
* **Color scheme**: Cambia entre los modos claro Light mode y oscuro Dark mode para ver cómo se adapta tu diseño a cada tema.
* **Locale**: Selecciona un idioma para previsualizar tu flow con el contenido localizado.
* **View options**: Activa o desactiva el bisel del dispositivo y las guías de área segura.
## Propiedades de pantalla y elemento (panel derecho) \{#screen-and-element-properties-right-panel\}
### Ajustes y disposición de pantalla \{#screen-settings-and-layout\}
:::link
Artículo principal: [Pantallas y capas](paywall-layout-and-products)
:::
Cuando no hay ningún elemento seleccionado, el panel derecho te permite ajustar las propiedades de la pantalla del [flow](paywall-layout-and-products) activa, entre ellas:
* Interacciones con la interfaz del sistema (por ejemplo, si la barra de estado es visible)
* Reglas de disposición automática
* Fondo (color, imagen o vídeo)
* Tamaño del relleno (padding)
* Comportamiento de desplazamiento vertical
Si la pantalla contiene ciertos elementos, como [cuestionarios interactivos](onboarding-quizzes), esta lista se ampliará con las propiedades correspondientes.
### Propiedades del elemento \{#element-properties\}
Cuando seleccionas un elemento, el panel derecho te permite cambiar sus propiedades de estilo e interacción.
#### Propiedades de diseño \{#design-properties\}
:::link
Más información: [Diseño y posicionamiento](manage-paywall-ui-elements), [Estilos y apariencia](builder-styling)
:::
La pestaña **Design** te permite configurar la apariencia visual y el diseño del elemento seleccionado:
* **Visibility**: Muestra u oculta el elemento. Activa la visibilidad **Conditional** para establecer reglas que determinen cuándo debe ser visible el elemento.
* **Position**: Elige entre posicionamiento Relative, Absolute o Fixed.
* **Content** (solo elementos de texto): Edita el contenido de texto del elemento, inserta [variables](#variables) y gestiona las localizaciones.
* **Typography** (solo elementos de texto): Configura la fuente, el peso, el tamaño, el color, la alineación, la decoración y el truncamiento.
* **Spacing**: Establece el margen y el relleno del elemento.
* **Effects**: Añade sombras externas, sombras internas, desenfoque de fondo o desenfoque de capa.
* **Animation**: Añade efectos animados (p. ej., Pulse) y configura su temporización e intensidad.
* **Appearance**: Ajusta la opacidad y la rotación.
* **Layout**: Elige una dirección de diseño (vertical u horizontal) y determina cómo se distribuyen los elementos secundarios.
#### Propiedades de interacciones \{#interactions-properties\}
:::link
Más información: [Acciones](onboarding-actions), [Navegación e interacción](onboarding-navigation-branching)
:::
La pestaña **Interactions** te permite definir qué ocurre cuando el usuario interactúa con el elemento seleccionado. Cada interacción consta de un **trigger** y una o más **acciones**:
* **Los disparadores** definen *cuándo* ocurre algo — por ejemplo, **On Tap** (el usuario toca el elemento).
* **Las acciones** definen *qué* ocurre — por ejemplo, navegar a otra pantalla o cambiar el valor de una variable. Añade varias acciones a un mismo disparador para encadenarlas en secuencia.
Puedes añadir varios disparadores al mismo elemento para ejecutar varias acciones en orden.
## Panel izquierdo \{#left-panel\}
El panel izquierdo cambia su funcionalidad según el botón que esté activo. Puedes elegir entre:
* [Pantallas y capas](#screens-and-layers)
* [Añadir elemento](#element-selection)
* [Productos](#products)
* [Estilos](#saved-styles)
* [Variables](#variables)
* [Localización](#localization)
### Pantallas y Capas \{#screens-and-layers\}
:::link
Artículo principal: [Pantallas y Capas](paywall-layout-and-products)
:::
El botón de capas Layers abre Pantallas y Capas (que se muestra por defecto al abrir el flow builder).
Muestra cada pantalla como un árbol de capas. Cada elemento de una pantalla es una capa, y los contenedores tienen sus elementos hijos anidados dentro. Puedes arrastrar y soltar capas para reordenarlas.
### Selección de elementos \{#element-selection\}
:::link
Artículo principal: [Elementos](builder-elements)
:::
Si haces clic en el botón más Plus, el panel izquierdo muestra la lista de elementos de interfaz disponibles y sus variaciones. Haz clic en un elemento para añadirlo a la pantalla actual como una nueva capa.
### Productos
:::link
Artículo principal: [Productos](paywall-product-block)
:::
El botón de productos Products abre la lista de productos. Muestra qué productos están asignados a cada pantalla de tu flow.
Esta lista es de solo lectura. Para asignar productos a una pantalla, añade un elemento Producto y configúralo en el panel derecho. Para crear o editar productos, utiliza la página **Products** en el Adapty Dashboard.
### Estilos guardados \{#saved-styles\}
:::info
Más información:
- [Estilos y apariencia](builder-styling)
- [Contenido de texto](onboarding-text)
- [Modo oscuro](paywall-dark-mode)
:::
El botón de estilos Styles abre los Estilos guardados.
Aquí puedes editar y gestionar los estilos globales. Si varios elementos de tu flow usan la misma tipografía o color, guarda esos datos como estilo global. Después podrás reutilizarlos con un solo clic.
Actualmente, Flow Builder admite dos tipos de estilos globales: estilos de fuente y estilos de color. Cada estilo de color puede tener, opcionalmente, un valor distinto para el modo oscuro.
### Variables
:::link
Artículo principal: [Variables](onboarding-variables)
:::
El botón de corchetes Variables abre Variables.
Aquí puedes crear y gestionar variables para tu flow. En tiempo de ejecución, el SDK reemplaza los marcadores de posición de las variables con valores reales: atributos de usuario, precios de productos, cadenas localizadas y más.
Las variables se agrupan en dos pestañas:
* **Custom**: Variables que creas y controlas mediante acciones.
* **Elements**: Valores determinados por la interacción del usuario, como respuestas de quiz, estados de toggles o selección de pestañas.
Las variables de producto — precio, nombre y otros datos del producto — no aparecen en este panel. Referenciarlas directamente al editar un elemento de texto.
Usa las variables para:
* **Vincular texto**: Muestra contenido dinámico en lugar de cadenas estáticas.
* **Controlar la visibilidad**: Muestra u oculta elementos según condiciones (por ejemplo, ocultar un botón de actualización para usuarios premium).
* **Interactuar con el usuario**: Accede a los datos de los campos de entrada del usuario, como formularios o cuestionarios.
### Localización \{#localization\}
:::link
Artículo principal: [Localización](add-flow-remote-config-locale)
:::
La vista de Localización te permite gestionar todo el contenido traducible de tu flow. Muestra una tabla con cada cadena de texto e imagen, organizada por pantalla, con columnas para cada idioma. Desde esta vista puedes:
* Añadir nuevos idiomas y editar las cadenas localizadas directamente.
* Hacer seguimiento del estado de traducción — cada fila aparece marcada como **Done** o **Missing**.
* Filtrar por pantalla o mostrar solo las traducciones que faltan.
* Usar **AI Translate** para traducir el contenido automáticamente, o **Import/Export** para gestionar las traducciones de forma masiva.
---
# File: flow-builder-recipes
---
---
title: "Recetas comunes de flows"
description: "Guías paso a paso para construir las plantillas de pantalla más comunes en el Flow Builder."
---
Esta sección explica cómo construir las plantillas de pantalla más comunes en el Flow Builder — elemento por elemento, desde las opciones de diseño hasta las interacciones. Cada guía es independiente y utiliza los elementos estándar del Flow Builder.
3. Los botones de compra, los enlaces y los botones de cierre vienen con acciones preconfiguradas. Para los enlaces, [configura las URLs a las que se dirigirá a los usuarios](#links). Para los demás tipos de botón, ve al panel **Interactions**. Allí, en la sección **Button triggers**, configura las [acciones](onboarding-actions) que debe realizar el botón.
4. Configura el [diseño del botón](builder-styling) en el panel **Design**.
## Tipos de botones \{#button-types\}
### Botones de compra \{#purchase-buttons\}
:::link
Para que los botones de compra funcionen, vincula productos a las pantallas y añade el elemento **Products**. Consulta la [guía](paywall-product-block).
:::
Un botón de compra inicia la compra in-app del producto que el usuario haya seleccionado en la pantalla. El SDK procesa la transacción automáticamente, por lo que no necesitas gestionar las compras en el código de la app.
Para añadir un botón de compra:
1. Haz clic en **+** y selecciona **Button**, luego elige un preset de botón.
2. Con el botón seleccionado, abre la pestaña **Interactions** en el panel derecho.
3. Haz clic en **Add trigger** > **On tap**, luego haz clic en **Add action**.
4. Establece **Action** en **Purchase** y **Product** en `products.selectedProduct`. La variable `products.selectedProduct` siempre se resuelve al producto actualmente seleccionado en la pantalla.
:::tip
Puedes atraer más atención hacia los botones de compra animándolos. El Paywall Builder admite actualmente el tipo de animación **Pulse**.
Configura el estilo de animación en el panel **Design**.
:::
### Links \{#links\}
:::important
Los botones **Terms of Use** y **Privacy Policy** tienen una acción **Open URL** integrada. Establece la URL de destino allí. Las URLs vacías en Open URL y los [enlaces en línea](onboarding-text#inline-link) bloquean la vista previa y la publicación.
:::
Para cumplir con algunos requisitos del store, puedes añadir enlaces a:
- Términos de servicio
- Política de privacidad
- Restauración de compras
Para añadir enlaces:
1. Haz clic en **+** y selecciona **Button > Links**. Esto añadirá una fila de botones en línea con acciones predefinidas: restaurar compras o abrir una URL. Si no necesitas todos los botones incluidos, elimina los que no necesites en el panel de capas.
2. Ahora, configura las acciones de los botones:
- El botón **Restore purchases** ya gestiona la restauración de compras.
- Para cada enlace restante:
1. Haz clic en el botón para seleccionarlo y cambia a la pestaña **Interactions** en el panel derecho.
2. Pega la URL en el campo.
3. Por defecto, la URL se abre en un navegador integrado en la app para una experiencia de usuario fluida. Si quieres que los usuarios naveguen a un navegador externo, marca la casilla **Open in external browser**.
### Cerrar el flow \{#close-flow\}
El botón **Close** cierra el flow automáticamente.
Para añadir un botón de cierre, haz clic en **+** y selecciona **Button > Close flow**.
:::tip
Usa la posición **Absolute** para colocar el botón de cierre en la esquina de la pantalla.
:::
También puedes configurar cualquier otro botón para cerrar el flow usando [acciones](onboarding-actions).
### Botones personalizados \{#custom-buttons\}
Cualquier botón que añadas puede configurarse para realizar una acción al pulsarlo:
- Navegar a la siguiente pantalla
- Mostrar una alerta
- Establecer una [variable](onboarding-variables)
- [Mostrar u ocultar elementos de la pantalla](onboarding-element-visibility)
- Abrir URLs
- Restaurar compras
- Ejecutar acciones condicionales
---
# File: builder-tabs
---
---
title: "Tabs"
description: "Añade navegación por pestañas que intercambia paneles de contenido en un flow."
---
**Tabs** divide una sección de pantalla en paneles de contenido intercambiables: el usuario toca un encabezado de pestaña y el panel inferior se actualiza para coincidir.
{/* TODO: on-device GIF */}
## Añadir, eliminar y seleccionar pestañas \{#add-remove-and-select-tabs\}
Cada pestaña tiene dos partes:
- **Encabezado de pestaña** — la etiqueta en la que se hace clic (Tab 1, Tab 2, etc.).
- **Contenido de pestaña** — un contenedor por pestaña. Lo que pongas en un contenedor de contenido aparece cuando se selecciona esa pestaña.
Haz clic en **Add tab** para añadir una nueva pestaña. Cada nueva pestaña genera su propio contenedor de contenido.
Para que una pestaña concreta esté activa al cargar la pantalla, activa **Selected by default**.
## Dar estilo a las pestañas \{#style-the-tabs\}
### Plantillas \{#templates\}
El Flow Builder ofrece tres plantillas de pestañas listas para usar:
- **Segment control** — un selector con forma de píldora y esquinas redondeadas alrededor de la pestaña seleccionada.
- **Button Tabs** — pestañas con estilo de botón independientes.
- **Underline** — etiquetas de texto con un subrayado que marca la pestaña seleccionada.
### Estados de las pestañas \{#tab-states\}
Cada pestaña tiene un selector de estado (**Default / Selected**) para aplicar estilos distintos al estado activo e inactivo: tipografía, colores, relleno y borde por estado.
## Grupo seleccionable \{#selectable-group\}
Las pestañas son un **grupo seleccionable de elección única** — exactamente una pestaña está activa a la vez. Gestiona el grupo desde el panel **Screen settings**, en la sección [Selectable groups](paywall-layout-and-products#selectable-groups).
El grupo expone dos variables:
- `tabs.selectedOptionId` — el ID de la pestaña seleccionada. Úsalo en condiciones.
- `tabs.selectedOptionTitle` — la etiqueta de la pestaña seleccionada. Úsalo en texto dinámico.
Reemplaza `tabs` con tu **Group ID** personalizado si renombraste el grupo.
Consulta [Selectable elements and groups](flow-selectable-elements) para ver el panorama completo.
---
# File: builder-toggles
---
---
title: "Toggles"
description: "Añade interruptores de activación a tus flows de pago."
---
:::warning
Apple puede rechazar apps que usen un toggle de prueba preseleccionado. Un toggle configurado en "activado" por defecto puede marcarse como un patrón oscuro manipulador según las directrices de revisión de la App Store, ya que implica el consentimiento del usuario a una prueba gratuita sin una elección explícita.
Para evitar el rechazo, configura el toggle en **desactivado** por defecto y deja que los usuarios activen la prueba por su cuenta.
:::
Un trial toggle es un interruptor binario que permite a los usuarios elegir entre productos estándar y productos con periodo de prueba en un paywall. Cuando el usuario cambia su estado, puede desencadenar una acción de forma instantánea, como intercambiar grupos de productos, actualizar variables o mostrar y ocultar elementos.
Para añadir un trial toggle, haz clic en **+** en la pantalla de destino y selecciona **Trial toggle**.
Cada trial toggle es un elemento seleccionable de tipo **Toggle**. Cada elemento seleccionable tiene una variable asignada para reflejar su estado; por ejemplo, un toggle llamado `trial` obtiene una variable `trial.is_selected` con un valor `True` o `False`.
Para hacer que otros elementos dependan del estado del toggle, establece una [acción](onboarding-actions) condicional o una [visibilidad condicional](onboarding-element-visibility) basada en esta variable.
---
# File: builder-reviews-and-testimonials
---
---
title: "Reseñas y testimonios"
description: "Añade reseñas, valoraciones y prueba social a un paywall."
---
La categoría de elementos **User Engagement** ofrece cuatro plantillas para mostrar reseñas, valoraciones y prueba social en un paywall. Cada plantilla es una composición totalmente editable: reemplaza el texto de marcador de posición y aplica tus [estilos de color](builder-styling) y [tipografía](onboarding-text) para que encaje con el resto del flow.
## Reseña \{#review\}
Una tarjeta con una valoración, una cita y el nombre del autor. Úsala para destacar una cita memorable de un usuario.
## Valoración \{#rating\}
Una fila con recuento y estrellas, como "17000+ valoraciones". Úsala para destacar el volumen de valoraciones.
## Valoración de la app \{#app-rating\}
Una puntuación destacada con el tamaño de la muestra, como "4.9 / Basado en más de 1000 reseñas". Úsala para resaltar una puntuación global sólida.
## Prueba social \{#social-proof\}
Un grupo de avatares con un contador de miembros, como "Únete a más de 50.000 usuarios". Úsalo para destacar el tamaño de la comunidad.
---
# File: flow-timer
---
---
title: "Temporizador de cuenta regresiva"
description: "Añade un temporizador de cuenta regresiva a un paywall."
---
El **Temporizador de cuenta regresiva** cuenta hacia atrás desde una duración fija hasta cero — una vez que llega a cero, la pantalla se congela.
## Plantillas \{#templates\}
La categoría ofrece cuatro variantes visuales:
- **Blocks** — Días, horas, minutos y segundos en celdas separadas con etiquetas.
- **Inline Units** — Texto en una sola línea con sufijos de unidad.
- **Inline** — Solo dígitos.
- **Badge** — Visualización de dígitos en forma de píldora.
## Configuración \{#settings\}
### Establecer la duración \{#set-the-duration\}
En la sección **Countdown** del panel derecho, introduce la duración inicial en días, horas, minutos y segundos.
### Configurar el comportamiento \{#configure-the-behavior\}
El desplegable **Behavior** controla cuándo empieza el temporizador:
- **Every appear** — Se reinicia cada vez que el usuario abre la pantalla. Es el valor predeterminado.
- **First appear** — Arranca en la primera vez que el usuario ve la pantalla durante la sesión actual. Sigue contando si vuelve a ella en la misma sesión; se reinicia al abrir la app de nuevo.
- **First appear (persisted)** — Arranca la primera vez que el usuario abre la pantalla y sigue contando aunque cierre y vuelva a abrir la app.
### Desencadenar una acción cuando el temporizador termina \{#trigger-an-action-when-the-timer-ends\}
:::link
Artículo principal: [Acciones](onboarding-actions)
:::
Añade un disparador **On timer end** para ejecutar una acción cuando la cuenta atrás llega a cero — por ejemplo, navegar a otra pantalla u ocultar una insignia de descuento.
---
# File: onboarding-quizzes
---
---
title: "Cuestionarios en flows"
description: "Añade cuestionarios interactivos a tus flows de Adapty para recopilar preferencias de usuario y crear flows personalizados, sin código."
---
Usa los cuestionarios para presentar a los usuarios opciones predefinidas. A diferencia de los campos de entrada, los cuestionarios no tienen campos de texto libre: los usuarios eligen entre las opciones que tú defines. Úsalos para recopilar preferencias, segmentar usuarios o ramificar el flow según sus respuestas.
### Agregar un cuestionario \{#add-a-quiz\}
1. Haz clic en **+** en la parte superior izquierda.
2. Selecciona **Quiz**.
3. Elige el tipo de cuestionario:
- **Icon/image/emoji options:** Una lista vertical de opciones seleccionables, cada una con un icono, imagen o emoji junto a una etiqueta de texto.
- **Icon/image/emoji grid:** Una cuadrícula de opciones seleccionables, cada una con un icono, imagen o emoji.
- **Rating:** Una escala para que los usuarios expresen una valoración — numérica o basada en estrellas.
### Configurar la navegación condicional \{#set-up-conditional-navigation\}
Para redirigir a los usuarios de forma diferente según su selección, configura una acción condicional en el **botón de navegación**, no en la opción del quiz:
1. Selecciona el botón de navegación.
2. En el panel **Interactions**, añade un trigger **On Tap** con una acción **Conditional**.
3. En el diálogo **Edit Action**, configura la fila **if**:
- A la izquierda, haz clic en `{}` y selecciona **Elements → Screen → `
2. Haz clic en **Create product** en la esquina superior derecha. Adapty admite todo tipo de productos: suscripciones, no consumibles \(incluido el acceso de por vida\) y consumibles.
3. Selecciona **Create a new product and push to stores**.
4. Introduce los siguientes datos:
- **Product name**: introduce el nombre del producto que se usará en el Adapty Dashboard. El nombre es principalmente para tu referencia, así que elige el que te resulte más cómodo usar en el Adapty Dashboard.
- **Access Level**: selecciona el [nivel de acceso](access-level) al que pertenece el producto. El nivel de acceso determina las funcionalidades que se desbloquean tras comprar el producto. Ten en cuenta que esta lista solo contiene los niveles de acceso creados previamente. El nivel de acceso `premium` se crea en Adapty por defecto, pero también puedes [añadir más niveles de acceso](access-level).
- **Subscription duration**: selecciona la duración de la suscripción en la lista.
- **Weekly/Monthly/2 Months/3 Months/6 Months/Annual**: la duración de la suscripción.
- **Lifetime**: usa el período de por vida para los productos que desbloquean las funcionalidades premium de la app de forma permanente.
- **Non-Subscriptions**: para los productos que no son suscripciones y, por tanto, no tienen duración, usa non-subscriptions. Pueden utilizarse para desbloquear funcionalidades adicionales, productos consumibles, etc.
- **Consumables**: los artículos consumibles pueden comprarse varias veces y se consumen durante la vida de la aplicación. Algunos ejemplos son la moneda del juego y los extras. Ten en cuenta que los productos consumibles no afectan a los niveles de acceso. Para otorgar un nivel de acceso desde una compra única, usa **Non-Subscriptions** en su lugar.
- **Price (USD)**: el precio del producto en USD. Este precio se usará como base para calcular y establecer automáticamente los precios en todos los países. Podrás [personalizar el precio para distintos países y regiones](edit-product#set-country-specific-prices) más adelante.
5. Haz clic en **Save & Continue**.
6. Configura la información del producto para App Store si tienes previsto publicar allí:
- **Product ID**: Crea un ID único y permanente para el producto.
- **Product group**: Selecciona un grupo de productos existente que hayas creado en App Store Connect o haz clic en **Create new Product Group** e introduce su nombre. Una vez que Adapty lo cree, podrás seleccionarlo desde el desplegable.
- **Screenshot**: Sube una captura de pantalla de la compra in-app que muestre claramente el artículo o servicio ofrecido. Esta captura de pantalla se usa únicamente para la revisión de App Store y no se muestra en la App Store. Consulta los requisitos de tamaño y formato [aquí](https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications/).
7. Haz clic en **Push data to App Store**.
:::warning
Si es el primer producto de esta app, deberás enviarlo manualmente a revisión en App Store Connect. Esto no será necesario más adelante. Una vez finalizada la revisión, el estado del producto en Adapty se actualizará automáticamente.
:::
8. Configura la información del producto para Google Play si piensas publicarlo allí:
- **Base Product ID**: Crea un ID único y permanente para el producto.
- **Subscription**: Selecciona un grupo de suscripción existente que hayas creado en Google Play Console o haz clic en **Create new Product Group** y define su nombre e ID. Una vez que Adapty lo cree, podrás seleccionarlo desde el desplegable.
:::note
El período de gracia y el período de retención de cuenta se establecerán automáticamente con los valores predeterminados según las reglas de Play Store. Puedes cambiarlos más adelante en Google Play Console.
:::
9. Haz clic en **Push data to Play Store**.
10. Para iOS, configura la oferta introductoria – prueba gratuita – seleccionando su **Free duration** en el desplegable. Para esta configuración inicial, puedes añadir una prueba gratuita introductoria. Una vez que el store apruebe el producto principal, podrás [añadir más ofertas](offers) (p. ej., promocionales, de recuperación) vinculando sus IDs existentes desde la consola de tu store.
:::important
Las ofertas introductorias no se sincronizan automáticamente con Google Play. A diferencia del App Store, Google Play no tiene un tipo de "oferta introductoria" separado: tanto las pruebas gratuitas como las ofertas con descuento se configuran como **offers** en un plan base. [Crea la oferta en Google Play Console y vincúlala a tu producto de Adapty](google-play-offers).
:::
11. Por último, haz clic en **Save** para confirmar la creación del producto.
## Crear producto y conectar productos de store existentes \{#create-product-and-connect-existing-store-products\}
:::warning
Antes de empezar, asegúrate de haber:
- Configurado la integración con los stores que necesitas:
- [App Store](initial_ios)
- [Google Play](initial-android)
- Creado productos en los stores que necesitas:
- [App Store](app-store-products)
- [Google Play](android-products)
**Si no tienes ningún producto creado**, considera seguir la guía [Enviar a stores](#create-product-and-push-to-store) para crearlos en Adapty y en los stores al mismo tiempo.
:::
2. Haz clic en **Create product** en la esquina superior derecha. Adapty admite todo tipo de productos: suscripciones, no consumibles \(incluido acceso de por vida\) y consumibles.
3. Selecciona **Connect an existing store product**.
4. Introduce los siguientes datos:
- **Product name**: introduce el nombre del producto que se usará en el Adapty Dashboard. Este nombre es principalmente para tu referencia, así que elige el que te resulte más cómodo usar en el Adapty Dashboard.
- **Access Level ID**: Selecciona el [nivel de acceso](access-level) al que pertenece el producto. El nivel de acceso determina las funciones que se desbloquean tras comprar el producto. Ten en cuenta que esta lista solo contiene niveles de acceso creados previamente. El nivel de acceso `premium` se crea en Adapty por defecto, pero también puedes [añadir más niveles de acceso](access-level).
- **Duración de la suscripción**: selecciona la duración de la suscripción en la lista.
- **Semanal/Mensual/2 meses/3 meses/6 meses/Anual**: La duración de la suscripción.
- **Lifetime**: Usa el período de por vida para los productos que desbloquean las funciones premium de la app para siempre.
- **Non-Subscriptions**: Para los productos que no son suscripciones y, por tanto, no tienen duración, usa non-subscriptions. Pueden servir para desbloquear funciones adicionales, productos consumibles, etc.
- **Consumables**: Los artículos consumibles se pueden comprar varias veces. Se pueden agotar durante la vida útil de la aplicación. Algunos ejemplos son la moneda del juego y los extras. Ten en cuenta que los productos consumibles no afectan a los niveles de acceso. Para otorgar un nivel de acceso a partir de una compra única, usa **Non-Subscriptions** en su lugar.
- **Precio (USD)**: El precio del producto en USD. Si tu producto ya está en el store, este valor no afectará a su precio real en el store; puedes seleccionar cualquier valor de la lista. Más adelante, puedes [personalizar los precios para distintas regiones](edit-product#set-country-specific-prices) directamente en el Adapty Dashboard.
5. Haz clic en **Continue**.
6. Configura la información del producto en cada store:
- **App Store:**
- **App Store Product ID:** Este identificador único se usa para acceder a tu producto en los dispositivos. Selecciónalo de la lista. Si no aparece, revisa su configuración en App Store Connect y asegúrate de que sea correcto y pertenezca a esta app.
- **Play Store:**
- **Google Play Product ID:** Es el identificador del producto en la Play Store. Selecciónalo de la lista. Si no aparece, revisa su configuración en Google Play Console y asegúrate de que sea correcto y pertenezca a esta app.
- **Base Plan ID:** Este ID define el plan base del producto en la Play Store. Al añadir el Product ID de una suscripción en la Play Store, debes proporcionar un Base Plan ID. Un plan base define los detalles esenciales de una suscripción: el período de facturación, el tipo de renovación (automática o prepago) y el precio asociado. Ten en cuenta que, en Adapty, cada combinación de la misma suscripción con distintos planes base se trata como un producto independiente.
- **Legacy fallback product**: Un producto de respaldo que se usa exclusivamente para apps con versiones antiguas del SDK de Adapty (versiones 2.5 e inferiores). Al marcar un producto como compatible con versiones anteriores en Google Play Console, Adapty puede determinar si puede ser adquirido por versiones antiguas del SDK. Para este campo, especifica el valor con el siguiente formato: `
## Establecer precios por país \{#set-country-specific-prices\}
Puedes configurar precios diferentes para distintas regiones directamente en el Adapty Dashboard, y estos precios por país se aplicarán automáticamente a tus productos en App Store Connect y/o Google Play Console.
Para establecer precios por país:
1. [Abre el producto para editarlo](#edit-product).
2. Haz clic en **Download** para exportar tus precios actuales de las stores en el formato correcto, o crea un nuevo archivo CSV.
3. Actualiza los precios en el archivo CSV. Respeta el [formato](#csv-file-format). Si dejas el precio de algún país sin cambios o no lo incluyes en el archivo, no ocurrirá nada. Al subir el CSV, Adapty compara los precios y actualiza únicamente los que sean diferentes.
4. En la ventana **Edit**, haz clic en **Upload** y selecciona el archivo CSV.
5. Si quieres que los cambios también se apliquen a los suscriptores existentes, selecciona **Apply to existing subscribers**.
6. Revisa los cambios que se aplicarán y haz clic en **Save changes**.
### Formato del archivo CSV \{#csv-file-format\}
:::tip
Puedes reutilizar el mismo archivo CSV si tienes productos similares en una misma app o si quieres establecer los mismos precios en diferentes apps.
:::
La forma más sencilla de editar precios en CSV es [descargar un archivo con los precios actuales y editarlo directamente](#set-country-specific-prices).
Sin embargo, si lo creas tú mismo, el archivo debe contener las siguientes columnas:
- `region_name`
- `region_code`
- `app_store_currency`
- `app_store_requested_price`
- `play_store_currency`
- `play_store_requested_price`
Ejemplo:
```
region_name,region_code,app_store_currency,app_store_requested_price,play_store_currency,play_store_requested_price
United States,US,,8.99,,8.99
United Arab Emirates,AE,USD,8.99,AED,39.99
Germany,DE,USD,8.99,USD,8.99
```
## Ver el registro de auditoría \{#view-audit-log\}
Adapty registra todos los cambios de precio de cada producto, para que puedas hacer seguimiento de quién realizó los cambios y cuándo. Para ver el registro de auditoría:
1. Ve a **[Products](https://app.adapty.io/products)** desde el menú principal de Adapty.
2. Haz clic en los tres puntos junto al producto y selecciona **Audit log**.
La tabla del registro de auditoría muestra cada cambio de precio con la fecha, el nombre y rol del miembro del equipo, y el número de cambios.
Para descargar un desglose CSV detallado de un evento, haz clic en el icono de descarga de esa fila.
---
# File: delete-product
---
---
title: "Eliminar producto"
description: "Descubre cómo eliminar un producto de suscripción en Adapty sin interrumpir el flujo de ingresos de tu app."
---
Solo puedes eliminar productos que no estén en uso en ningún paywall.
Para eliminar el producto:
1. Ve a **[Products](https://app.adapty.io/products)** desde el menú principal de Adapty.
2. Haz clic en el botón de **3 puntos** junto al producto y selecciona **Delete**.
2. Introduce el nombre del producto que vas a eliminar.
3. Haz clic en **Delete forever**.
---
# File: add-product-to-paywall
---
---
title: "Añadir producto a un paywall"
description: "Aprende a añadir y gestionar productos en paywalls en Adapty."
---
Para que un producto sea visible y seleccionable dentro de un [paywall](paywalls) para los usuarios de tu app, sigue estos pasos:
1. Al [configurar un paywall](create-paywall), haz clic en **Add product** bajo el título **Products**.
2. En el menú desplegable que se abre, selecciona los productos que se mostrarán a tus clientes. La lista contiene únicamente los productos creados previamente. El orden de los productos se mantiene en el lado del SDK, por lo que es importante tener en cuenta el orden deseado al configurar el paywall. Además, puedes especificar una oferta para un producto si lo deseas.
3. Haz clic en **Create as draft** o **Save and publish** según el estado del paywall.
Ten en cuenta que, tras la creación, no se recomienda editar, añadir ni eliminar productos del paywall, ya que esto puede afectar a las métricas del paywall.
---
# File: virtual-currencies
---
---
title: "Monedas virtuales"
description: "Define monedas in-app en Adapty, vincúlalas a productos para conceder créditos automáticamente y lleva el saldo de cada usuario."
---
Para crear una oferta en Google Play Console:
1. Haz clic en **Add offer** y elige el plan base de la lista.
2. Introduce el ID de la oferta. Se usará más adelante en los análisis y en el Adapty Dashboard, así que dale un nombre descriptivo.
3. Elige los criterios de elegibilidad:
1. **New customer acquisition**: la oferta estará disponible solo para nuevos suscriptores que no la hayan utilizado antes. Es la opción más habitual y la que deberías usar por defecto.
2. **Upgrade**: esta oferta estará disponible para los clientes que actualicen desde otra suscripción. Úsala cuando quieras promocionar planes más caros a tus suscriptores actuales; por ejemplo, clientes que pasan del nivel bronce al nivel oro de tu suscripción.
3. **Developer determined**: puedes controlar quién puede usar esta oferta desde el código de la app. Úsala con precaución en producción para evitar posibles fraudes: los clientes podrían activar una suscripción gratuita o con descuento una y otra vez. Un buen caso de uso para este tipo de oferta es recuperar suscriptores que han cancelado.
4. Añade hasta dos fases de precio a tu oferta. Hay tres tipos de fase disponibles:
1. **Free trial**: la suscripción se puede usar gratis durante un período de tiempo configurado (mínimo 3 días). Es la oferta más habitual.
2. **Single payment**: la suscripción es más barata si los clientes pagan por adelantado. Por ejemplo, normalmente un plan mensual cuesta 9,99 $, pero con este tipo de oferta, los primeros tres meses cuestan 19,99 $, un descuento del 30%.
3. **Discounted recurring payment**: la suscripción es más barata durante los primeros `n` períodos. Por ejemplo, normalmente un plan mensual cuesta 9,99 $, pero con este tipo de oferta, cada uno de los primeros tres meses cuesta 4,99 $, un descuento del 50%.
Una oferta puede tener dos fases. En ese caso, la primera fase debe ser un Free trial y la segunda puede ser un Single payment o un Discounted recurring payment. Se aplicarán en ese orden.
:::important
Ten en cuenta que los paywalls creados con el Adapty Paywall Builder mostrarán únicamente la primera fase de una oferta de suscripción de Google con varias fases. No obstante, cuando un usuario compre el producto, todas las fases de la oferta se aplicarán tal como están configuradas en Google Play.
:::
5. Activa la oferta para usarla en la app.
6. Continúa con [cómo añadir la oferta a Adapty](create-offer).
:::note
Los IDs de oferta pueden ser iguales para distintos planes base.
:::
## Pasos siguientes \{#next-steps\}
Una vez añadidas las ofertas, continúa con la configuración:
- Si también tienes **apps en App Store**, consulta la [guía de App Store](app-store-offers).
- Si tienes **apps solo en Google Play**, sigue [esta guía](create-offer) para añadir ofertas a Adapty.
---
# File: create-offer
---
---
title: "Añadir ofertas a Adapty"
description: "Crea y gestiona ofertas especiales de suscripción con las herramientas de Adapty."
---
Adapty te permite ofrecer trials o descuentos a suscriptores nuevos, actuales o que han abandonado.
Una vez que los hayas configurado en App Store Connect o Google Play Console, necesitas añadirlos a Adapty en dos pasos:
1. [Añade las ofertas a los productos en Adapty usando los IDs de oferta de los stores.](#1-create-offer)
2. [Muestra la oferta en un flow o paywall.](#2-display-offer)
:::warning
Las ofertas introductorias (App Store) se aplican automáticamente si el usuario es elegible. No las añadas a los productos en Adapty.
Esta guía explica cómo configurar ofertas promocionales (App Store), ofertas de recuperación (App Store) y todas las ofertas de Google Play.
:::
## 0. Antes de empezar \{#before-you-start\}
Antes de configurar ofertas en Adapty, asegúrate de lo siguiente:
1. Has creado todas las ofertas que necesitas en el store:
- [App Store](app-store-offers)
- [Google Play](google-play-offers)
2. Has creado los [productos](create-product) en Adapty y has añadido sus IDs.
3. Para App Store: has subido [la clave de compra in-app para ofertas promocionales](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers).
## 1. Añade la oferta al producto en Adapty \{#1-add-offer-to-product-in-adapty\}
Una vez que hayas configurado tu oferta promocional (tanto para Play Store como para App Store) u oferta de recuperación (para App Store) en los stores, añadirla a Adapty es sencillo:
1. Abre [**Products**](https://app.adapty.io/products) desde el menú principal de Adapty. Localiza el producto al que quieres añadir una oferta.
2. Encuentra el producto al que quieres añadir una oferta. En la columna **Actions**, haz clic en el botón de **3 puntos** junto al producto y selecciona **Edit**.
3. En la ventana **Edit product**, haz clic en **+** y selecciona **Add offers**.
4. Haz clic en **Add offer**.
5. A continuación, introduce los detalles de la oferta para el producto.
Estos son los campos de la oferta:
- **Offer name**: Asigna un nombre a la oferta para identificarla fácilmente en Adapty. Usa el nombre que más te convenga.
- **App Store Offer type**: Selecciona el tipo de oferta de App Store que estás añadiendo: Promotional o Win-back. (Las ofertas introductorias no es necesario añadirlas, ya que se aplican automáticamente si están disponibles.)
- **App Store Offer ID**: Es el ID único de la oferta [que configuraste en App Store](app-store-products).
- **Play Store Offer ID**: De igual forma, es el ID único de la oferta [que configuraste en Play Store](android-products).
:::tip
Si el campo **App Store Offer ID** o **Play Store Offer ID** no está activo, cambia a la pestaña **Products** y selecciona un ID de producto.
:::
6. (opcional) Añade más ofertas si es necesario haciendo clic en **Add offer**.
7. Haz clic en **Save** para añadir las ofertas al producto.
## 2. Mostrar la oferta \{#2-display-offer\}
Una vez que la oferta está vinculada a un producto, muéstrala donde los usuarios ven ese producto: en un flow o en un paywall.
### Añadir una oferta a un flow \{#add-offer-to-flow\}
En el [Flow Builder](adapty-flow-builder), una oferta se asocia a un producto dentro del elemento Products. Primero añade el elemento de productos y asígnales productos — consulta [Configurar compras](paywall-product-block).
Para asociar una oferta:
1. En el canvas, selecciona la tarjeta de producto que debe mostrar la oferta.
2. En el panel derecho, en **Product**, selecciona el producto y luego elige la oferta en el desplegable **Select offer (optional)**.
### Añadir una oferta a un paywall \{#add-offer-to-paywall\}
:::info
No puedes añadir ofertas a paywalls en estado **live**. Si quieres añadir una oferta a un paywall existente, [duplícalo](duplicate-paywalls) y configura los productos en el nuevo paywall.
:::
Para que una oferta sea visible y seleccionable dentro de un [paywall](paywalls) para los usuarios de tu app, sigue estos pasos:
1. Al crear o editar un paywall, en la pestaña **General**, añade el producto al que acabas de añadir la oferta.
2. Elige la oferta que creaste anteriormente para este producto en la lista **Offer**. La lista solo está disponible para los productos que tienen ofertas.
3. Si lo necesitas, añade más productos y ofertas, pero solo puedes añadir una oferta por producto.
## Cómo funciona Adapty con las ofertas \{#how-adapty-works-with-offers\}
Ten en cuenta lo siguiente sobre cómo funcionan las ofertas en Adapty:
- Cuando un usuario es elegible para una oferta, Adapty aplica automáticamente la oferta que hayas configurado cuando el usuario realiza una compra.
- Si un producto tiene configurada tanto una oferta introductoria como ofertas promocionales en el App Store, los usuarios elegibles recibirán primero la oferta introductoria. Una vez finalizado su período, si el usuario todavía es elegible para la oferta promocional y la has configurado en Adapty, se aplicará cuando intente comprar el producto de nuevo.
- Si quieres tener más control sobre cómo se aplican las ofertas o necesitas vender tu producto sin ofertas en determinados casos, tienes varias opciones:
- Configura los criterios de elegibilidad en el App Store o en Google Play Console
- Crea un producto separado sin ofertas en el App Store o en Google Play Console
- Crea un producto separado sin ofertas en Adapty, añade paywalls que contengan ambas variantes del producto a un [placement](placements) y usa [segmentos](segments) de audiencia para controlar qué paywall se muestra a cada usuario. Por ejemplo, puedes crear segmentos basados en el **Subscription product** o en el **Paid access level**, o usar [atributos personalizados](profiles-crm) para implementar tu propia lógica.
---
# File: create-access-level
---
---
title: "Crear nivel de acceso"
description: "Crea y asigna niveles de acceso en Adapty para una mejor segmentación de usuarios."
---
Los niveles de acceso te permiten controlar lo que los usuarios de tu app pueden hacer sin necesidad de codificar IDs de productos específicos. Cada producto define cuánto tiempo obtiene el usuario un determinado nivel de acceso. Así, cuando un usuario realiza una compra, Adapty concede acceso a la app durante un período específico (para suscripciones) o de forma permanente (para compras de por vida).
Cuando creas una app en el Adapty Dashboard, el nivel de acceso `premium` se genera automáticamente. Este es el nivel de acceso predeterminado y no se puede eliminar.
:::tip
También puedes crear niveles de acceso de forma programática usando el [Developer CLI](developer-cli-reference#adapty-access-levels-create).
:::
Para crear un nuevo nivel de acceso:
1. Ve a **[Products](https://app.adapty.io/access-levels)** desde el menú principal de Adapty y selecciona la pestaña **Access levels**.
2. Haz clic en **Create access level**.
3. En la ventana **Create access level**, asígnale un ID. Este ID servirá como identificador dentro de tu app, permitiendo el acceso a funciones adicionales cuando el usuario realice una compra. Además, este identificador ayuda a distinguir un nivel de acceso de otros dentro de la app. Asegúrate de que sea claro y fácil de entender para tu comodidad.
4. Haz clic en **Create access level** para confirmar la creación del nivel de acceso.
---
# File: assigning-access-level-to-a-product
---
---
title: "Asignar nivel de acceso a un producto"
description: "Asigna niveles de acceso a los productos para optimizar la gestión de suscripciones."
---
Cada [producto](product) necesita un nivel de acceso asociado para garantizar que los usuarios reciban el contenido restringido correspondiente tras la compra. Adapty determina automáticamente la duración de la suscripción, que sirve como fecha de expiración del nivel de acceso. En el caso de un producto de acceso de por vida, si un usuario lo compra, el nivel de acceso permanece activo indefinidamente sin fecha de expiración.
Para vincular un nivel de acceso a un producto:
1. Al [configurar un producto](create-product), selecciona el nivel de acceso en la lista **Access Level ID**.
2. Haz clic en **Save**.
---
# File: give-access-level-to-specific-customer
---
---
title: "Asignar nivel de acceso a un cliente específico"
description: "Asigna niveles de acceso específicos a clientes usando las herramientas avanzadas de Adapty."
---
Puedes ajustar manualmente el nivel de acceso de un cliente concreto directamente desde el Adapty Dashboard. Esto resulta muy útil en escenarios de soporte. Por ejemplo, si quieres ampliar el uso premium de un usuario una semana extra como agradecimiento por haber dejado una reseña estupenda.
## Asignar nivel de acceso a un cliente específico en el Adapty Dashboard \{#give-access-level-to-a-specific-customer-in-the-adapty-dashboard\}
1. Ve a **[Profiles and Segments](https://app.adapty.io/placements)** desde el menú principal de Adapty.
2. Haz clic en el cliente al que quieres conceder acceso.
3. Haz clic en **Add access level**.
4. Selecciona el nivel de acceso que quieres conceder y cuándo debe expirar para ese cliente.
5. Haz clic en **Apply**.
## Asignar nivel de acceso a un cliente específico mediante la API \{#give-access-level-to-a-specific-customer-via-api\}
También puedes conceder un nivel de acceso a un cliente desde tu servidor usando la API de Adapty. Esto es muy útil si tienes bonificaciones por referidos u otros eventos relacionados con tus productos. Consulta más detalles en la página [Conceder nivel de acceso con la API del servidor](api-adapty/operations/grantAccessLevel).
---
# File: local-access-levels
---
---
title: "Niveles de acceso locales"
description: "Gestiona los niveles de acceso en caso de interrupciones temporales."
---
:::important
Ten en cuenta lo siguiente:
- Los niveles de acceso locales son compatibles con el SDK de Adapty a partir de la versión 3.12.
- Por defecto, los niveles de acceso locales están desactivados en Android por seguridad adicional. Si los necesitas, actívalos durante la inicialización del SDK: [Android](sdk-installation-android#enable-local-access-levels), [React Native](sdk-installation-reactnative), [Flutter](sdk-installation-flutter#enable-local-access-levels-android).
:::
Cada producto que configuras tiene un [**nivel de acceso**](access-level) asociado. Cuando tus usuarios realizan una compra, el SDK de Adapty asigna el nivel de acceso al [perfil](profiles-crm) del usuario, por lo que debes usar este nivel de acceso para determinar si los usuarios pueden acceder al contenido de pago en la app.
El SDK de Adapty es muy fiable y es muy raro que sus servidores no estén disponibles. Sin embargo, incluso en ese caso excepcional, tus usuarios no lo notarán.
Si un usuario realiza una compra pero Adapty no puede recibir respuesta, el SDK pasa a verificar las compras directamente en el store. Por tanto, el nivel de acceso se concede de forma local en la app y no se necesita ninguna configuración adicional para activarlo. El SDK lo gestiona automáticamente en segundo plano, y los usuarios accederán a lo que han pagado con total normalidad.
Ten en cuenta lo siguiente sobre cómo funcionan los niveles de acceso locales:
- Cuando los usuarios vuelven a estar en línea, la información de las transacciones se envía automáticamente a los servidores de Adapty, que aplican las transacciones al perfil del usuario y devuelven el perfil actualizado al SDK.
- Los datos actualizados no aparecerán en los análisis de Adapty hasta que se envíen los datos.
- Los niveles de acceso locales solo funcionan cuando los servidores de Adapty están caídos. En caso contrario, el SDK utilizará los datos en caché.
- Los niveles de acceso locales no funcionan con productos consumibles, excepto cuando un producto consumible tiene asignado un tipo de suscripción (mensual, anual, semanal, etc.) en el dashboard de Adapty.
---
# File: choose-meaningful-placements
---
---
title: "Elige placements significativos"
description: "Optimiza los placements de flows y paywalls con Adapty para aumentar la interacción con los usuarios y los ingresos."
---
Cuando [creas placements](create-placement), es fundamental tener en cuenta el flujo lógico de tu app y la experiencia de usuario que quieres ofrecer. La mayoría de las apps no necesitan más de 5 [placements](placements) para poder ejecutar experimentos sin restricciones. Aquí tienes un ejemplo de cómo puedes estructurar tus placements:
1. **Flow de onboarding:** Esta etapa representa la primera interacción de tus usuarios con tu app. Es una oportunidad excelente para presentarles la propuesta de valor combinando placements de flow, onboarding y paywall. Más del 80% de las suscripciones se activan durante el proceso de onboarding, por lo que es importante centrarse en vender las suscripciones más rentables aquí. Con Adapty, puedes tener fácilmente diferentes [flows](adapty-flow-builder), [onboardings](onboardings) y [paywalls](paywalls) para distintas audiencias, y ejecutar pruebas A/B para encontrar la mejor opción para tu app. Por ejemplo, puedes ejecutar una prueba A/B para usuarios de EE. UU., mostrando suscripciones más caras el 50% del tiempo.
2. **Configuración de la app:** Si el usuario no se ha suscrito durante el proceso de onboarding, puedes crear un placement de flow o paywall dentro de tu app. Puede estar en la configuración de la app o tras completar una acción objetivo específica. Como los usuarios dentro de la app tienden a pensárselo más antes de suscribirse, los productos aquí pueden ser algo menos costosos que los de la etapa de onboarding.
3. **Promo:** Si el usuario no se ha suscrito después de ver el flow o el paywall varias veces, puede indicar que los precios son demasiado altos para él o que tiene dudas sobre las suscripciones. En ese caso, puedes mostrarle una oferta especial con la suscripción más asequible o incluso un producto de acceso de por vida. Esto puede ayudar a convencer a los usuarios sensibles al precio o escépticos ante las suscripciones para que realicen una compra.
La mayoría de las apps siguen una lógica y unos placements similares, que acompañan el recorrido del usuario y los puntos clave donde se pueden mostrar flows, paywalls, onboardings o pruebas A/B para impulsar conversiones e ingresos. Puedes configurarlos en cada placement para experimentar y optimizar tus estrategias de monetización.
---
# File: create-placement
---
---
title: "Crear un placement"
description: "Crea y gestiona placements en Adapty para mejorar el rendimiento de flows y paywalls."
---
Un [Placement](placements) es una ubicación específica dentro de tu app móvil donde puedes mostrar un flow, un paywall, un onboarding o una prueba A/B. Por ejemplo, una pantalla de elección de suscripción puede aparecer en el flow de inicio, mientras que un producto consumible (como monedas de oro) podría mostrarse cuando al usuario se le acaben las monedas en un juego.
Puedes mostrar los mismos o diferentes flows, paywalls, onboardings o pruebas A/B en distintos placements o para diferentes segmentos de usuarios, que en Adapty se denominan "audiencias".
Consulta la sección [Elige placements con sentido](choose-meaningful-placements) para ver consejos sobre cómo elegir el placement adecuado.
:::tip
También puedes crear placements mediante programación usando la [CLI para desarrolladores](developer-cli-reference#adapty-placements-create).
:::
:::info
Aunque el proceso de creación de placements es similar para flows, paywalls y onboardings, no puedes crear un mismo placement que sirva para más de un tipo: cada tipo de placement procesa métricas diferentes.
:::
## Crear y configurar un placement \{#create-and-configure-a-placement\}
1. Ve a **[Placements](https://app.adapty.io/placements)** desde el menú principal de Adapty. Cambia a la pestaña **Flows**, **Paywalls** o **Onboardings** según el tipo de placement que quieras crear.
2. Haz clic en **Create placement**.
3. Escribe un **Placement name**. Es un identificador interno en el Adapty Dashboard. Puedes editarlo más adelante si lo necesitas.
4. Escribe un **Placement ID**. Usarás este ID en el SDK de Adapty para llamar a los [flows](adapty-flow-builder), [paywalls](paywalls), [onboardings](onboardings) y [pruebas A/B](ab-tests) del placement. No puedes editarlo después, ya que es único para cada placement.
A continuación, asigna un flow, paywall, onboarding o prueba A/B al placement. Adapty admite [audiencias](audience) — segmentos de usuarios basados en [segmentos](segments) — para que puedas mostrar contenido diferente a grupos de usuarios distintos. Si no necesitas segmentación, la audiencia predeterminada *All users* cubre a todos.
:::note
Para continuar, asegúrate de haber creado un flow, paywall, onboarding o prueba A/B que quieras ejecutar, así como una audiencia que quieras especificar.
:::
1. En la ventana **Placements/ Your placement**, añade un flow, paywall, onboarding o prueba A/B para mostrar a la audiencia predeterminada *All users*. Para ello, haz clic en el botón **Run flow**, **Run paywall** o **Run A/B test** (la etiqueta depende del tipo de placement) y selecciona el flow, paywall, onboarding o prueba A/B deseado en la lista desplegable.
2. Si quieres usar más de una audiencia en el placement para crear contenido personalizado adaptado a distintos grupos de usuarios, haz clic en el botón **Add audience** y elige el segmento de usuarios deseado de la lista.
El archivo CSV exportado contiene la siguiente información sobre tus placements:
- ID de placement
- Nombre del placement
- Nombre de audiencia
- Nombre de segmento
- Nombre de prueba A/B entre placements
- Nombre de prueba A/B
- Nombre de flow, nombre de paywall o nombre de onboarding (según la pestaña desde la que hayas exportado)
:::note
Las pruebas A/B entre placements no son compatibles con los placements de flow, por lo que esa columna estará vacía en las exportaciones de flows.
:::
---
# File: delete-placement
---
---
title: "Eliminar un placement"
description: "Descubre cómo eliminar un placement en Adapty sin afectar el rendimiento de tu flow o paywall."
---
Un [placement](placements) designa una ubicación específica dentro de tu app móvil donde se puede mostrar un flow, paywall, onboarding o prueba A/B.
:::danger
Aunque tienes la opción de eliminar cualquier placement, es fundamental asegurarte de no eliminar un placement que esté en uso activo en tu app. Eliminar un placement de flow o paywall activo hará que se muestre permanentemente el paywall de respaldo local si lo has [configurado](fallback-paywalls), y no podrás reemplazarlo nunca con un flow o paywall dinámico en las versiones de la app ya publicadas.
:::
Para eliminar un placement existente:
1. Ve a **[Placements](https://app.adapty.io/placements)** desde el menú principal de Adapty. Cambia a la pestaña **Flows**, **Paywalls** u **Onboardings** según el tipo de placement que quieras eliminar.
2. Haz clic en el botón de **3 puntos** junto al placement y selecciona la opción **Delete**.
3. En la ventana **Delete placement** que se abre, escribe el nombre del placement que vas a eliminar.
4. Haz clic en el botón **Delete forever** para confirmar la eliminación.
---
# File: add-audience-paywall-ab-test
---
---
title: "Añadir audiencia y flow, paywall o prueba A/B a un placement"
description: "Ejecuta pruebas A/B en flows y paywalls para diferentes segmentos de audiencia en Adapty."
---
:::note
Para continuar, asegúrate de haber creado un flow, paywall, onboarding o prueba A/B que quieras ejecutar, así como una audiencia que quieras especificar.
:::
1. En la ventana **Placements/ Your placement**, añade un flow, paywall, onboarding o prueba A/B para mostrar a la audiencia predeterminada *All users*. Para ello, haz clic en el botón **Run flow**, **Run paywall** o **Run A/B test** (la etiqueta depende del tipo de placement) y selecciona el flow, paywall, onboarding o prueba A/B deseado en la lista desplegable.
2. Si quieres usar más de una audiencia en el placement para crear contenido personalizado adaptado a distintos grupos de usuarios, haz clic en el botón **Add audience** y elige el segmento de usuarios deseado de la lista.
En este caso, nos basamos en la prioridad de audiencia. La prioridad de audiencia es un orden numérico donde el n.º 1 es la más alta. Determina la secuencia en la que se comprueban las audiencias. En términos más sencillos, la prioridad de audiencia ayuda a Adapty a decidir qué audiencia aplicar primero al seleccionar el paywall, onboarding o prueba A/B que se mostrará. Si la prioridad de una audiencia es baja, los usuarios que potencialmente encajan pueden quedar excluidos y ser derivados a otra audiencia con mayor prioridad.
Las audiencias multiplacement, es decir, las creadas para [pruebas A/B multiplacement](ab-tests#ab-test-types), siempre tienen prioridad sobre las audiencias normales.
La audiencia "Todos los usuarios" siempre tiene la prioridad más baja, ya que es un fallback e incluye a todos los que no coinciden con ninguna otra audiencia.
Para ajustar las prioridades de audiencia en un placement:
1. Al crear un nuevo placement o editar uno existente, haz clic en **Edit priority**. El botón solo es visible si se han añadido al menos tres audiencias al placement ("Todos los usuarios" y otras dos). Si hay menos, el orden es obvio: la audiencia "Todos los usuarios" va siempre al final.
2. En la ventana **Edit audience priorities** que se abre, arrastra y suelta las audiencias para reordenarlas correctamente.
3. Haz clic en el botón **Save**.
---
# File: placement-metrics
---
---
title: "Métricas de placement"
description: "Analiza las métricas de placement en Adapty para mejorar el rendimiento de tus paywalls."
---
Con Adapty, puedes crear y gestionar múltiples placements en tu app, cada uno asociado a paywalls o pruebas A/B distintas. Esta flexibilidad te permite dirigirte a segmentos de usuarios específicos, experimentar con diferentes ofertas o modelos de precios, y optimizar la estrategia de monetización de tu app.
Para obtener información valiosa sobre el rendimiento de tus placements y la interacción de los usuarios con tus ofertas, Adapty registra diversas interacciones de usuarios y transacciones relacionadas con los paywalls mostrados. El sólido sistema de analíticas captura métricas como vistas, vistas únicas, compras, pruebas, reembolsos, tasas de conversión e ingresos.
Las métricas recopiladas se actualizan continuamente en tiempo real y pueden consultarse y analizarse cómodamente desde el dashboard de Adapty. Puedes personalizar el rango de tiempo para el análisis, aplicar filtros basados en distintos parámetros y comparar métricas entre varios placements, segmentos de usuarios o productos.
Las métricas de placement están disponibles en la lista de placements, donde puedes obtener una visión general del rendimiento de todos tus placements. Esta vista de alto nivel ofrece métricas agregadas para cada placement, lo que te permite comparar su rendimiento e identificar tendencias.
Para un análisis más detallado de cada placement, puedes navegar a las métricas de detalle del placement. En esta página encontrarás métricas completas específicas del placement seleccionado. Estas métricas ofrecen una visión más profunda del rendimiento de un placement concreto, lo que te permite evaluar su efectividad y tomar decisiones basadas en datos.
### Filtrar métricas por fecha de instalación \{#filter-metrics-by-install-date\}
Las métricas de paywall, periodo de prueba y compra se pueden agrupar por dos tipos de fechas distintos:
- **La fecha del evento**: cuando se visualizó el paywall, empezó el periodo de prueba o se realizó la compra.
- **La fecha de instalación**: cuando el usuario abrió la app por primera vez.
Ambas vistas pueden mostrar números muy diferentes para el mismo rango de fechas. La casilla **Filter metrics by install date** controla cuál de las dos usa el dashboard:
- **Sin marcar (por defecto)**: Las métricas se agrupan por fecha del evento.
- **Marcada**: Las métricas se agrupan por fecha de instalación.
**Ejemplo.** Estableces el rango de fechas del 1 al 30 de abril y observas los periodos de prueba.
- **Sin marcar**: Muestra los periodos de prueba que *comenzaron* en abril, independientemente de cuándo se instalaron esos usuarios.
- **Marcada**: Muestra los periodos de prueba de usuarios que *instalaron* la app en abril, independientemente de cuándo empezaron sus periodos de prueba.
Usa la vista por fecha de instalación para medir el rendimiento de adquisición de usuarios de una cohorte concreta. Usa la vista por fecha del evento para medir la actividad del paywall u onboarding en un periodo específico.
### Controles de métricas \{#metrics-controls\}
El sistema muestra las métricas en función del período de tiempo seleccionado y las organiza según el parámetro de la columna izquierda con cuatro niveles de sangría.
#### Opciones de visualización de datos de métricas \{#view-options-for-metrics-data\}
La página de métricas de placement ofrece dos opciones de visualización de datos: por paywall y por audiencia.
En la vista por paywall, las métricas se agrupan por los placements asociados al paywall. Esto permite analizar las métricas según los distintos placements.
En la vista por audiencia, las métricas se agrupan por la audiencia objetivo del paywall. Los usuarios pueden evaluar las métricas específicas de cada segmento de audiencia.
#### Rangos de tiempo \{#time-ranges\}
Puedes elegir entre varios períodos de tiempo para analizar datos de métricas, lo que te permite centrarte en duraciones específicas como días, semanas, meses o rangos de fechas personalizados.
#### Filtros y agrupación disponibles \{#available-filters-and-grouping\}
:::link
Artículo principal: [Controles de análisis](controls-filters-grouping-compare-proceeds)
:::
Adapty ofrece potentes herramientas para filtrar y personalizar el análisis de métricas según tus necesidades. En la página de métricas de Adapty tienes acceso a distintos rangos de tiempo, opciones de agrupación y posibilidades de filtrado.
- ✅ Filtrar por: Audiencia, paywall, grupo de paywalls, placement, país, store.
- ✅ Agrupar por: Segmento, store y producto
#### Gráfico de métrica individual \{#single-metrics-chart\}
Una de las partes principales de la página de métricas de placement es la sección de gráficos, que representa visualmente las métricas seleccionadas y facilita su análisis.
La sección de gráfico en la página de métricas de placements incluye un gráfico de barras horizontales que representa visualmente los valores de la métrica seleccionada. Cada barra del gráfico corresponde a un valor de la métrica y es proporcional en tamaño, lo que facilita entender los datos de un vistazo. La línea horizontal indica el período de tiempo analizado, y la columna vertical muestra los valores numéricos de las métricas. El valor total de todos los valores de la métrica se muestra junto al gráfico.
Además, al hacer clic en el icono de flecha en la esquina superior derecha de la sección del gráfico, la vista se amplía y muestra las métricas seleccionadas en la línea completa del gráfico.
#### Resumen total de métricas \{#total-metrics-summary\}
Junto al gráfico de métrica individual, se muestra la sección de resumen de métricas totales, que presenta los valores acumulados de las métricas seleccionadas en un momento concreto, con la posibilidad de cambiar la métrica mostrada mediante un menú desplegable.
### Definiciones de métricas \{#metrics-definitions\}
Aprovecha al máximo las métricas de placement con nuestras definiciones completas. Desde los ingresos hasta las tasas de conversión, obtén información valiosa que impulsará tus estrategias de monetización y el éxito de tu app.
:::note
Adapty convierte otras divisas a USD según el tipo de cambio de [currencylayer.com](https://currencylayer.com/) (actualizado cada 8 horas). El tipo de cambio se **fija en el momento de la transacción** — los cambios futuros no afectan al resultado de la conversión.
:::
#### Ingresos \{#revenue\}
Esta métrica representa el importe total en USD generado por compras y renovaciones dentro de placements específicos. Ten en cuenta que el cálculo de ingresos no incluye la comisión de Apple App Store ni de Google Play Store y se calcula antes de deducir cualquier comisión.
#### Proceeds
Esta métrica representa el importe real recibido por el propietario de la aplicación en USD, procedente de compras y renovaciones dentro de placements específicos, una vez deducida la comisión correspondiente de Apple App Store o Google Play Store. Refleja los ingresos netos que contribuyen directamente a las ganancias de la aplicación. Para más información sobre cómo se calculan los ingresos netos, consulta la [documentación](analytics-cohorts#revenue-vs-proceeds) de Adapty.
#### ARPPU \{#arppu\}
ARPPU son las siglas de Average Revenue Per Paying User (ingreso medio por usuario de pago) y mide el ingreso medio generado por cada usuario de pago dentro de placements específicos. Se calcula dividiendo el ingreso total entre el número de usuarios de pago únicos. Por ejemplo, si el ingreso total es $15,000 y hay 1,000 usuarios de pago, el ARPPU sería $15.
#### ARPAS
ARPAS, o ingresos medios por suscriptor activo (Average Revenue Per Active Subscriber), permite medir los ingresos medios generados por cada suscriptor activo dentro de placements específicos. Se calcula dividiendo los ingresos totales entre el número de suscriptores que han activado una prueba o suscripción. Por ejemplo, si los ingresos totales son 5.000 $ y hay 1.000 suscriptores, el ARPAS sería de 5 $. Esta métrica ayuda a evaluar el potencial de monetización medio por suscriptor.
#### ARPU \{#arpu\}
Solo para placements de onboarding. El ARPU es el ingreso promedio por usuario que vio el onboarding. Se calcula dividiendo el ingreso total entre el número de visualizaciones únicas.
#### CR única a compras \{#unique-cr-to-purchases\}
La tasa de conversión única a compras se calcula dividiendo el número de compras dentro de placements específicos entre el número de visualizaciones únicas. Se centra en la relación entre compras y el número único de visualizaciones, lo que permite entender la efectividad a la hora de convertir visitantes únicos en clientes de pago dentro de placements específicos.
#### CR a compras \{#cr-to-purchases\}
La tasa de conversión a compras se calcula dividiendo el número de compras dentro de placements específicos entre el número total de vistas de paywalls. Indica el porcentaje de vistas dentro de placements específicos que resultan en compras, lo que ofrece información sobre la eficacia de tu paywall para convertir usuarios en clientes de pago.
#### CR único a pruebas \{#unique-cr-to-trials\}
La tasa de conversión única a pruebas gratuitas se calcula dividiendo el número de pruebas iniciadas en placements específicos entre el número de vistas únicas. Mide el porcentaje de vistas únicas en placements específicos que resultan en activaciones de prueba, y ofrece información sobre la efectividad de tu paywall para convertir visitantes únicos en usuarios de prueba.
#### Compras \{#purchases\}
Las compras representan el total acumulado de diversas transacciones realizadas en el paywall dentro de placements específicos. Las siguientes transacciones se incluyen en esta métrica (las renovaciones no están incluidas):
- Las nuevas compras se realizan directamente dentro de placements específicos.
- Las conversiones de prueba de trials que se activaron inicialmente dentro de placements específicos.
- Los cambios de categoría (downgrades, upgrades y cross-grades) de suscripciones realizados dentro de placements específicos.
- Las restauraciones de suscripciones dentro de placements específicos, como cuando se restablece una suscripción tras su expiración sin renovación automática.
Al tener en cuenta estos diferentes tipos de transacciones, la métrica de compras ofrece una visión completa de la actividad general de adquisición y monetización dentro de placements específicos.
#### Trials \{#trials\}
La métrica de trials representa el número total de trials activados en placements concretos. Refleja cuántos usuarios han iniciado períodos de prueba a través de tu paywall en esos placements. Esta métrica ayuda a medir la efectividad de tu oferta de trial y puede aportar información sobre el engagement de los usuarios y la conversión de trials a suscripciones de pago.
#### Trials cancelados \{#trials-canceled\}
La métrica de pruebas canceladas representa el número de pruebas dentro de placements específicos en las que se ha desactivado la renovación automática. Esto ocurre cuando los usuarios cancelan manualmente la prueba, lo que indica su decisión de no continuar con la suscripción una vez finalizado el período de prueba. Hacer un seguimiento de las pruebas canceladas proporciona información valiosa sobre el comportamiento de los usuarios y permite entender la tasa a la que estos optan por salir de la prueba dentro de placements específicos.
#### Reembolsos \{#refunds\}
La métrica de reembolsos representa el número de compras y suscripciones reembolsadas en placements específicos. Esto incluye transacciones que han sido revertidas o reembolsadas por diversas razones, como solicitudes de clientes, problemas de pago u otras políticas de reembolso aplicables.
#### Tasa de reembolso \{#refund-rate\}
La tasa de reembolso se calcula dividiendo el número de reembolsos en placements específicos entre el número de primeras compras (las renovaciones no se incluyen). Por ejemplo, si hay 5 reembolsos y 1.000 primeras compras, la tasa de reembolso sería del 0,5%.
#### Vistas \{#views\}
La métrica de vistas representa el número total de veces que el paywall dentro de placements específicos ha sido visualizado por los usuarios. Cada vez que un usuario visita el paywall dentro de esos placements, se cuenta como una vista independiente. El seguimiento de las vistas te ayuda a entender el nivel de participación e interacción de los usuarios con tu paywall, proporcionando información sobre el comportamiento del usuario y la efectividad del placement y diseño de tu paywall en áreas específicas de tu app.
#### Vistas únicas \{#unique-views\}
La métrica de vistas únicas representa el número de instancias únicas en las que los usuarios han visto el paywall dentro de placements específicos. A diferencia de las vistas totales, que cuentan cada visita como una vista separada, las vistas únicas cuentan la visita de cada usuario al paywall dentro de esos placements solo una vez, independientemente de cuántas veces acceda a él. Registrar las vistas únicas ayuda a obtener una medida más precisa del engagement de los usuarios y el alcance de tu paywall dentro de placements específicos, ya que se centra en usuarios individuales en lugar del número total de visitas.
#### Completions y completions únicas \{#completions--unique-completions\}
Solo para placements de onboarding. Las completions cuentan el número de veces que los usuarios completan tu placement de onboarding, es decir, que pasan de la primera a la última pantalla. Si alguien lo completa dos veces, eso cuenta como dos **completions** pero una **unique completion**.
#### Tasa de unique completions \{#unique-completions-rate\}
Solo para placements de onboarding. El número de unique completions dividido entre el número de unique views. Esta métrica te ayuda a entender cómo interactúa la gente con el placement de onboarding y a realizar cambios si detectas que lo ignoran.
---
# File: create-paywall
---
---
title: "Crear paywall"
description: "Aprende a crear paywalls de alta conversión usando el Paywall Builder de Adapty."
---
Un [paywall](paywalls) es una configuración de Adapty que define qué productos ofrecer. En Adapty, los paywalls son la única forma de recuperar productos en tu app.
Necesitas un paywall independientemente de cómo lo muestres:
- [**Paywall Builder**](adapty-paywall-builder): Diseña una pantalla en el editor sin código. Adapty la renderiza y gestiona las compras.
- **Paywall personalizado**: Implementa tu propia interfaz y usa la configuración del paywall para recuperar los productos.
Una vez creado, asigna el paywall a un [placement](placements) — los placements controlan qué paywall ven los usuarios. Los productos de un paywall en producción son fijos, por lo que sus métricas siempre reflejan la misma combinación, lo que te permite comparar el rendimiento entre distintos conjuntos de productos y precios.
:::tip
También puedes crear paywalls mediante programación usando la [CLI para desarrolladores](developer-cli-reference#adapty-paywalls-create).
:::
## Próximos pasos \{#next-steps\}
Después de crear tu primer paywall:
1. Agrégalo a un [placement](placements). Los IDs de placement serán las únicas entidades hardcodeadas. Los usarás para obtener los productos que quieres vender.
2. El modo de trabajo con el paywall a partir de aquí depende de tu implementación:
- Si quieres usar el [Adapty Paywall Builder](adapty-paywall-builder), diseña el paywall en el editor sin código. Adapty renderizará el paywall y gestionará la lógica de compra, mientras que tú solo necesitarás mostrar el paywall en el código de la app.
- Si tienes un paywall personalizado que quieres usar, consulta nuestras guías para implementar compras in-app con Adapty en tu plataforma:
- [iOS](ios-implement-paywalls-manually)
- [Android](android-implement-paywalls-manually)
- [React Native](react-native-implement-paywalls-manually)
- [Flutter](flutter-implement-paywalls-manually)
- [Unity](unity-implement-paywalls-manually)
- [Kotlin Multiplatform](kmp-implement-paywalls-manually)
---
# File: customize-paywall-with-remote-config
---
---
title: "Diseña un paywall con Remote Config"
description: "Personaliza tu paywall con Remote Config en Adapty para un mejor targeting."
---
:::important
Esta guía cubre Remote Config para paywalls clásicos. Para Flow Builder, consulta [Personalizar flow con Remote Config](customize-flow-with-remote-config).
:::
El Remote Config de paywall es una herramienta muy útil que ofrece opciones de configuración flexibles. Permite usar payloads JSON personalizados para ajustar tus paywalls con precisión. Con él puedes definir distintos parámetros como títulos, imágenes, fuentes, colores y más.
3. Cambia a la pestaña **Remote config**.
El Remote Config tiene 2 vistas:
- [Tabla](customize-paywall-with-remote-config#table-view-of-the-remote-config)
- [JSON](customize-paywall-with-remote-config#json-view-of-the-remote-config)
Tanto la vista **Tabla** como la vista **JSON** incluyen los mismos elementos de configuración. La única diferencia es de preferencia personal, con la salvedad de que la vista de tabla ofrece un menú contextual, que puede ser útil para corregir errores de localización.
Puedes cambiar entre vistas haciendo clic en la pestaña **Table** o **JSON** cuando lo necesites.
Independientemente de la vista que hayas elegido para personalizar tu paywall, puedes acceder a estos datos desde el SDK usando las propiedades `remoteConfig` o `remoteConfigString` de `AdaptyPaywall` y hacer ajustes en tu paywall. También puedes actualizar los valores del Remote Config mediante programación usando la [API del lado del servidor](api-adapty/operations/updatePaywall) para modificar dinámicamente las configuraciones de paywall sin actualizaciones manuales en el dashboard. Aquí tienes algunos ejemplos de cómo puedes usar un Remote Config.
### Vista de tabla del Remote Config \{#table-view-of-the-remote-config\}
Si no es habitual para ti trabajar con código y necesitas corregir algunos valores del JSON, Adapty tiene la vista **Table** para ti.
Es una copia de tu JSON en formato de tabla, fácil de leer y entender. El código de colores ayuda a identificar los distintos tipos de datos.
Para añadir una clave, haz clic en el botón **Add row**. Comprobamos automáticamente la correspondencia entre valores y tipos, y mostramos una alerta si tus cambios pueden producir un JSON no válido.
Las opciones adicionales de fila son especialmente útiles para las [localizaciones de paywall](add-remote-config-locale):
Ahora es el momento de [crear un placement](create-placement) y añadir el paywall a él. Después, puedes
4. Haz clic en **Locales** y selecciona los idiomas que quieres admitir. Guarda los cambios para añadir estas localizaciones al paywall.
Ahora puedes traducir el contenido manualmente, usar IA o exportar el archivo de localización para traductores externos.
## Traducir paywalls con IA \{#translate-paywalls-with-ai\}
La traducción con IA es una forma rápida y eficaz de localizar tu paywall.
Puedes traducir tanto valores de tipo **String** como **List**. Por defecto, todas las líneas están seleccionadas (resaltadas en violeta). Las líneas que ya han sido traducidas aparecen en verde y no se incluirán en la nueva traducción por defecto. Las líneas que no están seleccionadas ni traducidas aparecen en gris.
1. Selecciona las líneas que quieres traducir. Es recomendable desmarcar las líneas con IDs, URLs y variables para que la IA no las traduzca.
2. Selecciona los idiomas para la traducción.
3. Haz clic en **AI Translate** para aplicar las traducciones. Las líneas seleccionadas se traducirán y se añadirán al paywall, quedando marcadas en verde.
## Exportar archivos de localización para traductores externos \{#exporting-localization-files-for-external-translation\}
Aunque la localización con IA es cada vez más popular, puede que prefieras un método más fiable, como usar traductores profesionales o una agencia de traducción con experiencia contrastada. En ese caso, puedes exportar los archivos de localización para compartirlos con tus traductores e importar los resultados traducidos de vuelta a Adapty.
Al exportar con el botón **Export** se crean archivos `.json` individuales para cada idioma, agrupados en un único archivo comprimido. Si solo necesitas un archivo, puedes exportarlo directamente desde el menú específico del idioma.
Una vez que hayas recibido los archivos traducidos, usa el botón **Import** para subirlos todos a la vez o de forma individual. Adapty validará automáticamente los archivos para asegurarse de que tienen el formato correcto.
### Formato del archivo de importación \{#import-file-format\}
Para que la importación se realice correctamente, el archivo debe cumplir los siguientes requisitos:
- **Nombre y extensión del archivo:**
El nombre del archivo debe coincidir con la localización que representa y tener extensión `.json`. Puedes verificar y copiar el nombre de la localización en el Adapty Dashboard. Si el nombre no se reconoce, la importación fallará.
- **JSON válido:**
El archivo debe ser un JSON válido. Si no lo es, la importación fallará.
## Localización manual \{#manual-localization\}
A veces puede que quieras ajustar traducciones, añadir imágenes diferentes para localizaciones específicas o incluso modificar las configuraciones remotas directamente.
1. Elige el elemento que quieres traducir e introduce un nuevo valor. Puedes actualizar tanto valores de tipo **String** como **List**, o reemplazar imágenes por otras más adecuadas para la localización.
2. Aprovecha el menú contextual de la localización en inglés para resolver problemas de localización de forma eficiente:
- **Copy this value to all locales**: Sobreescribe los cambios realizados en localizaciones que no sean la inglesa para la fila seleccionada, reemplazándolos con el valor de la localización en inglés.
- **Revert all row changes to original values**: Descarta los cambios realizados durante la sesión actual y restaura los valores al último estado guardado.
Después de añadir localizaciones a un paywall, asegúrate de implementar correctamente los códigos de localización en el código de tu app. Consulta
3. ⚠️ Si eliges Stripe, asegúrate de usar las claves del entorno **Test Mode** aunque la interfaz diga **Sandbox**. De lo contrario, tu web paywall no funcionará. Los **Sandboxes** de Stripe aún no son compatibles.
### Configura la verificación de dominio de Apple Pay \{#set-up-apple-pay-domain-verification\}
En **Settings > Domains**, selecciona tu proveedor de pagos principal para usarlo en la verificación de dominio. Luego, verifica los dominios de tu paywall con el proveedor correspondiente:
**Stripe**:
1. Ve a [Payment method domain settings](https://dashboard.stripe.com/settings/payment_method_domains) y haz clic en **Add a new domain**.
2. Añade `app.funnelfox.com` y tu subdominio personal del paywall (tendrá un aspecto similar a `paywalls-....fnlfx.com`). Para encontrar tu subdominio, ve a **Settings > Domains** y copia el valor de **Hosted subdomain**.
**Paddle**:
1. En la consola de Paddle, ve a **Checkout > Website approval** y haz clic en **Add a new domain**.
2. Añade `app.funnelfox.com` y tu subdominio personal del paywall (tendrá un aspecto similar a `paywalls-....fnlfx.com`). Para encontrar tu subdominio, ve a **Settings > Domains** y copia el valor de **Hosted subdomain**.
El proceso de aprobación en Paddle es manual, por lo que tendrás que esperar hasta que los dominios pasen de `Pending` a `Approved`.
**FunnelFox Billing**:
Sigue las [instrucciones de integración de FunnelFox Billing](https://funnelfox.com/docs/billing/integration-billing-funnelfox).
**SolidGate**:
1. En tu Solidgate Dashboard, ve a **Developers > Apple Pay Domains**.
2. Haz clic en **+ Add new domain** y pega el dominio de tu proyecto (desde **Settings > Domains** en FunnelFox). Añade también tu dominio personalizado, si corresponde.
3. Para usar Apple Pay en modo de vista previa, añade también `http://app.funnelfox.com/`.
## Crea y configura un web paywall \{#create-and-configure-a-web-paywall\}
1. En la página de lista de web paywalls, haz clic en **Create a paywall**.
2. Introduce un nombre para el paywall y haz clic en **Create**.
3. Se te redirigirá a una plantilla básica con dos opciones de suscripción y el botón de compra de Apple Pay.
La primera pantalla muestra los planes de suscripción. La segunda y la tercera son pantallas de pago. Cada pantalla corresponde a un plan que ofreces. Si solo tienes un plan, elimina la pantalla extra. Si tienes más, debes duplicar las pantallas de pago.
La última pantalla que ven los usuarios tras una compra exitosa es donde debes indicar claramente que pueden volver a tu app.
4. Configura la lista de planes: añade o elimina planes y precios. Todos los precios y planes que ves en pantalla no se añaden de forma dinámica, por lo que debes configurarlos manualmente.
5. Añade o configura una pantalla de pago para cada plan que tengas. Te recomendamos añadir el importe total en cada pantalla de pago para que los usuarios sepan cuánto van a pagar antes de hacer clic en el botón de compra.
6. En las pantallas de pago, ya tienes el botón de Apple Pay. Para que funcione, configura en cada pantalla:
1. **Product type**: Selecciona si quieres añadir un período de prueba o un descuento.
2. **Trial period**: Introduce la duración del período de prueba.
3. **Product**: Selecciona tu producto de tu proveedor de pagos.
:::important
Asegúrate de que el producto esté añadido en Adapty. De lo contrario, el resultado de la compra se establecerá por defecto.
:::
4. **Subscription discount**: Opcionalmente, selecciona un cupón de tu proveedor de pagos.
7. Ahora necesitas asociar los planes con las pantallas de pago. En la pantalla de selección de plan, haz clic en el botón **Continue** y selecciona una pantalla de destino para cada plan.
Cuando tengas el paywall listo, necesitas obtener su enlace para activarlo en Adapty. La forma de obtenerlo depende de si lo estás probando o lanzando en el entorno de producción:
1. **Para pruebas en sandbox**: Haz clic en **Preview** en la parte superior derecha y copia el enlace.
2. **Para producción**: Haz clic en **Publish** en la parte superior derecha. Haz clic en **Home** y copia el enlace de la columna **URL**.
¡Listo! Usa este enlace para [continuar con la configuración](web-paywall#step-2-trigger-the-paywall).
---
# File: fallback-paywalls
---
---
title: "Paywalls de respaldo"
description: "Usa paywalls de respaldo para garantizar una experiencia de usuario fluida en Adapty."
---
Para mantener una experiencia de usuario fluida, es importante que configures **versiones de respaldo** para tus [paywalls](paywalls) y [onboardings](onboardings).
Cuando tu aplicación carga un paywall, el SDK de Adapty solicita los datos de configuración del paywall desde nuestros servidores. ¿Pero qué ocurre si el dispositivo no puede conectarse a Adapty por problemas de red o interrupciones del servidor?
* Si el usuario accedió al paywall anteriormente y el dispositivo guardó sus datos en caché, la aplicación carga los datos del paywall **desde la caché**.
* Si el dispositivo no tiene el paywall en caché, la aplicación busca un archivo de configuración almacenado localmente. Esto le permite mostrar el paywall sin errores.
Adapty genera automáticamente archivos de configuración de respaldo para que los descargues y uses. Cada archivo contiene configuraciones específicas de plataforma para *todos* tus placements.
## Primeros pasos \{#get-started\}
1. [Descarga el archivo de configuración de respaldo](/local-fallback-paywalls) desde Adapty.
2. Usa el SDK de Adapty para configurar tus paywalls de respaldo:
* [iOS](ios-use-fallback-paywalls)
* [Android](android-use-fallback-paywalls)
* [React Native](react-native-use-fallback-paywalls)
* [Flutter](flutter-use-fallback-paywalls)
* [Unity](unity-use-fallback-paywalls)
* [Kotlin Multiplatform](kmp-use-fallback-paywalls)
* [Capacitor](capacitor-use-fallback-paywalls)
## Limitaciones \{#limitations\}
Los paywalls de respaldo están codificados de forma fija y se almacenan localmente, por lo que carecen de las capacidades dinámicas de los paywalls regulares de Adapty.
* Los paywalls de respaldo no admiten [internacionalización](paywall-localization). Cuando Adapty genera el archivo de configuración, utiliza el idioma predeterminado `en`.
* Cada placement solo puede tener un paywall de respaldo. Si tu configuración incluye distintos paywalls para diferentes [audiencias](audience), Adapty usa la configuración destinada a "All users".
* Los paywalls de respaldo no admiten [pruebas A/B](ab-tests). Si un paywall participa en una prueba A/B, su archivo de configuración de respaldo incluirá la variante con mayor peso.
* Los paywalls de respaldo no se pueden [gestionar de forma remota](customize-paywall-with-remote-config). Si quieres actualizar el archivo de configuración, deberás publicar una nueva versión de la app en App Store / Google Play.
---
# File: local-fallback-paywalls
---
---
title: "Descargar paywalls de respaldo"
description: "Usa paywalls de respaldo locales en Adapty para garantizar flujos de suscripción sin interrupciones."
---
Adapty genera automáticamente archivos de configuración JSON para tus [paywalls de respaldo](/fallback-paywalls), uno por plataforma. Estos archivos también contienen los datos de respaldo para tus onboardings.
Si un placement tiene más de un paywall u onboarding, la versión de respaldo incluirá la variación con el mayor peso o la audiencia más amplia. Adapty actualiza estos archivos cada vez que modificas tus paywalls u onboardings.
Sigue los pasos a continuación para descargar tus configuraciones de respaldo:
1. Abre la página **[Placements](https://app.adapty.io/placements)**.
2. Haz clic en el botón **Fallbacks**.
3. Selecciona tu plataforma de destino (*iOS* o *Android*) en el menú desplegable.
4. Selecciona la versión de tu SDK para iniciar la descarga.
## Después de la descarga \{#after-the-download\}
Sigue la guía de configuración para tu plataforma:
* [iOS](ios-use-fallback-paywalls)
* [Android](android-use-fallback-paywalls)
* [React Native](react-native-use-fallback-paywalls)
* [Flutter](flutter-use-fallback-paywalls)
* [Unity](unity-use-fallback-paywalls)
* [Kotlin Multiplatform](kmp-use-fallback-paywalls)
* [Capacitor](capacitor-use-fallback-paywalls)
---
# File: paywall-metrics
---
---
title: "Métricas de paywall"
description: "Rastrea y analiza las métricas de rendimiento de tus paywalls para mejorar los ingresos por suscripción."
---
Adapty recopila una serie de métricas para ayudarte a medir mejor el rendimiento de los paywalls. Todas las métricas se actualizan en tiempo real, excepto las vistas, que se actualizan cada varios minutos. Todas las métricas, excepto las vistas, se atribuyen al producto dentro del paywall. Este documento describe las métricas disponibles, sus definiciones y cómo se calculan.
Las métricas de los paywalls están disponibles en la lista de paywalls, lo que te ofrece una visión general del rendimiento de todos tus paywalls. Esta vista consolidada muestra métricas agregadas para cada paywall, lo que te permite evaluar su efectividad e identificar áreas de mejora.
Para un análisis más detallado de cada paywall, puedes navegar a las métricas de detalle del paywall. En esta sección encontrarás métricas exhaustivas específicas del paywall seleccionado, con información más profunda sobre su rendimiento.
### Filtrar métricas por fecha de instalación \{#filter-metrics-by-install-date\}
Las métricas de paywall, periodo de prueba y compra se pueden agrupar por dos tipos de fechas distintos:
- **La fecha del evento**: cuando se visualizó el paywall, empezó el periodo de prueba o se realizó la compra.
- **La fecha de instalación**: cuando el usuario abrió la app por primera vez.
Ambas vistas pueden mostrar números muy diferentes para el mismo rango de fechas. La casilla **Filter metrics by install date** controla cuál de las dos usa el dashboard:
- **Sin marcar (por defecto)**: Las métricas se agrupan por fecha del evento.
- **Marcada**: Las métricas se agrupan por fecha de instalación.
**Ejemplo.** Estableces el rango de fechas del 1 al 30 de abril y observas los periodos de prueba.
- **Sin marcar**: Muestra los periodos de prueba que *comenzaron* en abril, independientemente de cuándo se instalaron esos usuarios.
- **Marcada**: Muestra los periodos de prueba de usuarios que *instalaron* la app en abril, independientemente de cuándo empezaron sus periodos de prueba.
Usa la vista por fecha de instalación para medir el rendimiento de adquisición de usuarios de una cohorte concreta. Usa la vista por fecha del evento para medir la actividad del paywall u onboarding en un periodo específico.
### Controles de métricas \{#metrics-controls\}
El sistema muestra las métricas según el período de tiempo seleccionado y las organiza de acuerdo con el parámetro de la columna izquierda con tres niveles de sangría.
Para el paywall en directo, las métricas cubren el período desde la fecha de inicio del paywall hasta la fecha actual. Para los paywalls inactivos, las métricas abarcan todo el período desde la fecha de inicio hasta el final del período de tiempo seleccionado. Los paywalls en borrador y archivados están incluidos en la tabla de métricas, pero si no hay datos disponibles para esos paywalls, aparecerán en la lista sin ninguna métrica.
#### Opciones de visualización de datos de métricas \{#view-options-for-metrics-data\}
La página del paywall ofrece dos opciones de visualización de datos de métricas: por placement y por audiencia.
En la vista por placement, las métricas se agrupan según los placements asociados al paywall. Esto permite analizar las métricas por diferentes placements.
En la vista basada en audiencia, las métricas se agrupan según la audiencia objetivo del paywall. Los usuarios pueden evaluar métricas específicas para distintos segmentos de audiencia. Puedes seleccionar la vista preferida mediante el menú desplegable en la parte superior de la página de detalles del paywall.
#### Rangos de tiempo \{#time-ranges\}
Puedes elegir entre varios períodos de tiempo para analizar los datos de métricas, lo que te permite centrarte en duraciones específicas como días, semanas, meses o rangos de fechas personalizados.
#### Filtros y agrupación disponibles \{#available-filters-and-grouping\}
:::link
Artículo principal: [Controles de análisis](controls-filters-grouping-compare-proceeds)
:::
Adapty ofrece potentes herramientas para filtrar y personalizar el análisis de métricas según tus necesidades. En la página de métricas de Adapty tienes acceso a distintos rangos de tiempo, opciones de agrupación y posibilidades de filtrado.
- Filtrar por: Audiencia, país, paywall, estado del paywall, grupo de paywalls, placement, país, store, producto y store del producto.
- Agrupar por: Producto y store.
#### Gráfico de métrica individual \{#single-metrics-chart\}
Una de las partes principales de la página de métricas del paywall es la sección de gráficos, que representa visualmente las métricas seleccionadas y facilita el análisis.
La sección del gráfico en la página de métricas del paywall incluye un gráfico de barras horizontales que representa visualmente los valores de la métrica seleccionada. Cada barra corresponde a un valor de la métrica y es proporcional en tamaño, lo que facilita la comprensión de los datos de un vistazo. La línea horizontal indica el período de tiempo analizado, y la columna vertical muestra los valores numéricos de las métricas. El valor total de todos los valores de la métrica se muestra junto al gráfico.
Además, al hacer clic en el icono de flecha en la esquina superior derecha de la sección del gráfico, la vista se amplía y muestra las métricas seleccionadas en la línea completa del gráfico.
#### Resumen de métricas totales \{#total-metrics-summary\}
Junto al gráfico de métrica individual, se muestra la sección de resumen de métricas totales, que presenta los valores acumulados de las métricas seleccionadas en un momento determinado, con la posibilidad de cambiar la métrica mostrada mediante un menú desplegable.
### Definiciones de métricas \{#metrics-definitions\}
:::note
Adapty convierte otras divisas a USD según el tipo de cambio de [currencylayer.com](https://currencylayer.com/) (actualizado cada 8 horas). El tipo de cambio se **fija en el momento de la transacción** — los cambios futuros no afectan al resultado de la conversión.
:::
#### Ingresos \{#revenue\}
Esta métrica representa el importe total en USD generado por compras y renovaciones. Ten en cuenta que el cálculo de ingresos no incluye la comisión de App Store / Play Store y se calcula antes de deducir cualquier comisión.
#### Ganancias netas \{#proceeds\}
Esta métrica representa el importe real en USD recibido por el propietario de la app por compras y renovaciones, tras deducir la comisión aplicable de App Store / Play Store.
:::important
Notifica a Adapty si tu app está inscrita en un programa de comisión reducida. Para garantizar cálculos correctos, especifica el estado de tu [Small Business Program](app-store-small-business-program) y [Reduced Service Fee program](google-reduced-service-fee) en los [ajustes de tu app](general).
:::
Refleja los ingresos netos que contribuyen directamente a las ganancias de la app. Para más información sobre cómo se calculan los ingresos netos, consulta la [documentación](analytics-cohorts#revenue-vs-proceeds) de Adapty.
#### ARPPU \{#arppu\}
ARPPU es el ingreso promedio por usuario de pago. Se calcula dividiendo los ingresos totales entre el número de usuarios de pago únicos. $15.000 de ingresos / 1.000 usuarios de pago = $15 de ARPPU.
#### ARPAS \{#arpas\}
El ingreso promedio por suscriptor activo te permite medir el ingreso promedio generado por cada suscriptor activo. Se calcula dividiendo los ingresos totales entre el número de suscriptores que han activado una prueba o suscripción. Por ejemplo, si los ingresos totales son $5.000 y hay 1.000 suscriptores, el ARPAS sería $5. Esta métrica ayuda a evaluar el potencial de monetización promedio por suscriptor.
#### Tasa de conversión (CR) única a compras
La tasa de conversión única a compras se calcula dividiendo el número de compras entre el número de vistas únicas. Por ejemplo, si hay 10 compras y 100 vistas únicas, la tasa de conversión única a compras sería del 10%. Esta métrica se centra en la proporción de compras respecto al número único de vistas, y ofrece información sobre la eficacia para convertir visitantes únicos en clientes de pago.
#### CR a compras
La tasa de conversión a compras se calcula dividiendo el número de compras entre el total de vistas. Por ejemplo, si hay 10 compras y 100 vistas, la tasa de conversión a compras sería del 10%. Esta métrica indica el porcentaje de vistas que resultan en compras, lo que ofrece información sobre la efectividad de tu paywall para convertir usuarios en clientes de pago.
#### CR único a trials \{#unique-cr-to-trials\}
La tasa de conversión única a pruebas se calcula dividiendo el número de pruebas iniciadas entre el número de vistas únicas. Por ejemplo, si se han iniciado 30 pruebas y hay 100 vistas únicas, la tasa de conversión única a pruebas sería del 30%. Esta métrica mide el porcentaje de vistas únicas que se convierten en activaciones de prueba, lo que permite evaluar la eficacia de tu paywall para convertir visitantes únicos en usuarios de prueba.
#### Compras \{#purchases\}
Las compras representan el total acumulado de distintas transacciones realizadas en el paywall. Las siguientes transacciones se incluyen en esta métrica (las renovaciones no están incluidas):
- Nuevas compras realizadas directamente en el paywall.
- Conversiones de prueba de trials que se activaron inicialmente en el paywall.
- Cambios de plan (downgrades, upgrades y cross-grades) de suscripciones realizados en el paywall.
- Restauraciones de suscripción en el paywall, como cuando una suscripción se reactiva tras expirar sin renovación automática.
Al considerar estos diferentes tipos de transacciones, la métrica de compras ofrece una visión completa de la actividad general de adquisición y monetización en tu paywall.
#### Pruebas gratuitas \{#trials\}
La métrica de pruebas gratuitas representa el número total de pruebas que se han activado. Refleja el número de usuarios que han iniciado períodos de prueba a través de tu paywall. Esta métrica ayuda a medir la eficacia de tu oferta de prueba y puede aportar información sobre la participación de los usuarios y la conversión de pruebas a suscripciones de pago.
#### Pruebas gratuitas canceladas \{#trials-canceled\}
La métrica de pruebas canceladas representa el número de pruebas en las que se ha desactivado la renovación automática. Esto ocurre cuando los usuarios cancelan manualmente la suscripción durante el período de prueba, lo que indica su decisión de no continuar con la suscripción al finalizar dicho período. Hacer seguimiento de las pruebas canceladas proporciona información valiosa sobre el comportamiento de los usuarios y permite entender la tasa a la que estos optan por abandonar la prueba.
#### Reembolsos \{#refunds\}
La métrica de reembolsos representa el número de compras y suscripciones reembolsadas. Esto incluye transacciones que han sido revertidas o reembolsadas por diversos motivos, como solicitudes de clientes, problemas de pago u otras políticas de reembolso aplicables.
#### Tasa de reembolso \{#refund-rate\}
La tasa de reembolso se calcula dividiendo el número de reembolsos entre el número de compras por primera vez (las renovaciones no se incluyen). Por ejemplo, si hay 5 reembolsos y 1000 compras por primera vez, la tasa de reembolso sería del 0,5%.
#### Vistas \{#views\}
La métrica de vistas representa el número total de veces que los usuarios han visto el paywall. Cada vez que un usuario visita el paywall, se cuenta como una vista independiente. Por ejemplo, si un usuario visita el paywall dos veces, se registrarán dos vistas. Hacer seguimiento de las vistas te ayuda a entender el nivel de interacción de los usuarios con tu paywall, y te da información sobre el comportamiento de los usuarios y la efectividad del placement y diseño del paywall.
#### Vistas únicas \{#unique-views\}
La métrica de vistas únicas representa el número de instancias únicas en las que los usuarios han visto el paywall. A diferencia de las vistas totales, que cuentan cada visita como una vista independiente, las vistas únicas cuentan la visita de cada usuario al paywall una sola vez, independientemente de cuántas veces accedan a él. Por ejemplo, si un usuario visita el paywall dos veces, se registrará como una única vista. Hacer seguimiento de las vistas únicas permite medir con mayor precisión la interacción de los usuarios y el alcance de tu paywall, ya que se centra en usuarios individuales en lugar de en el número total de visitas.
:::warning
Asegúrate de enviar las visualizaciones del paywall a Adapty usando el método `.logShowFlow()` (iOS SDK v4+) / `.logShowPaywall()`. De lo contrario, las visualizaciones del paywall no se contabilizarán en las métricas y las conversiones no serán relevantes.
:::
---
# File: migrate-paywalls
---
---
title: "Migrar paywalls entre apps"
description: "Aprende cómo migrar paywalls de otras apps en Adapty."
---
Con Adapty no necesitas crear un paywall desde cero para cada app. Si gestionas varias apps, puedes migrar la configuración del Paywall Builder de cualquier paywall creado con el builder de una app a otra.
La migración copia toda la configuración visual:
- Ajustes de diseño del paywall y de todos sus elementos
- Contenido multimedia
- Localización
La migración solo aplica a la configuración del builder y no copia los productos ni el Remote Config.
:::note
Si migras una configuración del Paywall Builder que usa fuentes personalizadas, pruébalas en un dispositivo, ya que pueden mostrarse incorrectamente.
:::
## Migrar un paywall \{#migrate-paywall\}
:::important
Solo puedes migrar paywalls creados en el **nuevo** Paywall Builder de Adapty. Para migrar paywalls del builder **legacy**, primero debes migrarlos al nuevo Paywall Builder.
:::
Para migrar una configuración del Paywall Builder:
1. **Para un paywall nuevo**: Comienza la [creación del paywall](create-paywall) y añade productos. Luego haz clic en **Build no-code paywall** para abrir la biblioteca de plantillas.
**Para un paywall existente**: Ve a la sección **Layout settings** de la pestaña **Builder & Generator** y haz clic en **Change template**.
2. Haz clic en **Choose paywall** dentro del recuadro **Copy a design from your apps** al editar la plantilla del paywall.
3. Selecciona la app y el paywall del que quieres copiar la configuración.
4. Haz clic en **Copy Selected Paywall**.
Tras la migración, puedes hacer los cambios que necesites sin que afecten al paywall original.
---
# File: duplicate-paywalls
---
---
title: "Duplicar paywall"
description: "Aprende a gestionar paywalls duplicados y optimizar el rendimiento de los paywalls en Adapty."
---
Si necesitas hacer pequeños cambios en un paywall existente de Adapty, especialmente cuando ya se está usando en tu app y no quieres estropear tus analíticas, puedes simplemente duplicarlo. Luego puedes usar esos duplicados para reemplazar los paywalls originales en algunos o todos los placements según necesites.
Esto crea una copia del paywall con todos sus detalles, como su nombre, productos y cualquier promoción. Al nombre del nuevo paywall se le añadirá "Copy" para que puedas distinguirlo fácilmente del original.
Para duplicar un paywall en el Adapty Dashboard:
1. Abre la sección [**Paywalls**](https://app.adapty.io/paywalls) en el menú principal de Adapty. La página de lista de paywalls del Adapty Dashboard ofrece una vista general de todos los paywalls presentes en tu cuenta.
2. Haz clic en el botón de **3 puntos** junto al paywall y selecciona la opción **Duplicate**.
3. Ajusta el nuevo paywall y haz clic en el botón **Save**.
4. Adapty te pedirá que reemplaces los paywalls originales por sus duplicados en los placements si el paywall original se está usando actualmente en algún placement. Si eliges **Create and replace original**, los nuevos paywalls pasarán a estar **Live** inmediatamente. También puedes crearlos como nuevos paywalls en estado **Draft** y añadirlos a los placements más adelante.
---
# File: archive-paywalls
---
---
title: "Archivar paywall"
description: "Aprende cómo archivar paywalls obsoletos en Adapty sin perder datos."
---
A medida que trabajas con Adapty y ajustas la configuración de tus paywalls, puede que acumules paywalls que ya no encajan con tu estrategia o campañas actuales. Estos paywalls sin uso, dejados como `Inactive`, pueden desordenar tu espacio de trabajo y dificultar encontrar los que realmente importan. Para resolver esto, Adapty ofrece la opción de archivar estos paywalls innecesarios.
Archivarlos garantiza que se guarden de forma segura sin eliminarlos permanentemente, listos para consultarse si es necesario en el futuro. Además, los paywalls archivados se pueden filtrar de la vista predeterminada, despejando tu espacio de trabajo y simplificando la interfaz. En esta guía, te explicamos cómo archivar paywalls en Adapty de forma eficiente para que tengas mayor control sobre la gestión de tus paywalls.
Un recordatorio importante: los paywalls activos que estén en uso en al menos un placement no se pueden archivar. Si quieres archivar uno de esos paywalls, primero elimínalo de todos los placements.
:::note
No puedes archivar un paywall si está siendo utilizado en una prueba A/B no archivada. De este modo, el usuario puede ver las métricas detalladas de una prueba A/B completada, y el paywall vinculado forma parte de esos datos.
:::
**Para archivar un paywall:**
1. Abre la sección [**Paywalls**](https://app.adapty.io/paywalls) en el menú principal de Adapty.
2. Haz clic en el botón **3-dot** junto al paywall y selecciona la opción **Archive**.
3. Cuando estés en la ventana **Archive paywall**, escribe el nombre del paywall que deseas archivar y haz clic en el botón **Archive**.
---
# File: restore-paywall
---
---
title: "Restaurar paywall desde el archivo"
description: "Restaura paywalls en Adapty para garantizar servicios de suscripción ininterrumpidos para los usuarios."
---
La posibilidad de archivar paywalls es una funcionalidad muy útil para simplificar la gestión de tus paywalls. Te permite ocultar los paywalls que ya no necesitas, reduciendo el desorden en tu espacio de trabajo. Además, la opción de restaurar paywalls archivados te da flexibilidad para reincorporarlos a tu estrategia si vuelven a ser útiles.
Los paywalls archivados pueden estar excluidos de la vista predeterminada. Para verlos, selecciona **Archived** en el filtro **State**.
**Para devolver un paywall desde el archivo**
1. Abre la sección [**Paywalls**](https://app.adapty.io/paywalls) en el menú principal de Adapty.
2. Asegúrate de que los paywalls archivados se muestran en la lista. Si no es así, actualiza el filtro de la derecha.
3. Haz clic en el botón de **3 puntos** junto al paywall archivado y selecciona **Back to active**.
---
# File: profiles-crm
---
---
title: "Perfiles/CRM"
description: "Gestiona perfiles de usuario y datos de CRM en Adapty para mejorar la segmentación de audiencias."
---
Profiles es un CRM para tus usuarios. Con Profiles puedes:
1. Encontrar usuarios concretos por profile ID, customer user ID, email o transaction ID.
2. Ver la línea de tiempo de eventos del usuario, incluidos problemas de facturación, períodos de gracia y otros [eventos](events).
3. Analizar las propiedades del usuario, como el estado de suscripción, ingresos totales y más.
4. Conceder al usuario una suscripción.
:::note
Los eventos del feed de eventos llegan al dashboard con un retraso. Los nuevos perfiles y los cambios de atributos pueden no ser visibles de inmediato.
:::
:::link
Para entender cómo Adapty crea y vincula perfiles de usuario, consulta [Cómo funcionan los perfiles](how-profiles-work).
:::
## Búsqueda de usuarios \{#finding-users\}
En la lista de Profiles puedes buscar un usuario concreto por:
- **Profile ID**: el identificador interno de Adapty para el usuario (también llamado Adapty ID).
- **Customer user ID**: el identificador de tu app para el usuario, si lo has configurado.
- **Email**: el email del usuario, si se ha enviado como atributo personalizado.
- **Transaction ID**: el transaction ID del store de una compra.
Haz clic en cualquier fila para abrir el perfil completo del usuario.
## Estado de suscripción \{#subscription-state\}
En la lista de Profiles puedes filtrar y ordenar usuarios por estado de suscripción. Los valores posibles son:
| **Estado** del usuario | Descripción |
| :--------------------- | :----------------------------------------------------------- |
| Subscribed | El usuario tiene una suscripción activa con la renovación automática habilitada. |
| Auto-renew off | El usuario desactivó la renovación automática, pero sigue teniendo acceso a las funciones premium hasta que finalice el período de suscripción. |
| Subscription cancelled | El usuario canceló su suscripción y esta ha finalizado por completo. |
| Billing issue | No se pudo cobrar al usuario debido a un problema de facturación, ya sea tras el vencimiento de su suscripción o del período de prueba. |
| Grace period | El usuario se encuentra actualmente en un período de gracia debido a un problema de facturación que ocurrió al intentar cobrarle tras el vencimiento de su suscripción o del período de prueba. |
| Active trial | El usuario tiene una suscripción activa que se encuentra actualmente en su período de prueba. |
| Trial cancelled | El usuario canceló el período de prueba y no tiene una suscripción activa. |
| Never subscribed | El usuario nunca se ha suscrito ni ha iniciado un período de prueba, y sigue siendo un usuario freemium. |
## Atributos de usuario \{#user-attributes\}
Puedes enviar propiedades adicionales del usuario a Adapty mediante el SDK.
Por defecto, Adapty establece:
| Propiedad | Descripción |
| ---------------- | ------------------------------------------------------------ |
| Customer user ID | Un identificador de tu usuario final en tu sistema. |
| Adapty ID | Identificador interno de Adapty para tu usuario final, llamado Profile ID. |
| IDFA | El Identifier for Advertisers, asignado por Apple al dispositivo del usuario. Requiere permiso de App Tracking Transparency (ATT) en iOS 14+. No disponible en Android. |
| Country | País de tu usuario final. |
| OS | El sistema operativo utilizado por el usuario final. |
| Device | El nombre del modelo de dispositivo visible para el usuario final. |
| Install date | La fecha en que el usuario se registró por primera vez en Adapty:
## Conceder una suscripción \{#granting-a-subscription\}
En un perfil puedes ampliar una suscripción activa o conceder al usuario acceso de por vida a un nivel de acceso, sin necesidad de que realice una compra.
Esto resulta especialmente útil para:
- Compensar a un usuario tras un problema de facturación o soporte.
- Ejecutar promociones manuales o programas beta.
- Probar flujos de suscripción sin una compra real.
Para conceder acceso, abre el perfil del usuario, ve a la sección **Access levels** y haz clic en **Edit**. Establece la fecha de vencimiento y guarda. La fecha de vencimiento debe ser futura y no puede reducirse una vez establecida. Ajustarla en suscripciones activas no afecta a los pagos en curso.
:::note
Conceder acceso no crea eventos de compra en App Store ni en Google Play. El historial de eventos y los análisis del usuario diferirán de un flujo de compra real.
:::
También puedes conceder acceso de forma programática mediante el método de API [Grant access level](api-adapty/operations/grantAccessLevel).
## Compartir acceso de pago entre cuentas de usuario \{#sharing-paid-access-between-user-accounts\}
:::link
Artículo principal: [Compartir acceso de pago entre cuentas de usuario](sharing-paid-access-between-user-accounts)
:::
### Historial de uso compartido de acceso \{#access-sharing-history\}
Cuando se comparten o transfieren niveles de acceso, el perfil del usuario muestra un enlace al perfil conectado — el perfil que compartió el acceso o el que lo recibió. Para ver el perfil conectado, en el **Profile** del usuario, haz clic en el enlace situado junto al nivel de acceso.
:::note
Los saldos de moneda virtual no se comparten ni se transfieren entre perfiles como los niveles de acceso. Cada saldo permanece en un único perfil; consulta [Saldos, perfiles y dispositivos](virtual-currency-balance#balances-profiles-and-devices).
:::
## Próximos pasos \{#next-steps\}
- Para entender cómo Adapty crea y vincula perfiles, consulta [Cómo funcionan los perfiles](how-profiles-work).
- Para configurar la política de compartición de acceso, consulta [Compartir acceso de pago entre cuentas de usuario](sharing-paid-access-between-user-accounts).
- Para conceder acceso de forma programática, consulta el método de API [Grant access level](api-adapty/operations/grantAccessLevel).
---
# File: how-profiles-work
---
---
title: "Cómo funcionan los perfiles"
description: "Entiende cómo Adapty crea, rastrea y vincula perfiles de usuario, incluyendo perfiles anónimos, usuarios identificados y relaciones padre/heredero."
---
Cada usuario de tu app tiene un perfil de Adapty que registra sus compras, eventos y estado de suscripción. Entender cómo se crean y vinculan los perfiles te ayuda a prevenir errores de integración, evitar la fragmentación de datos e interpretar correctamente la información en la sección [Perfiles](profiles-crm).
## Creación de perfil \{#profile-creation\}
Adapty crea automáticamente un perfil la primera vez que un usuario abre tu app.
**Sin un Customer User ID**, el perfil es anónimo. Se crea un nuevo perfil anónimo cada vez que:
- Un usuario reinstala la app
- Un usuario cierra sesión en tu app (cuando tu app llama a `Adapty.logout()`)
Las compras están vinculadas a la instalación de la app, no a una identidad de usuario persistente.
**Con un Customer User ID**, el perfil persiste entre reinstalaciones y dispositivos. Usar un Customer User ID te permite:
1. Rastrea a un usuario en reinstalaciones y múltiples dispositivos.
2. Busca usuarios por su customer user ID en la sección [**Profiles**](profiles-crm).
3. Usa el customer user ID en la [API server-side](getting-started-with-server-side-api).
4. Adapty envía el customer user ID a todas las integraciones.
El comportamiento del perfil con un customer user ID depende de cuándo lo configures:
- **Al activar el SDK**: Adapty usa el perfil existente con ese customer user ID (para usuarios que regresan) o crea un nuevo perfil (para usuarios nuevos).
- **Después de activar el SDK**: Adapty crea un perfil anónimo al activarse. Cuando identificas al usuario más adelante, Adapty vincula el customer user ID al perfil anónimo (para usuarios nuevos) o cambia al perfil existente con ese ID (para usuarios que regresan).
**Qué enfoque usar:**
- **ID de usuario disponible al iniciar la app** (por ejemplo, guardado de una sesión anterior): pásalo a `activate()` al inicializar el SDK.
- **Los usuarios inician sesión después de abrir la app**: llama a `identify()` tras la autenticación. Adapty vincula el ID al perfil actual (si el ID es nuevo) o cambia al perfil existente (si el ID ya existe).
- **Los usuarios pueden comprar antes de iniciar sesión**: llama a `identify()` después del login. Si el customer user ID ya existe en Adapty, recupera el perfil a continuación para sincronizar el nivel de acceso actual.
Para más detalles de implementación, consulta la guía del SDK sobre [identificación de usuarios](identifying-users).
:::note
Si un usuario que regresa usaba tu app anteriormente sin un customer user ID, esos perfiles anónimos no se fusionan automáticamente cuando empiezas a identificar en la activación del SDK. Para mantener el historial completo de esos usuarios, usa `identify()` después del inicio de sesión.
:::
## Perfiles padre e hijo \{#parent-and-inheritor-profiles\}
Cuando la misma suscripción de la store está asociada a más de un perfil de Adapty, Adapty trata esos perfiles como una cadena: un perfil **padre** y uno o más perfiles **herederos** que comparten el acceso de la misma compra.
Esto ocurre cuando:
- [El acceso de pago compartido entre cuentas de usuario](sharing-paid-access-between-user-accounts) está habilitado y un usuario inicia sesión en un dispositivo donde un perfil diferente realizó previamente la compra.
- Un usuario reinstala la app sin `customer_user_id`, y el nuevo perfil recoge la compra de la instalación anterior.
- Diferentes usuarios identificados restauran compras en el mismo dispositivo.
- Una app se transfiere entre Team IDs de Apple y la nueva app recoge las compras realizadas con el antiguo Team ID.
**Cómo se selecciona el perfil principal.**
El perfil padre es el **primer perfil en registrar la compra** — determinado por el orden de los recibos de compra en Adapty, no por el orden de creación del perfil. Por ejemplo: instalas la app y no realizas ninguna compra, luego la reinstales y compras una suscripción. El segundo perfil se convierte en el padre porque realizó la compra. El primer perfil se convierte en el heredero y obtiene acceso a través del uso compartido.
**Cómo se distribuyen los eventos:**
- **Eventos transaccionales** (compras, renovaciones, cancelaciones, problemas de facturación, períodos de gracia, reembolsos): Aparecen únicamente en el **perfil principal** que realizó la compra. Todas las renovaciones y actualizaciones de suscripción siguen apareciendo en ese perfil.
- **Eventos `access_level_updated`**: Aparecen en **el perfil principal y en los perfiles herederos** cada vez que cambia el estado del nivel de acceso. Esto mantiene todos los perfiles vinculados al día sobre su estado de acceso actual.
El perfil padre muestra el historial completo de transacciones. Los perfiles herederos solo muestran sus actualizaciones de nivel de acceso y un enlace al perfil padre en la sección **Access level**.
**Seguimiento de la misma suscripción en varios perfiles.**
Cada perfil heredero tiene su propio `profile_id`, por lo que este no es estable a lo largo de una cadena. Para identificar la misma suscripción en varios perfiles —por ejemplo, al reconciliar eventos de webhook o relacionar perfiles del dashboard con un mismo usuario subyacente— utiliza el identificador del lado del store.
| Campo | Usar para |
| --- | --- |
| `store_original_transaction_id` | Identificar una cadena de suscripciones entre perfiles. Único por suscripción de Apple. |
| `profiles_sharing_access_level` (campo de webhook) | Todos los perfiles con nivel de acceso activo gracias a la suscripción, cuando el uso compartido está habilitado. |
| `profile_id` | **No** es adecuado para el seguimiento entre perfiles: cada heredero tiene el suyo propio. |
## Transacciones sin perfil \{#transactions-without-profiles\}
Algunas transacciones en Adapty no están asociadas a ningún perfil: aparecen en los análisis y exportaciones, pero no en la lista de perfiles. Esto ocurre con las **notificaciones S2S (servidor a servidor) del store** recibidas para usuarios cuyas cuentas nunca se conectaron a tu app mediante el SDK de Adapty. Las fuentes conocidas son:
- Notificaciones S2S del App Store (incluidos los eventos de reembolso)
- Notificaciones S2S de Google Play
- Eventos de webhook de Stripe y Paddle
Estas transacciones:
- **Aparecen en los gráficos de análisis** (cuentan para las métricas globales)
- **Aparecen en las exportaciones** (S3, GCS, BigQuery) con `profile_id` establecido como `null`
- **No aparecen en la lista de Perfiles** — no hay ningún perfil al que asociarlos
Si ves más eventos en los análisis o las exportaciones de los que puedes encontrar en la interfaz de Perfiles, la diferencia probablemente se deba a estas transacciones sin perfil. Para encontrarlas en una exportación, filtra las filas donde `profile_id IS NULL`.
## Compartir acceso de pago entre cuentas de usuario \{#sharing-paid-access-between-user-accounts\}
:::link
Artículo principal: [Compartir acceso de pago entre cuentas de usuario](sharing-paid-access-between-user-accounts)
:::
Para configurar tu política de compartición de nivel de acceso, en la página de configuración [**General**](general), selecciona una opción de sharing. Puedes establecer una política separada para el [entorno sandbox](test-purchases-in-sandbox).
**Activado (predeterminado)**
Los usuarios identificados (aquellos con un [Customer User ID](identifying-users#set-customer-user-id-on-configuration)) pueden compartir el mismo [nivel de acceso](access-level) proporcionado por Adapty si su dispositivo está conectado al mismo Apple/Google ID. Esto es útil cuando un usuario reinstala la app e inicia sesión con un correo diferente: seguirá teniendo acceso a su compra anterior. Con esta opción, varios usuarios identificados pueden compartir el mismo nivel de acceso.
Aunque el nivel de acceso se comparte, todas las transacciones pasadas y futuras se registran como eventos en el Customer User ID original para mantener una analítica coherente y conservar un historial completo de transacciones — incluidos períodos de prueba, compras de suscripciones, renovaciones y más, vinculadas al mismo perfil.
**Transferir acceso al nuevo usuario**
Los usuarios identificados pueden seguir accediendo al [nivel de acceso](access-level) proporcionado por Adapty, incluso si inician sesión con un [Customer User ID](identifying-users#set-customer-user-id-on-configuration) diferente o reinstalan la app, siempre que el dispositivo esté conectado al mismo Apple/Google ID.
A diferencia de la opción anterior, Adapty transfiere la compra entre usuarios identificados. Esto garantiza que el contenido adquirido esté disponible, pero solo un usuario puede tener acceso a la vez. Por ejemplo, si UserA compra una suscripción y UserB inicia sesión en el mismo dispositivo y restaura las transacciones, UserB obtendrá acceso a la suscripción y se le revocará a UserA.
Si uno de los usuarios (ya sea el nuevo o el antiguo) no está identificado, el nivel de acceso seguirá compartiéndose entre esos perfiles en Adapty.
Aunque el nivel de acceso se transfiere, todas las transacciones pasadas y futuras se registran como eventos en el Customer User ID original para mantener una analítica coherente y conservar un historial completo de transacciones — incluidos períodos de prueba, compras de suscripciones, renovaciones y más, vinculadas al mismo perfil.
Tras activar **Transferir acceso al nuevo usuario**, los niveles de acceso no se transferirán entre perfiles de forma inmediata. El proceso de transferencia para cada nivel de acceso específico solo se activa cuando Adapty recibe un evento del store, como una renovación de suscripción, una restauración o al validar una transacción.
**Desactivado**
El primer perfil de usuario identificado que obtenga un nivel de acceso lo conservará de forma permanente. Esta es la mejor opción si tu lógica de negocio requiere que las compras estén vinculadas a un único Customer User ID.
Ten en cuenta que los niveles de acceso siguen compartiéndose entre usuarios anónimos.
Puedes "desvincular" una compra [eliminando el perfil del usuario propietario](https://adapty.io/docs/es/api-adapty/operations/deleteProfile). Tras la eliminación, el nivel de acceso queda disponible para el primer perfil de usuario que lo reclame, ya sea anónimo o identificado.
Desactivar el uso compartido solo afecta a los nuevos usuarios. Las suscripciones que ya se comparten entre usuarios seguirán compartiéndose aunque se desactive esta opción.
:::warning
Apple y Google exigen que las compras in-app se compartan o transfieran entre usuarios porque se basan en el Apple/Google ID para asociar la compra. Sin el uso compartido, restaurar las compras podría no funcionar en reinstalaciones posteriores.
Desactivar el uso compartido puede impedir que los usuarios recuperen el acceso después de iniciar sesión.
Recomendamos desactivar el uso compartido solo si tus usuarios **están obligados a iniciar sesión** antes de realizar una compra. De lo contrario, un usuario identificado podría comprar una suscripción, iniciar sesión en otra cuenta y perder el acceso de forma permanente.
:::
### ¿Qué opción debo elegir? \{#which-setting-should-i-choose\}
| Mi app... | Opción a elegir |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| No tiene sistema de inicio de sesión y solo utiliza los IDs de perfil anónimos de Adapty. | Usa la opción predeterminada, ya que los niveles de acceso siempre se comparten entre IDs de perfil anónimos en las tres opciones. |
| Tiene un sistema de inicio de sesión opcional y permite a los clientes realizar compras antes de crear una cuenta. | Elige **Transferir acceso al nuevo usuario** para garantizar que los clientes que compren sin cuenta puedan restaurar sus transacciones más adelante. |
| Requiere que los clientes creen una cuenta antes de comprar, pero permite que las compras estén vinculadas a varios Customer User IDs. | Elige **Transferir acceso al nuevo usuario** para garantizar que solo un Customer User ID tenga acceso a la vez, permitiendo además que los usuarios inicien sesión con un Customer User ID diferente sin perder su acceso de pago. |
| Requiere que los clientes creen una cuenta antes de comprar, con reglas estrictas que vinculan las compras a un único Customer User ID. | Elige **Desactivado** para garantizar que las transacciones nunca se transfieran entre cuentas. |
## Marcas de tiempo de eventos con fechas futuras (Apple/iOS) \{#event-timestamps-with-future-dates-appleios\}
Este comportamiento es exclusivo de la App Store de Apple. El sistema de notificaciones de Google Play no envía eventos con antelación.
Las marcas de tiempo de eventos en los perfiles e integraciones pueden mostrar fechas futuras porque Apple envía los eventos de renovación por adelantado.
- **Por qué ocurre**: Apple hace esto para garantizar que las suscripciones se renueven automáticamente antes de que expiren, evitando interrupciones en el servicio del usuario. Para más detalles, consulta el Apple Developer Forum: [Server Notifications for Subscriptions](https://developer.apple.com/forums/tags/app-store-server-notifications).
- **Tipos de eventos afectados**: Por lo general, esto aplica a las renovaciones de suscripción y las conversiones de prueba a pago. Estos eventos pueden tener marcas de tiempo futuras porque Apple notifica a los sistemas con antelación.
- **Otros tipos de eventos**: Las compras in-app adicionales y los cambios de plan de suscripción se registran con sus marcas de tiempo reales, ya que estos eventos no se pueden predecir con antelación.
- **Impacto en Analytics y el Event Feed**: Estos eventos solo aparecerán en **Analytics** y el **Event Feed** una vez que sus marcas de tiempo hayan pasado. Los eventos con marcas de tiempo futuras no se muestran en ninguna de las dos secciones.
- **Impacto en las integraciones**: Adapty envía los eventos a las integraciones en cuanto los recibe. Si un evento tiene una marca de tiempo futura, Adapty lo envía a tu integración con esa marca de tiempo futura sin modificar.
## Pasos siguientes \{#next-steps\}
- Para usar el dashboard de Profiles para encontrar y gestionar usuarios, consulta [Profiles](profiles-crm).
- Para configurar la identificación de usuarios en tu app, consulta la guía de SDK para [identificar usuarios](identifying-users).
- Para configurar la política de compartición de acceso, consulta [Compartir acceso de pago entre cuentas de usuario](sharing-paid-access-between-user-accounts).
---
# File: sharing-paid-access-between-user-accounts
---
---
title: "Compartir acceso de pago entre cuentas de usuario"
description: "Cómo compartir el acceso de pago entre diferentes cuentas de usuario para usuarios con varios dispositivos o múltiples perfiles en la app"
---
Cuando un usuario realiza una compra, Adapty asigna un nuevo [nivel de acceso](access-level) a su [perfil](identifying-users) activo. Este nivel de acceso autoriza al comprador a acceder al contenido de pago.
El perfil del comprador puede cambiar involuntariamente si reinstala la app o inicia sesión en una nueva cuenta dentro de la app. Para garantizar un acceso ininterrumpido, Adapty comparte automáticamente el nivel de acceso del usuario entre el perfil original y los que le siguen.
Este enfoque funciona bien para la mayoría de las aplicaciones. Sin embargo, si tu lógica de negocio lo requiere, puedes seleccionar una política de compartición de acceso de pago más restrictiva.
Abre la página de [General Settings](https://app.adapty.io/settings/general) para configurar una política de compartir niveles de acceso. Para facilitar las pruebas, puedes cambiar esta configuración solo para el [entorno sandbox](#sharing-paid-access-on-sandbox).
## Habilitado (por defecto) \{#enabled-default\}
Esta configuración funciona mejor para aplicaciones **sin autenticación integrada**. Tras la compra, todos los perfiles asociados a la misma cuenta del store heredan automáticamente el nivel de acceso.
* Si un usuario inicia sesión en tu app con un nuevo conjunto de credenciales, conserva el acceso al contenido de pago.
* Si un usuario reinstala tu aplicación tras un restablecimiento de fábrica, conserva el acceso al contenido de pago.
* Si un usuario instala la aplicación en otros dispositivos con la misma cuenta de la store, la compra estará disponible en todos los dispositivos, incluso si cada instancia de la aplicación tiene su propio perfil de cliente.
## Transferir el acceso a un nuevo usuario \{#transfer-access-to-new-user\}
Esta configuración es ideal para aplicaciones que permiten compras **con o sin autenticación**, o que quieren aplicar una política de **un dispositivo por usuario**.
Adapty limita el acceso a las compras a 1 customer ID a la vez. El propietario del dispositivo puede reinstalar la app, iniciar y cerrar sesión, pero no puede acceder al mismo producto desde más de un customer ID al mismo tiempo.
Con esta opción activada, los perfiles anónimos (por ejemplo, un perfil que se activa cuando el usuario cierra sesión) siempre heredan el nivel de acceso del último ID de cliente activo. Esto es necesario para evitar que se pierda el acceso más adelante.
:::warning
Cuando desactivas la configuración predeterminada y activas **Transfer access to new user**, Adapty no actualiza inmediatamente los niveles de acceso de los perfiles de cliente existentes.
El cambio se produce cuando el usuario genera un nuevo evento en el store: por ejemplo, renueva la suscripción o restaura sus compras.
:::
:::important
Adapty revoca el perfil antiguo solo cuando el nuevo perfil tiene un [Customer User ID](identifying-users#set-customer-user-id-on-configuration) en el momento en que el SDK propaga la transacción. Si `restorePurchases` se ejecuta en un perfil anónimo, tanto el antiguo Customer User ID como el nuevo perfil anónimo obtendrán el nivel de acceso. El perfil antiguo se revoca más adelante, cuando identificas el perfil anónimo.
Para evitarlo, llama a los métodos del SDK en este orden: `activate` → `identify` → `restorePurchases`.
:::
## Desactivar el acceso compartido de pago \{#disable-paid-access-sharing\}
Esta configuración **solo es adecuada** para aplicaciones con **autenticación obligatoria** o una implementación propia de gestión de accesos. En cualquier otro caso, los usuarios podrían no poder acceder a sus compras, y tu aplicación corre el riesgo de **no superar la revisión obligatoria del store**.
Si deshabilitas el acceso compartido de pago, Adapty vincula el producto al [ID de cliente](identifying-users#set-customer-user-id-on-configuration) activo en el momento de la compra y no comparte el nivel de acceso con ningún otro perfil. Esta política permite una distribución estricta de productos en proporción 1 a 1.
:::warning
Al deshabilitar el acceso compartido de pago, impides que los IDs de cliente hereden el acceso de pago. Si un ID de cliente ya heredó acceso de pago en el pasado, ese acceso no se puede revocar automáticamente.
:::
:::important
En situaciones de emergencia, puede que necesites [eliminar un perfil de usuario](api-adapty/operations/deleteProfile) para que el siguiente perfil disponible (ya sea identificado o anónimo) pueda reclamar su nivel de acceso.
:::
## Referencia práctica \{#practical-reference\}
Una vez elegido un modo, los contratos a continuación describen qué esperar: qué perfiles verán el acceso, cuándo lo pierde el perfil anterior y qué eventos de webhook se disparan.
| Modo | ¿Varios perfiles comparten una compra? | ¿Se revoca el perfil antiguo al transferir? | Cuándo se revoca el perfil antiguo | Eventos de webhook cuando un segundo perfil reclama la suscripción |
| --- | --- | --- | --- | --- |
| **Habilitado (por defecto)** | Sí — todos los perfiles que restauran o inician sesión heredan el acceso | Nunca | N/A | `access_level_updated` (`is_active=true`) por cada nuevo perfil que hereda |
| **Transferir acceso al nuevo usuario** | No — exclusivo, pero se puede mover entre perfiles | Sí | Inmediatamente cuando el nuevo dispositivo identificado propaga la transacción (`restorePurchases`, identify, o el siguiente evento del store) | Perfil nuevo: `access_level_updated` (`is_active=true`). Perfil antiguo: `access_level_updated` (`is_active=false`) |
| **Deshabilitado** | No — un Customer User ID por compra, de forma permanente | N/A — el acceso nunca se transfiere | N/A | Ninguno en el segundo perfil. El SDK no muestra acceso para ese perfil |
## Compartir acceso de pago en sandbox \{#sharing-paid-access-on-sandbox\}
Puedes establecer una política de compartición de acceso de pago específicamente para el entorno sandbox. Al probar compras en sandbox, ten en cuenta el siguiente comportamiento:
* Apple almacena información sobre tus compras anteriores en el historial de compras de la cuenta. El SDK de Adapty también puede acceder a él.
* Si reinstalaas la aplicación y Adapty detecta que el producto ya fue comprado, el perfil activo heredará el nivel de acceso.
* Si Apple detecta una compra existente para el producto, no permitirá realizar la misma compra dos veces, aunque el perfil activo no tenga el nivel de acceso necesario.
Este comportamiento se produce **independientemente de la configuración de acceso de pago compartido**. Si tu app no muestra el paywall, no puedes comprar el producto. La única solución es **borrar el historial de compras de tu cuenta**. Consulta la [guía de pruebas en sandbox](test-purchases-in-sandbox) para obtener instrucciones detalladas.
:::warning
Las suscripciones sandbox en Apple se renuevan automáticamente cada pocos minutos. Estas renovaciones rápidas pueden cambiar qué perfil trata Adapty como [principal](how-profiles-work#parent-and-inheritor-profiles) — un patrón de cadena que raramente se reproduce en producción. Prueba el modo que usas en producción y confirma el comportamiento con un Apple ID real antes de sacar conclusiones del sandbox.
:::
## Compartición de acceso de pago en los análisis \{#paid-access-sharing-in-analytics\}
* Adapty registra las transacciones a medida que se producen. Una misma transacción puede estar asociada a más de un perfil, pero no se contabiliza más de una vez.
* Si dos o más perfiles comparten el mismo nivel de acceso, la compra se atribuye al [perfil principal](how-profiles-work#parent-and-inheritor-profiles).
* La herencia del nivel de acceso no afecta a las estadísticas de instalación. Para saber cómo Adapty contabiliza las instalaciones, puedes seleccionar una de las dos [definiciones de instalación](installs#calculation) disponibles en la página de configuración.
---
# File: segments
---
---
title: "Segmentos"
description: "Crea y gestiona segmentos de usuarios para una mejor segmentación en Adapty."
---
Un **segmento** es un conjunto de filtros que agrupa usuarios con características comunes. Usa segmentos para dirigir paywalls y pruebas A/B de forma más efectiva.
:::note
Los eventos del feed de eventos llegan al dashboard con un retraso. Los nuevos perfiles y los cambios de atributos pueden no ser visibles de inmediato.
:::
Después de crear un segmento, puedes [usarlo como **audiencia** en Placements y pruebas A/B](audience) para controlar qué paywall ven los usuarios (uno o varios). Ejemplos:
- Muestra un paywall estándar a los no suscriptores y ofrece un descuento a los usuarios que hayan cancelado previamente una suscripción o prueba.
- Muestra paywalls diferentes a usuarios de distintos países.
- Segmenta usuarios basándote en datos de atribución de Apple Search Ads.
- Asegúrate de que los usuarios en versiones antiguas de la app sigan viendo el paywall actual, mientras que las versiones más recientes reciban el actualizado.
- [En Analytics](controls-filters-grouping-compare-proceeds#filter-and-group-data), filtra por segmentos para ver el rendimiento de grupos de usuarios específicos. Agrupa por segmento para comparar el rendimiento o la contribución dentro de **All users**.
## Creación \{#creation\}
Para crear un segmento, introduce un nombre y selecciona los atributos que definen sus filtros. Si seleccionas varios atributos, los usuarios deben cumplir todas las condiciones. Adapty aplica lógica AND entre atributos.
## Atributos disponibles \{#available-attributes\}
:::note
Aunque muchos atributos de usuario se establecen automáticamente (como **Country** o **Calculated total revenue USD**), los atributos **Age**, **App user ID**, **Attribution**, **Gender** y **Custom attributes** no se definen automáticamente. Debes [establecer los atributos de usuario](setting-user-attributes) o [pasar los datos de atribución](attribution-integration) si quieres usarlos para segmentación.
:::
:::tip
Para los atributos basados en fechas, puedes filtrar usando:
- **Fecha fija**: Selecciona fechas concretas en un calendario (por ejemplo, mostrar una oferta especial a usuarios que instalaron la app entre el Black Friday y el Cyber Monday)
- **Rango relativo**: Define ventanas de tiempo dinámicas como "Últimos 7 días" o "Últimos 3 meses" (por ejemplo, volver a captar usuarios que no se han visto en más de 30 días, o apuntar a instalaciones recientes)
Los rangos relativos se actualizan automáticamente, lo que los hace ideales para campañas continuas. Las fechas fijas funcionan mejor para promociones acotadas en el tiempo.
:::
| Atributo | Filtrar por |
|---------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Age** | La edad del usuario. Ten en cuenta que la edad se calcula cuando Adapty la recibe por primera vez y no se actualiza posteriormente. |
| **App User ID** | El identificador del usuario en tu app ([customer_user_id](profiles-crm#user-attributes)). Puedes filtrar por su presencia o ausencia, por ejemplo, para mostrar un paywall solo a usuarios que no han iniciado sesión. |
| **App version (current)** | La versión actual de la app instalada en el dispositivo del usuario donde Adapty recibió datos de eventos por última vez — **se actualiza a medida que el usuario actualiza la app**, por lo que siempre refleja la versión que está usando en este momento. Úsalo cuando quieras llegar a todos los usuarios que ejecutan una versión específica, incluidos los que actualizaron desde una versión anterior. Al crear un segmento, selecciona el icono de lápiz junto a **App version** y añade una nueva versión para poder usarla de inmediato.
| Campo | Descripción |
| ------ |--------------------------------------------------------------------------------------------------------------------------------------|
| **Name** | Una etiqueta para el atributo personalizado, usada solo en el Adapty Dashboard. |
| **Key** | Un identificador único para el atributo. Debe coincidir con la clave utilizada en el SDK. |
| **Type** | Elige entre:
## Duplicar segmentos \{#duplicate-segments\}
Si necesitas un segmento similar a uno existente, duplícalo en lugar de crearlo desde cero. Esto ahorra tiempo a los equipos que gestionan varias campañas o pruebas A/B con grupos de usuarios que se solapan.
Duplicar un segmento crea una copia con todos sus filtros y descripción. Al nombre del nuevo segmento se le añade "(copy)" para que puedas distinguirlo del original. El nuevo segmento es independiente del original: los cambios en uno no afectan al otro.
Para duplicar un segmento en el Adapty Dashboard:
1. Abre la sección **Profiles & Segments** en el menú principal de Adapty y cambia a la pestaña [**Segments**](https://app.adapty.io/segments).
2. Haz clic en el botón de **3 puntos** junto al segmento y selecciona **Duplicate**.
3. Abre el nuevo segmento y ajusta sus filtros según sea necesario.
## Eliminar segmentos \{#delete-segments\}
Cuando ya no necesites un segmento, puedes eliminarlo de forma permanente.
Adapty bloquea la eliminación si el segmento se está usando como audiencia en alguno de los siguientes casos:
- **Un placement**: Al menos un placement no eliminado usa el segmento como audiencia.
- **Una prueba A/B (activa o completada)**: Al menos una prueba A/B no eliminada usa el segmento como audiencia.
Para eliminar segmentos, Adapty considera como activas tanto las pruebas A/B **Live** como las **Completed**. Una prueba completada sigue utilizando la audiencia para mostrar el paywall o onboarding posterior a la prueba a los usuarios que coincidan, y las métricas históricas de la prueba están vinculadas a ese segmento. El segmento solo se libera cuando se elimina la propia prueba A/B.
:::warning
La eliminación de un segmento es permanente. El segmento no se puede restaurar.
:::
Para eliminar un segmento en el Adapty Dashboard:
1. Ve a **Profiles & Segments** en el menú principal de Adapty y cambia a la pestaña [**Segments**](https://app.adapty.io/segments).
2. Haz clic en el botón de **3 puntos** junto al segmento y selecciona **Delete**.
3. Escribe el nombre del segmento en el campo de confirmación y haz clic en **Delete forever**.
:::info
Si el segmento está en uso, el cuadro de diálogo muestra los placements y las pruebas A/B que lo referencian.
Para desbloquear la eliminación, abre cada placement o prueba A/B de la lista y elimina el segmento de su audiencia, o elimina el placement o la prueba A/B por completo. Una vez que nada haga referencia al segmento, podrás eliminarlo.
:::
---
# File: event-feed
---
---
title: "Feed de eventos"
description: "Monitoriza y analiza la actividad de los usuarios con el feed de eventos de Adapty."
---
El feed de eventos te permite hacer un seguimiento visual de los [Eventos](events) generados por Adapty y comprobar el estado de su exportación a integraciones de terceros, incluido el webhook.
:::warning
El Feed de Eventos no muestra:
- **Transacciones de la API server-side v1**: Creadas usando la [API server-side (versión 1)](server-side-api-specs-legacy#requests). Usa la [API server-side (versión 2)](api-adapty/operations/setTransaction) en su lugar para que aparezcan.
- **Eventos sin perfil**: Transacciones que llegaron antes de que el SDK identificara a un usuario — por ejemplo, notificaciones del servidor de la store. Para incluirlas en las exportaciones, activa **Include events without profile** en la integración de [S3](s3-exports) o [Google Cloud Storage](google-cloud-storage).
:::
:::note El estado de envío de AppsFlyer, Facebook Ads y Branch puede ser inexacto porque no siempre devuelven errores cuando se producen. ::: Para ver el perfil del usuario que ha iniciado la transacción, haz clic en el botón **View Profile** en los detalles del evento. --- # File: ab-tests --- --- title: "Prueba A/B" description: "Optimiza los precios de suscripción con pruebas A/B en Adapty para mejorar las tasas de conversión." --- :::tip Puedes obtener un plan de prueba A/B accionable sin tener que hacer la investigación tú mismo. [AI Growth Advisor](autopilot) analiza tu paywall, compara a tus competidores y genera sugerencias a partir de datos anonimizados de 20.000 apps de suscripción rastreadas por Adapty. ::: Aumenta los ingresos de tu app ejecutando pruebas A/B en Adapty. Compara distintos flows, paywalls y onboardings para descubrir qué convierte mejor, sin necesidad de cambiar el código. Por ejemplo, puedes probar: - Precios de suscripción - Diseño, textos y estructura del paywall - Períodos de prueba y duraciones de suscripción - Diseños de onboarding ## Requisitos previos \{#prerequisites\} Antes de configurar una prueba A/B, necesitas tener: - **Placements**: Uno o más [placements](placements) donde se muestre un flow, un paywall o un onboarding. - **Para flows**: Al menos dos [flows](adapty-flow-builder). - **Para paywalls**: Al menos dos [paywalls](paywalls). - **Para onboardings**: Al menos dos [onboardings](onboardings). :::warning Si no estás usando el [Adapty Flow builder](adapty-flow-builder) o el [Adapty Paywall builder](adapty-paywall-builder), [envía las vistas de paywall a Adapty](present-remote-config-paywalls#track-paywall-view-events) con `.logShowFlow()` (iOS SDK v4+) / `.logShowPaywall()`. Sin este método, Adapty no puede calcular las vistas de paywall en la prueba, y las estadísticas de conversión serán inexactas. ::: ## Tipos de prueba A/B \{#ab-test-types\} Adapty admite tres tipos de prueba A/B: - **Regular**: Se ejecuta en un único placement de paywall. - **Onboarding**: Se ejecuta en un único placement de onboarding. - **Crossplacement**: Se ejecuta en múltiples placements de paywall, mostrando la misma variante al usuario en todos ellos. Para una comparación completa de tipos, casos de uso y reglas de prioridad, consulta [Tipos de prueba A/B](ab-test-types). ## Próximos pasos \{#next-steps\} - [AI Growth Advisor](autopilot) — Analiza tu paywall, obtén información del mercado y genera un plan de prueba A/B - [Tipos de prueba A/B](ab-test-types) — Aprende sobre los tipos de prueba y cuándo usar cada uno - [Crear, ejecutar y detener una prueba A/B](run_stop_ab_tests) — Configura y ejecuta tu primera prueba - [Resultados y métricas de la prueba A/B](results-and-metrics) — Entiende los datos de tu prueba A/B y elige un ganador --- # File: ab-test-types --- --- title: "Tipos de prueba A/B" description: "Aprende sobre los tipos de prueba A/B en Adapty." --- Adapty ofrece dos tipos de prueba A/B, cada uno pensado para distintos escenarios de prueba: - **Prueba A/B regular:** Una prueba A/B creada para un único placement de [flow](adapty-flow-builder)/[paywall](paywalls)/[onboarding](onboardings). - **Prueba A/B multiplacement:** Una prueba A/B creada para varios placements de paywall en tu app. Una vez que la prueba A/B asigna una
## Diferencias clave \{#key-differences\}
| Característica | Prueba A/B Regular | Prueba A/B Crossplacement |
| ------------------------------- |----------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|
| **Qué se prueba** | Un flow/paywall/onboarding | Conjunto de paywalls pertenecientes a una variante |
| **Consistencia de variante** | La variante se determina de forma independiente para cada placement | La misma variante se usa en todos los placements de paywalls |
| **Segmentación de audiencia** | Definida por placement de flow/paywall/onboarding | Compartida en todos los placements de paywalls |
| **Analíticas** | Analizas un placement de flow/paywall/onboarding | Analizas toda la app en los placements que forman parte de la prueba |
| **Distribución de peso de variante** | Por flow/paywall/onboarding | Por conjunto de paywalls |
| **Usuarios** | Para todos los usuarios | Solo usuarios nuevos (los que no han visto un paywall de Adapty) |
| **Versión del SDK de Adapty** | Para flows: v4.0.0+. Cualquiera para paywalls. Para onboardings: v3.8.0+ (iOS, Android, React Native, Flutter), v3.14.0+ (Unity), v3.15.0+ (KMP, Capacitor) | 3.5.0+ |
| **Ideal para** | Probar cambios independientes en un único placement de flow/paywall/onboarding sin tener en cuenta la economía global de la app | Evaluar estrategias de monetización globales en toda la app |
## Lógica de selección de pruebas A/B \{#ab-test-selection-logic\}
**Las pruebas A/B Crossplacement tienen prioridad sobre las pruebas A/B normales.** Sin embargo, las pruebas Crossplacement solo se muestran a **nuevos usuarios** — aquellos que aún no han visto ningún paywall de Adapty (el método `getPaywall` del SDK nunca ha sido llamado para ellos). Esto garantiza la coherencia de los resultados entre placements.
El siguiente diagrama muestra la lógica que utiliza Adapty para seleccionar una prueba A/B para un placement:
En la página **A/B Tests**, las pruebas de paywall, onboarding, flow y Crossplacement aparecen en pestañas separadas.
## Limitaciones de las pruebas A/B multiplacement \{#crossplacement-ab-test-limitations\}
:::warning
Las pruebas A/B multiplacement no pueden incluir placements de flow ni de onboarding.
:::
Las pruebas A/B multiplacement garantizan que cada usuario vea la misma variante en todos los placements incluidos en la prueba. Esto genera las siguientes limitaciones:
* Solo pueden participar usuarios nuevos. Un usuario nuevo es aquel que no ha visto ningún paywall de Adapty y cuya app nunca ha llamado a `getPaywall`. Adapty no puede garantizar una cadena de paywalls coherente para el resto de usuarios.
* El primer placement que el usuario encuentre determina qué paywall muestra Adapty. No es posible cambiar la asignación de un usuario ni inscribir al mismo usuario en más de una prueba A/B Cross-placement.
:::warning
Una vez que un usuario recibe un paywall Cross-placement, lo verá durante 90 días, incluso después de detener la prueba. Para cambiar esta duración, en los ajustes de **General**, modifica **[Cross-placement variation stickiness](general#9-cross-placement-variation-stickiness)**.
:::
## Prioridad de las pruebas A/B entre placements \{#crossplacement-ab-test-priority\}
* Las pruebas A/B entre placements siempre tienen prioridad sobre las pruebas A/B regulares y de onboarding. Si un nuevo usuario cumple los requisitos tanto de una prueba entre placements como de una prueba regular en el mismo placement, se mostrará la prueba entre placements.
* Cuando varias pruebas A/B entre placements con la misma audiencia comparten el mismo placement, Adapty asigna automáticamente la prioridad de las pruebas según el orden en que se añadieron. La primera prueba recibe la mayor prioridad. No es posible cambiarla manualmente.
* Las pruebas que se dirigen a segmentos más pequeños de tu audiencia tienen prioridad automáticamente sobre las que se dirigen al segmento de todos los usuarios.
:::note
En Analytics, una prueba A/B Crossplacement aparece como varias pruebas secundarias, una por placement. Las pruebas secundarias siguen el patrón de nomenclatura `
2. En la esquina superior derecha, haz clic en **Create A/B test**.
3. En la ventana **Create the A/B test**, introduce un **Test name**. Este campo es obligatorio. Elige un nombre que describa claramente el objetivo de la prueba para que puedas identificarla al revisar los resultados.
4. Rellena el campo **Test goal** para describir qué quieres conseguir (por ejemplo, aumentar las suscripciones o reducir la cancelación).
5. Haz clic en **Select placement** y elige un placement de flow, paywall u onboarding.
6. Configura el contenido de la prueba en la tabla **Variants**. Cada fila es una variante y cada columna es un placement. Añade un paywall en cada intersección.
Por defecto, la tabla tiene 2 variantes y 1 placement. Puedes añadir hasta 20 variantes. Si añades un segundo placement, la prueba se convierte en una prueba A/B de cross-placement. Ten en cuenta que las pruebas A/B de cross-placement solo están disponibles para paywalls.
7. Guarda tu prueba. Tienes dos opciones:
1. **Save as draft**: La prueba no se publicará de inmediato. Puedes lanzarla más tarde desde el placement o la lista de pruebas A/B. Úsala para revisar la configuración antes del lanzamiento.
2. **Run A/B test**: Lanza la prueba de inmediato. La prueba se pone en marcha en cuanto haces clic en este botón.
Una vez guardada como borrador, continúa en [Ejecutar una prueba A/B](#run-an-ab-test).
## Editar una prueba A/B \{#edit-an-ab-test\}
Solo puedes editar las pruebas A/B que están guardadas como borradores. Una vez que la prueba está activa, no se puede modificar. Para actualizar una prueba en curso, usa la opción **Modify** — esto crea un duplicado con el mismo nombre donde puedes hacer cambios. Adapty detiene la prueba original, y tanto la versión original como la modificada aparecen por separado en tus analíticas.
## Ejecutar una prueba A/B \{#run-an-ab-test\}
Ejecutar una prueba A/B en Adapty significa asignarla a un placement para que empiece a mostrar paywalls y onboardings a los usuarios.
1. Ve a la sección [Pruebas A/B](ab-tests) desde el menú principal de Adapty.
2. Asegúrate de estar viendo la lista correcta: las pruebas A/B de **Paywall**, **Flow**, **Onboardings** y **Crossplacement** se muestran en pestañas separadas entre las que puedes alternar.
3. Cambia a la pestaña **Drafts**. Solo se pueden iniciar las pruebas en borrador.
4. Junto a la prueba que quieres lanzar, haz clic en **Run A/B test**.
5. Se abre la ventana **Edit A/B test**. Revisa la configuración y realiza los últimos cambios que necesites. Si falta el placement o la audiencia, agrégalos ahora.
6. Tras revisar la configuración, haz clic en **Run A/B test** para comenzar.
Después de lanzar la prueba, puedes hacer un seguimiento de su progreso y ver los datos de rendimiento en la página [Resultados y métricas de la prueba A/B](results-and-metrics).
## Detener una prueba A/B \{#stop-an-ab-test\}
Cuando detienes una prueba A/B, esta finaliza y puedes revisar los resultados. También decides qué mostrar a los usuarios en los placements afectados una vez que concluya la prueba.
1. Abre la sección [A/B tests](https://app.adapty.io/ab-tests) y ve a la pestaña **Live**.
2. Junto a la prueba que quieres detener, haz clic en el menú de tres puntos y elige **Stop A/B test**.
3. En la ventana **Stop the A/B test**, decide qué debe ocurrir cuando termine la prueba. Tienes tres opciones:
| Opción | Descripción |
|----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Mostrar uno de los paywalls/onboardings probados | Elige el paywall u onboarding ganador según los resultados de la prueba, como ingresos, probabilidad de ser el mejor (**P2BB**) e ingresos por cada 1000 usuarios. Este paywall u onboarding se mostrará para el placement y la audiencia seleccionados. |
| Seleccionar paywalls/onboardings que no participan en la prueba A/B | Elige cualquier paywall u onboarding que no forme parte de la prueba A/B actual. Usa esta opción cuando ninguna de las variantes probadas haya cumplido tus objetivos. |
| No mostrar ningún paywall/onboarding específico | Para el placement y la audiencia seleccionados, no se seleccionará ningún paywall u onboarding específico al finalizar la prueba A/B. En su lugar, se mostrará el siguiente paywall u onboarding disponible según la prioridad de la audiencia. Es una buena opción si prefieres dejar que tu configuración actual decida qué paywall u onboarding mostrar, sin seleccionar uno manualmente. |
:::note
Detener una prueba A/B es irreversible: no se puede reiniciar. Asegúrate de haber recopilado suficientes datos antes de decidir detenerla.
:::
4. Haz clic en el botón **Stop and complete this A/B test**.
Una vez finalizada la prueba A/B, dejará de estar activa y los paywalls u onboardings asociados dejarán de mostrarse a nuevos usuarios.
Puedes seguir consultando los resultados y métricas de la prueba A/B en la [página de métricas de pruebas A/B](results-and-metrics#metrics-controls) para revisar el rendimiento de los usuarios que participaron mientras la prueba estaba activa. Las métricas pueden seguir actualizándose a medida que se atribuyen nuevos eventos de compra o ingresos a esos usuarios.
---
# File: ab-test-no-paywall-variants
---
---
title: "Añadir variantes de prueba A/B sin paywalls"
description: "Ejecuta una prueba A/B donde una variante omite el paywall, usando una bandera de Remote Config para controlar si el paywall se muestra."
---
Puedes medir el impacto de tu paywall ejecutando una prueba A/B contra una variante vacía. Una variante muestra tu paywall; la otra no muestra nada. Tu app lee una bandera del Remote Config del paywall para decidir si renderizarlo.
## Cómo funciona \{#how-it-works\}
La configuración usa dos paywalls en el mismo placement:
- **Paywall A**: El paywall que quieres probar, con `show_paywall` establecido en `true` en su Remote Config.
- **Paywall B**: Un paywall vacío con `show_paywall` establecido en `false` en su Remote Config.
Cuando `getPaywall` devuelve un paywall, tu app lee la bandera `show_paywall`. Si la bandera es `true`, la app renderiza el paywall. Si la bandera es `false`, la app omite el renderizado y el usuario continúa sin ver un paywall.
## 1. Añade el flag show_paywall en el Remote Config \{#1-add-the-show_paywall-flag-in-remote-config\}
Necesitas dos flows o paywalls en el mismo placement: Flow/Paywall A (el que quieres probar) y Flow/Paywall B (uno vacío). Añade un campo `show_paywall` a cada uno para que tu app pueda ramificar en la misma clave para ambas variantes.
Para añadir el flag al Flow/Paywall A:
1. Abre la sección [**Flows**](https://app.adapty.io/flows)/[**Paywalls**](https://app.adapty.io/paywalls) en el menú principal de Adapty y selecciona el Flow/Paywall A.
2. Abre la sección **Remote config**.
3. Crea un campo con el nombre `show_paywall` y el valor `true`. En la vista **JSON**, la entrada queda así:
```json showLineNumbers
{
"show_paywall": true
}
```
4. Guarda los cambios.
Repite los mismos pasos para el Flow/Paywall B, pero establece `show_paywall` en `false`.
Para obtener todos los detalles sobre Remote Config, consulta [Personalizar el flow con Remote Config](customize-flow-with-remote-config) o [Diseñar el paywall con Remote Config](customize-paywall-with-remote-config).
:::tip
Establecer `show_paywall` en ambas variantes mantiene la ruta de código idéntica para ambos grupos y facilita extender la prueba con más variantes más adelante.
:::
## 2. Configura la prueba A/B \{#2-set-up-the-ab-test\}
1. [Crea una prueba A/B](run_stop_ab_tests) en el placement y añade ambos paywalls como variantes.
2. Establece los pesos de las variantes para distribuir el tráfico entre los usuarios que ven el paywall y los que no.
## 3. Comprueba la flag en tu app \{#3-check-the-flag-in-your-app\}
Lee `show_paywall` desde el Remote Config devuelto por el SDK. Si la flag es `false`, omite el renderizado y deja que el usuario continúe.
:::note
Adapty convierte otras divisas a USD según el tipo de cambio de [currencylayer.com](https://currencylayer.com/) (actualizado cada 8 horas). El tipo de cambio se **fija en el momento de la transacción** — los cambios futuros no afectan al resultado de la conversión.
:::
**Ingresos**: Esta métrica muestra el importe total en USD generado por compras y renovaciones, menos los reembolsos realizados a usuarios. Incluye tanto la compra inicial como las renovaciones posteriores de suscripciones. Los ingresos te ayudan a entender el rendimiento financiero de cada variante de la prueba A/B y a identificar cuál genera más dinero.
Obtén más información sobre las métricas de [paywall](paywall-metrics).
**Probabilidad de ser el mejor**: Adapty utiliza un sólido marco de análisis matemático para analizar los resultados de las pruebas A/B y proporciona una métrica llamada Probabilidad de ser el mejor. Esta métrica evalúa la probabilidad de que una variante concreta sea la opción con mejor rendimiento (en términos de ingresos a largo plazo) entre todas las variantes probadas. La métrica se expresa como un valor porcentual que oscila entre el 1% y el 100%. Para más información sobre cómo Adapty calcula esta métrica, consulta la [documentación.](maths-behind-it) La opción con mejor rendimiento, determinada por los ingresos por cada 1000 usuarios, se resalta en verde y se selecciona automáticamente como opción predeterminada.
**Ingresos por 1000 usuarios**: La métrica de ingresos por 1000 usuarios calcula los ingresos medios generados por cada 1000 usuarios en cada variante de la prueba A/B. Esta métrica te ayuda a entender la eficiencia de ingresos de tus variantes, independientemente del número total de usuarios. Te permite comparar el rendimiento de distintas variantes en una escala estandarizada y tomar decisiones informadas basadas en la eficiencia de generación de ingresos.
**Intervalos de predicción para los ingresos por 1.000 usuarios**: La métrica de ingresos por 1.000 usuarios también incluye intervalos de predicción. Estos intervalos representan el rango dentro del cual se predice que caerán los ingresos reales por 1.000 usuarios para una variante determinada, según los datos disponibles y el análisis estadístico.
En el contexto de las pruebas A/B, al analizar los ingresos generados por las distintas variantes, calculamos los ingresos medios por cada 1.000 usuarios para cada variante. Dado que los ingresos pueden variar entre usuarios, los intervalos de predicción ofrecen una indicación clara de los valores plausibles para los ingresos por 1.000 usuarios, teniendo en cuenta la variabilidad y la incertidumbre asociadas al proceso de predicción.
Al incorporar intervalos de predicción en la métrica de ingresos por cada 1000 usuarios, Adapty te permite evaluar la eficiencia de ingresos de las variantes de tu prueba A/B teniendo en cuenta el rango de posibles resultados de ingresos. Esta información te ayuda a tomar decisiones basadas en datos y a optimizar tu estrategia de suscripción de forma eficaz, considerando la incertidumbre en el proceso de predicción y los valores plausibles de ingresos por cada 1000 usuarios.
Al analizar estas métricas que ofrece Adapty, puedes obtener información sobre el rendimiento financiero, la significancia estadística y la eficiencia de ingresos de las variantes de tu prueba A/B, lo que te permite tomar decisiones basadas en datos y optimizar tu estrategia de suscripción de manera efectiva.
## Métricas de la prueba A/B \{#ab-test-metrics\}
Adapty ofrece un conjunto completo de métricas para ayudarte a medir con eficacia el rendimiento de tus pruebas A/B realizadas en variantes de paywall u onboarding. Estas métricas se actualizan continuamente en tiempo real, excepto las vistas, que se actualizan de forma periódica. Entender estas métricas te ayudará a evaluar la efectividad de las distintas variantes y a tomar decisiones basadas en datos para optimizar tu estrategia de paywall u onboarding.
Las métricas de las pruebas A/B están disponibles en la lista de pruebas A/B, donde puedes obtener una visión general del rendimiento de todas tus pruebas A/B. Esta vista completa ofrece métricas agregadas para cada variante de prueba, lo que te permite comparar su rendimiento e identificar diferencias significativas. Para un análisis más detallado de cada prueba A/B, puedes acceder a las métricas de detalle de la prueba A/B. Esta sección proporciona métricas en profundidad específicas para la prueba A/B seleccionada, lo que te permite analizar en detalle el rendimiento de cada variante.
Todas las métricas, excepto las vistas, se atribuyen al producto dentro del paywall o onboarding.
## Controles de métricas \{#metrics-controls\}
El sistema muestra las métricas según el período de tiempo seleccionado y las organiza de acuerdo con el parámetro de la columna izquierda con tres niveles de sangría.
### Filtrado por fecha de instalación del perfil \{#profile-install-date-filtration\}
La casilla **Filter metrics by install date** permite filtrar las métricas según la fecha de instalación del perfil, en lugar de los filtros predeterminados que usan la fecha de prueba/compra para las transacciones o la fecha de visualización para las vistas de paywall u onboarding. Al marcar esta casilla, puedes centrarte en medir el rendimiento de adquisición de usuarios para un período específico, alineando las métricas con la fecha de instalación del perfil. Esta opción es útil para personalizar el análisis de métricas según tus necesidades concretas.
### Rangos de tiempo \{#time-ranges\}
Puedes elegir entre un rango de períodos de tiempo para analizar los datos de métricas, lo que te permite centrarte en duraciones específicas como días, semanas, meses o rangos de fechas personalizados.
### Filtros y agrupaciones disponibles \{#available-filters-and-grouping\}
:::link
Artículo principal: [Controles de análisis](controls-filters-grouping-compare-proceeds)
:::
Adapty ofrece herramientas potentes para filtrar y personalizar el análisis de métricas según tus necesidades. En la página de métricas de Adapty tienes acceso a distintos rangos de tiempo, opciones de agrupación y posibilidades de filtrado.
- ✅ Filtrar por: audiencia, atribución, país, paywall, estado del paywall, grupo de paywalls, onboarding, placement, país, store, producto y store del producto.
- ✅ Agrupar por: producto y store.
:::note
Cuando filtras por prueba A/B, las pruebas A/B entre placements aparecen como pruebas secundarias independientes (por ejemplo, `My test child-0`, `My test child-1`), una por placement. Consulta [Limitaciones de las pruebas A/B entre placements](ab-test-types#crossplacement-ab-test-limitations) para más detalles.
:::
## Gráfico de métrica individual \{#single-metrics-chart\}
Uno de los componentes clave de la página de métricas del paywall o del onboarding es la sección de gráficos, que representa visualmente las métricas seleccionadas y facilita su análisis.
El apartado de gráficos de la página de métricas de pruebas A/B incluye un gráfico de barras horizontales que representa visualmente los valores de la métrica seleccionada. Cada barra corresponde a un valor de la métrica y su tamaño es proporcional al dato que representa, lo que facilita interpretar la información de un vistazo. La línea horizontal indica el período de tiempo analizado, y la columna vertical muestra los valores numéricos de las métricas. El valor total de todos los valores de la métrica se muestra junto al gráfico.
Además, al hacer clic en el icono de flecha situado en la esquina superior derecha de la sección del gráfico, se amplía la vista y se muestran las métricas seleccionadas en la línea completa del gráfico.
## Resumen de la prueba A/B \{#ab-test-summary\}
Junto al gráfico de métrica individual, se muestra la sección de resumen de detalles de la prueba A/B, que incluye información sobre el estado, la duración, los placements y otros detalles relacionados con la prueba A/B.
## Definiciones de métricas \{#metrics-definitions\}
Estas son las métricas clave disponibles para las pruebas A/B:
### Ingresos \{#revenue\}
Los ingresos representan el importe total en USD generado a partir de las compras y renovaciones derivadas de la prueba A/B. Incluyen la compra inicial y las renovaciones de suscripción posteriores. La métrica de ingresos se calcula antes de deducir la comisión de App Store o Play Store.
Obtén más información sobre las métricas de [ingresos del paywall](paywall-metrics#revenue).
### CR to purchases \{#cr-to-purchases\}
La tasa de conversión a compras mide la efectividad de tu prueba A/B para convertir vistas en compras reales. Se calcula dividiendo el número de compras por el número de vistas. Por ejemplo, si tuviste 10 compras y 100 vistas, la tasa de conversión a compras sería del 10%.
### CR trials \{#cr-trials\}
La tasa de conversión (CR) a trials es el número de trials iniciados desde la prueba A/B dividido por el número de vistas. La tasa de conversión a trials mide la efectividad de tu prueba A/B para convertir vistas en activaciones de trial. Se calcula dividiendo el número de trials iniciados por el número de vistas.
### Purchases \{#purchases\}
La métrica de compras representa el número total de transacciones realizadas dentro del paywall o el onboarding como resultado de la prueba A/B. Incluye los siguientes tipos de compras:
- Nuevas compras realizadas.
- Conversiones de trials activados.
- Cambios de nivel inferior, superior y cruzados de suscripciones.
- Restauraciones de suscripciones (por ejemplo, cuando una suscripción expira sin renovación automática y se restaura posteriormente).
Ten en cuenta que las renovaciones no están incluidas en la métrica de compras.
### Trials \{#trials\}
La métrica de trials indica el número total de trials activados como resultado de la prueba A/B.
### Trials cancelled \{#trials-cancelled\}
La métrica de trials cancelados representa el número de trials en los que se ha desactivado la renovación automática. Esto ocurre cuando los usuarios cancelan manualmente su suscripción al trial.
### Refunds \{#refunds\}
Los reembolsos de la prueba A/B representan el número de compras y suscripciones reembolsadas específicamente relacionadas con las variaciones probadas.
### Views \{#views\}
Las vistas son el número de visualizaciones de los paywalls o los onboardings que componen la prueba A/B. Si el usuario visita dos veces, se contarán como dos visitas.
### Unique views \{#unique-views\}
Las vistas únicas son el número de visualizaciones únicas del paywall o del onboarding. Si el usuario lo visita dos veces, se contará como una única vista.
### Probability to be the best \{#probability-to-be-the-best\}
La métrica Probability to be the best cuantifica la probabilidad de que una variante específica dentro de una prueba A/B sea la opción de mejor rendimiento entre todos los paywalls u onboardings probados. Proporciona una probabilidad numérica que indica el rendimiento relativo de cada paywall u onboarding. Se expresa como un porcentaje que va del 1% al 100%.
### ARPU (Average revenue per user) \{#arpu-average-revenue-per-user\}
Solo para pruebas A/B de onboarding. Mide el promedio de ingresos generados por cada usuario en un período específico. Se calcula dividiendo los ingresos totales por el número de usuarios únicos.
### ARPPU (Average revenue per paying user) \{#arppu-average-revenue-per-paying-user\}
ARPPU son las siglas de Average Revenue Per Paying User (ingresos medios por usuario de pago) resultantes de la prueba A/B. Se calcula como los ingresos totales divididos por el número de usuarios de pago únicos. Por ejemplo, si has generado 15.000 $ en ingresos de 1.000 usuarios de pago, el ARPPU sería de 15 $.
### ARPAS (Average revenue per active subscriber) \{#arpas-average-revenue-per-active-subscriber\}
ARPAS es una métrica que permite medir el promedio de ingresos generados por suscriptor activo en la ejecución de la prueba A/B. Se calcula dividiendo los ingresos totales por el número de suscriptores que han activado un trial o una suscripción. Por ejemplo, si los ingresos totales son 5.000 $ y tienes 1.000 suscriptores, el ARPAS sería de 5 $. Esta métrica ayuda a evaluar el potencial de monetización promedio por suscriptor.
### Proceeds \{#proceeds\}
La métrica de proceeds para la prueba A/B representa el importe real en USD recibido por el propietario de la app por compras y renovaciones, tras deducir la comisión aplicable de App Store o Play Store. Refleja los ingresos netos específicamente asociados a las variaciones probadas en la prueba A/B, contribuyendo directamente a las ganancias de la app. Para más información sobre cómo se calculan los proceeds, puedes consultar la [documentación](analytics-cohorts#revenue-vs-proceeds) de Adapty.
### Unique subscribers \{#unique-subscribers\}
La métrica de suscriptores únicos representa el recuento de personas distintas que se han suscrito o activado un trial a través de las variaciones de la prueba A/B. Cada suscriptor se contabiliza una sola vez, independientemente del número de suscripciones o trials que inicie.
### Unique paid subscribers \{#unique-paid-subscribers\}
La métrica de suscriptores de pago únicos representa el número de personas únicas que han completado con éxito una compra y se han convertido en suscriptores de pago a través de las variaciones de la prueba A/B.
### Refund rate \{#refund-rate\}
La tasa de reembolso para la prueba A/B se calcula dividiendo el número de reembolsos específicamente asociados a las variaciones de la prueba por el número de primeras compras (las renovaciones quedan excluidas). Por ejemplo, si hay 5 reembolsos y 1.000 primeras compras, la tasa de reembolso sería del 0,5%.
### Unique CR purchases \{#unique-cr-purchases\}
La tasa de conversión única a compras para la prueba A/B se calcula dividiendo el número de compras específicamente asociadas a las variaciones de la prueba por el número de vistas únicas. Por ejemplo, si hay 10 compras y 100 vistas únicas, la tasa de conversión única a compras sería del 10%.
### Unique CR trials \{#unique-cr-trials\}
La tasa de conversión única a trials para la prueba A/B se calcula dividiendo el número de trials iniciados específicamente asociados a las variaciones de la prueba por el número de vistas únicas. Por ejemplo, si hay 30 trials iniciados y 100 vistas únicas, la tasa de conversión única a trials sería del 30%.
### Completions y completions únicos \{#completions--unique-completions\}
Solo para pruebas A/B de onboarding. Los completions cuentan el número de veces que los usuarios completan tu onboarding a través de las variaciones de la prueba A/B, es decir, que pasan de la primera a la última pantalla. Si alguien lo completa dos veces, eso cuenta como dos **completions** pero un único **unique completion**.
### Unique completions rate \{#unique-completions-rate\}
Solo para pruebas A/B de onboarding. El número de completions únicos dividido por el número de vistas únicas. Esta métrica te ayuda a entender cómo interactúan los usuarios con el onboarding a través de las variaciones de la prueba A/B y a realizar cambios si detectas que los usuarios lo ignoran.
---
# File: maths-behind-it
---
---
title: "Las matemáticas detrás de las pruebas A/B"
description: "Entiende las matemáticas detrás del análisis de suscripciones para obtener mejores insights de ingresos."
---
Las pruebas A/B son una técnica muy eficaz para comparar el rendimiento de dos versiones distintas de un flow, un paywall o un onboarding. El objetivo final es determinar cuál de las dos versiones es más eficaz, tomando como referencia el ingreso medio por usuario a lo largo de un período de 12 meses. Sin embargo, esperar un año completo para recopilar datos y tomar decisiones no es práctico. Por eso se utiliza el ingreso por usuario en 2 semanas como métrica proxy, elegida a partir del análisis de datos históricos para aproximar la métrica objetivo. Para obtener resultados precisos y fiables, es fundamental emplear un método estadístico sólido que pueda manejar distintos tipos de datos. La estadística bayesiana, un enfoque muy extendido en el análisis de datos moderno, ofrece un marco flexible e intuitivo para las pruebas A/B. Al incorporar conocimiento previo y actualizarlo con nuevos datos, los métodos bayesianos permiten tomar mejores decisiones en condiciones de incertidumbre. Este documento es una guía completa del análisis matemático que utiliza Adapty para evaluar los resultados de las pruebas A/B y proporcionar información valiosa para la toma de decisiones basada en datos.
## Enfoque de Adapty para el análisis estadístico \{#adaptys-approach-to-statistical-analysis\}
Adapty emplea un enfoque integral de análisis estadístico para evaluar el rendimiento de las pruebas A/B y ofrecer resultados precisos y fiables. Nuestra metodología consta de los siguientes pasos clave:
1. **Definición de la métrica:** Para llevar a cabo una prueba A/B con éxito, es necesario identificar y definir la métrica clave que se alinee con los objetivos específicos del análisis. Adapty aprovechó una gran cantidad de datos históricos de apps de suscripción para determinar cuál encaja mejor como métrica proxy del objetivo a largo plazo —el ingreso promedio tras 1 año— y el resultado es el ARPU a los 14 días.
2. **Formulación de la hipótesis:** Creamos dos hipótesis para la prueba A/B. La hipótesis nula (H0) asume que no existe una diferencia significativa entre el grupo de control (A) y el grupo de prueba (B). La hipótesis alternativa (H1) plantea que sí existe una diferencia significativa entre los dos o más grupos.
3. **Selección de la distribución:** Elegimos la familia de distribución más adecuada en función de las características de los datos y la métrica que observamos. La elección más habitual es la distribución log-normal (teniendo en cuenta los valores cero).
4. **Cálculo de la probabilidad de ser el mejor:** Utilizando el enfoque bayesiano para las pruebas A/B, calculamos la probabilidad de ser la mejor opción para cada variante de paywall u onboarding que participa en el test. Este valor está relacionado con los p-valores que usábamos antes, pero es fundamentalmente un enfoque diferente, más robusto y más fácil de interpretar.
5. **Interpretación de los resultados:** La probabilidad de ser el mejor es exactamente lo que sugiere el nombre. Cuanto mayor sea la probabilidad, mayor será la posibilidad de que una opción concreta sea la mejor elección para la tarea. El umbral para la toma de decisiones debes establecerlo tú mismo; dependerá de muchos otros factores propios de tu situación, pero una elección habitual es el 95%.
6. **Intervalos de predicción:** Adapty calcula intervalos de predicción para las métricas de rendimiento de cada grupo, lo que proporciona un rango de valores dentro del cual es probable que se encuentre el verdadero parámetro poblacional. Esto ayuda a cuantificar la incertidumbre asociada a las métricas de rendimiento estimadas.
## Determinación del tamaño de la muestra \{#sample-size-determination\}
Determinar un tamaño de muestra adecuado es fundamental para obtener resultados fiables y concluyentes en las pruebas A/B. Adapty tiene en cuenta factores como la potencia estadística y el tamaño de efecto esperado —que siguen siendo relevantes incluso con el enfoque bayesiano— para garantizar un tamaño de muestra suficiente. Los métodos de estimación del tamaño de muestra requerido, específicos del enfoque bayesiano que empleamos actualmente, aseguran la fiabilidad del análisis.
Para obtener más información sobre la funcionalidad de las pruebas A/B, te recomendamos consultar nuestra documentación sobre [cómo crearlas](ab-tests) y [cómo ejecutar pruebas A/B](run_stop_ab_tests), así como comprender las distintas [métricas y resultados de las pruebas A/B](results-and-metrics).
El marco analítico de Adapty para las pruebas A/B utiliza ahora un enfoque bayesiano, aunque el foco sigue siendo la definición de métricas, la formulación de hipótesis y la selección de distribuciones. Sin embargo, en lugar de calcular p-valores, ahora calculamos las distribuciones posteriores y la probabilidad de que cada variante sea la mejor. También determinamos los intervalos de predicción. Este enfoque revisado, aunque igualmente exhaustivo e incluso más robusto, está diseñado para ofrecer conclusiones más intuitivas y fáciles de interpretar. El objetivo sigue siendo el mismo: ayudar a las empresas a optimizar sus estrategias, mejorar el rendimiento y crecer a partir de un análisis estadístico sólido de sus pruebas A/B.
---
# File: autopilot-how-it-works
---
---
title: "Asesor de crecimiento con IA: Cómo funciona"
description: "Comprende la lógica del Asesor de crecimiento con IA y confía en nosotros para hacer crecer tus ingresos."
---
[AI Growth Advisor](autopilot) te ayuda a descubrir qué experimentos ejecutar basándose en tus datos de rendimiento reales y en cómo les va a aplicaciones similares en tu mercado. En lugar de adivinar qué podría funcionar, recibes recomendaciones específicas para pruebas con más probabilidades de mejorar tus resultados.
Este artículo ofrece una visión transparente de cómo piensa el AI Growth Advisor: qué datos utiliza, cómo evalúa las oportunidades y por qué aparecen ciertas recomendaciones. El objetivo es que puedas usarlo con confianza como parte de tu flujo de crecimiento.
## Qué hace realmente el Asesor de Crecimiento IA \{#what-ai-growth-advisor-actually-does\}
El Asesor de Crecimiento IA analiza las métricas de tu app y tus paywalls para identificar los experimentos con mayor probabilidad de aumentar tus ingresos. Tiene en cuenta:
- **Tu configuración actual**: precios, pruebas, productos y cómo convierten
- **Patrones del mercado**: cómo estructuran sus ofertas apps similares y qué cobran
- **Tu historial de pruebas**: qué experimentos ya has ejecutado y qué revelaron
- **Potencial de crecimiento**: qué cambios tienen más posibilidades de marcar la diferencia
Growth Advisor utiliza IA para evaluar estos factores de forma conjunta y convertirlos en pruebas A/B que puedes lanzar de inmediato. Obtienes un plan listo para usar sin tener que investigar a la competencia ni adivinar qué probar a continuación.
## Los datos detrás de AI Growth Advisor \{#the-data-behind-ai-growth-advisor\}
Cada recomendación se construye a partir de tres fuentes de datos principales que trabajan juntas.
#### Los datos propios de tu app \{#your-apps-own-data\}
AI Growth Advisor analiza cómo rinde tu app hoy:
- Métricas de conversión en tus paywalls
- Estructura de precios y productos
Esto le da a AI Growth Advisor una base de partida antes de sugerir cualquier cambio.
:::note
No usamos los datos de rendimiento de tu app para entrenar recomendaciones para otras apps. Tus datos son privados.
:::
#### Análisis del paywall \{#paywall-analysis\}
El AI Growth Advisor analiza la captura de pantalla de tu paywall y compara su diseño con los patrones consolidados que utilizan las apps de mayor rendimiento en tu categoría. Evalúa las decisiones de maquetación, el copy, los desglosados de suscripción y los elementos orientados a la conversión, como las etiquetas de ahorro o las secciones de reseñas.
Este análisis genera dos tipos de recomendaciones:
- **Recomendaciones basadas en benchmarks** sobre lo que hacen de forma diferente las apps con mejor rendimiento, cada una respaldada por un dato concreto (por ejemplo, «Usada por el 72% de las apps de Educación con mejor rendimiento»).
- **Recomendaciones de análisis visual** generadas por IA a partir de tu captura de pantalla, que cubren mejoras de copy, cambios de layout y otros ajustes de diseño.
Estas recomendaciones se incorporan directamente a tu [plan de crecimiento](autopilot-growth-plan#view-the-growth-plan) como hipótesis que puedes [lanzar como pruebas A/B](autopilot-execute-plan).
#### Datos de competidores \{#competitor-data\}
AI Growth Advisor compara tu configuración con aplicaciones similares de tu mercado utilizando información pública como precios, estructuras de suscripción y patrones habituales en tu categoría. Estas comparaciones son específicas por país, ya que los precios y las estructuras de la competencia varían según el mercado. Los precios de la competencia provienen de fuentes de terceros y públicas como la App Store, que son distintas de los datos anonimizados de la red de Adapty que utiliza el análisis de métricas.
De esta forma, estás probando estrategias que ya funcionan en apps similares a la tuya, no ideas al azar. Al ver el análisis, puedes comparar tus métricas de referencia y los precios de la competencia uno al lado del otro. Si apps similares obtienen mejores resultados con una estructura de precios diferente, es una buena señal de que el mismo enfoque podría funcionar también para ti.
:::tip
AI Growth Advisor selecciona automáticamente los competidores más relevantes en función de con quiénes puedes competir de manera realista. En general, recomendamos mantener estas sugerencias en lugar de añadir aplicaciones que estén muy por delante o muy por detrás. Si tu aplicación pertenece a varias categorías, puede que quieras ajustar la lista para centrarte en el segmento de mercado más relevante.
:::
#### Puntos de referencia del sector \{#industry-benchmarks\}
El AI Growth Advisor se basa en datos anonimizados de 20.000 aplicaciones de suscripción rastreadas por Adapty para mostrarte cómo te comparas con la media de la categoría en un país específico. Los datos se agregan en toda la red y nunca se vinculan a una aplicación concreta.
Por ejemplo, tu embudo de conversión y los ingresos por instalación se comparan con la media de aplicaciones de tu categoría y país. Esto te ayuda a ver si estás por debajo del promedio, en la media o ya por delante.
#### Datos de mercado geográfico \{#geographic-market-data\}
El Asesor de Crecimiento IA analiza mercados geográficos individuales —basándose en patrones de la red de 20.000 aplicaciones de Adapty— para identificar dónde los ajustes regionales de precios podrían generar más ingresos. Para cada país, evalúa:
- **Tasa de conversión**: cómo se compara la tasa de instalación a pago con la media global. Una tasa más alta puede indicar margen para subir precios; una más baja puede señalar sensibilidad al precio.
- **Índice de precios**: la posición del país en el [Índice de Precios de Adapty](https://uploads.adapty.io/adapty_pricing_index.pdf), que refleja el poder adquisitivo de sus habitantes.
Puedes actuar sobre estas recomendaciones creando pruebas A/B a partir de las [sugerencias de precios por región](autopilot-growth-plan#geo-pricing-hypotheses) de tu plan de crecimiento.
## Cómo decide AI Growth Advisor qué recomendar \{#how-ai-growth-advisor-decides-what-to-recommend\}
AI Growth Advisor genera un conjunto de sugerencias para mejorar la conversión de tu paywall. Estas sugerencias están diseñadas para probarse de una en una, de modo que puedas medir de forma fiable el impacto de cada cambio.
Así es como AI Growth Advisor elabora sus sugerencias:
1. **Encontrar las mayores oportunidades**
AI Growth Advisor analiza tus precios, productos y el rendimiento de tu embudo, y los compara con patrones del sector y aplicaciones similares. El análisis se ejecuta en la moneda de tu mercado principal —no solo en USD—, de modo que las recomendaciones de precio se ajusten a lo que realmente pagan tus suscriptores. Identifica dónde tienes más margen de mejora, ya sea ajustando el precio, añadiendo un período de prueba o cambiando la estructura de tu oferta.
2. **Seleccionar el siguiente experimento**
Cada hipótesis se genera a partir de tu historial de pruebas existente. AI Growth Advisor sabe qué experimentos ya has realizado, cuáles ganaron y qué direcciones siguen valiendo la pena explorar. La siguiente sugerencia parte de lo que reveló la anterior, en lugar de seguir una secuencia fija.
3. **Ejecuta pruebas de ganador vs. retador**
Tras cada experimento, el ganador se convierte en tu nueva línea base. Ese resultado da forma a la siguiente recomendación en tu plan de crecimiento: AI Growth Advisor conserva lo que funcionó, descarta lo que no, y elige la siguiente prueba a partir de ahí.
4. **Mantenlo práctico**
El AI Growth Advisor solo sugiere pruebas que puedes lanzar con tus productos y configuración actuales, o con cambios mínimos como crear un nuevo producto o ajustar un precio. El objetivo es que las pruebas sean rápidas y manejables.
5. **Mostrarte el razonamiento**
Para cada recomendación, el AI Growth Advisor ofrece una hipótesis clara que explica exactamente por qué vale la pena ejecutar esa prueba. Verás cómo se comparan tus métricas actuales con las de la competencia y los promedios del sector, cuál es la oportunidad y qué métricas clave esperamos mejorar.
Esto convierte la experimentación en un proceso repetible donde cada prueba te enseña algo y te acerca a un paywall más efectivo.
## Qué ocurre después de cada experimento \{#what-happens-after-each-experiment\}
Las recomendaciones no se agotan. Cada prueba completada se convierte en la base para nuevos experimentos. Mientras sigas probando, AI Growth Advisor seguirá sugiriendo qué probar a continuación.
Para actualizar los datos de mercado subyacentes, vuelve a ejecutar el análisis sobre el mismo placement. Cada nueva ejecución incorpora los precios actualizados de la competencia, los benchmarks de conversión y las tendencias de categoría, y añade las nuevas hipótesis identificadas a tu plan de crecimiento sin alterar lo que ya existe. Las hipótesis generadas por IA, las hipótesis personalizadas y las pruebas A/B en curso se conservan entre ejecuciones.
Una vez que hayas optimizado tu línea base, también puedes optar por competir con competidores más avanzados. Este enfoque iterativo te ayuda a maximizar continuamente tus ingresos a medida que tu app crece y el mercado evoluciona.
:::tip
¿Listo para probarlo? Lanza [AI Growth Advisor](autopilot-analysis) para analizar tus paywalls y generar un plan de crecimiento con pruebas A/B. Usa el [asistente integrado](autopilot-execute-plan) para lanzar pruebas complejas sin complicaciones: te guiará a través de la creación de productos, duplicación de paywalls y configuración de segmentos.
:::
---
# File: autopilot-analysis
---
---
title: "Análisis de Paywall y Mercado"
description: "Genera un plan de crecimiento basado en datos adaptado a tu app."
---
Sigue los pasos de este artículo para ejecutar el análisis del AI Growth Advisor y generar un plan de crecimiento.
Si ya generaste un plan de crecimiento para el placement objetivo, este análisis generará nuevas hipótesis entre las que podrás elegir.
:::tip
Asegúrate de cumplir los [requisitos para el análisis](autopilot#prerequisites) antes de empezar.
:::
## Análisis del paywall \{#paywall-analysis\}
### Selecciona un paywall para analizar \{#select-a-paywall-for-analysis\}
1. Abre la página **AI Growth Advisor** y haz clic en el botón [Get Growth plan](https://app.adapty.io/ab-tests/analysis/start).
2. En la página **Paywall Diagnostic**, selecciona un **Placement** y un **Paywall** en los desplegables. Adapty preselecciona el placement con mayores ingresos y su paywall principal. Para analizar un paywall diferente, cambia primero el placement.
3. Sube una captura de pantalla. AI Growth Advisor necesita una captura de pantalla para analizar el diseño y el contenido de tu paywall.
4. Revisa los productos activos del paywall. Las tarjetas de productos a la derecha muestran la duración de la suscripción, el precio y el período de prueba de cada producto.
5. Haz clic en **Confirm & Analyze** para continuar. Adapty analiza tu paywall y muestra el informe de diagnóstico.
### Informe de análisis de paywall \{#paywall-analysis-report\}
Después de seleccionar un paywall y subir una captura de pantalla, Adapty analiza tu paywall en busca de patrones de diseño establecidos, destacando tanto los aciertos como las oportunidades de mejora.
#### Lo que está funcionando bien \{#whats-working-well\}
Esta sección destaca el uso de patrones establecidos que maximizan la conversión. Por ejemplo: una insignia de ahorro visible, una sección de reseñas de usuarios destacada o desgloses claros de la suscripción.
#### Qué mejorar en tu paywall \{#what-to-fix-on-your-paywall\}
Adapty agrupa sus recomendaciones en dos categorías:
- **Recomendaciones basadas en benchmarks**: Sugerencias respaldadas por datos de las apps con mejor rendimiento en tu categoría. Cada recomendación incluye una estadística de referencia (por ejemplo, "Usada por el 72% de las apps de Educación con mejor rendimiento") y una descripción del cambio propuesto.
- **Recomendaciones por análisis visual**: Sugerencias generadas por IA a partir de la captura de pantalla de tu paywall. Incluyen: mejoras de copy, cambios de diseño y más.
:::tip
Tu [plan de crecimiento](autopilot-growth-plan#view-the-growth-plan) incluirá hipótesis basadas en las recomendaciones de referencia. Puedes añadir sugerencias de análisis visual al plan manualmente.
:::
Haz clic en **Get Market Insights** para continuar.
## Análisis de mercado y competencia \{#market-and-competitor-analysis\}
:::note
El análisis de mercado y competencia requiere completar primero el [análisis de paywall](#paywall-analysis).
:::
El análisis de Market Insights compara los precios y métricas de conversión de tu app con los de sus competidores y la media del sector. Las comparaciones son específicas por país. Para ofrecer un punto de referencia, Adapty agrega y analiza datos de apps de la App Store en tu subcategoría y país; información que no está disponible públicamente en ningún otro lugar.
### Seleccionar competidores \{#select-competitors\}
Selecciona hasta 5 competidores para la comparación.
Adapty elegirá 5 automáticamente y sugerirá 5 más. También puedes añadir apps manualmente con un enlace de App Store. Para obtener mejores resultados, selecciona apps con un MRR mayor que el tuyo.
Haz clic en **Generate report** para confirmar la lista y espera a que finalice el análisis.
### Seleccionar un país \{#select-a-country\}
Usa el desplegable **Country** para seleccionar uno de tus principales países y obtener un análisis detallado.
### Distribución de ingresos \{#revenue-distribution\}
Este gráfico de distribución de ingresos muestra de qué países provienen tus ingresos, con desglose por porcentajes. Destaca tus 5 países principales, que son el foco del resto del análisis.
### Precios de la competencia \{#competitor-pricing\}
La tabla de precios de la competencia compara los precios de suscripción de tu paywall con los de tus competidores en el [país seleccionado](#select-a-country). Incluye columnas separadas para cada duración de suscripción.
### Embudo de conversión \{#conversion-funnel\}
El gráfico muestra tus tasas de conversión — Vistas a prueba, Prueba a pago y Vistas a pago — junto a los promedios de aplicaciones similares.
### Distribución de ingresos por duración \{#revenue-distribution-by-duration\}
Este gráfico muestra qué duraciones de suscripción contribuyen más a tus ingresos, en comparación con la media del sector. Si tus ingresos están muy concentrados en una sola duración, puede ser una señal de oportunidad para optimizar tu estrategia de precios.
### ARPU de Activación \{#activation-arpu\}
El gráfico **Activation ARPU: your app vs. category** compara el ingreso medio por nueva instalación de tu app con el promedio de la categoría.
Úsalo junto con el [embudo de conversión](#conversion-funnel):
- La conversión muestra cuántos usuarios pagan.
- El ARPU de Activación muestra el ingreso medio por usuario.
Una tasa de conversión alta con un ARPU de Activación bajo puede indicar que las ofertas tienen un precio demasiado bajo.
La métrica es **basada en cohortes**. Adapty toma los usuarios que instalaron la app en los últimos 90 días y divide los ingresos que generaron entre su número.
#### Comparación con otras métricas \{#comparison-to-other-metrics\}
El ARPU de activación no coincidirá con los valores de ARPU que ves en otras partes del dashboard, ya que cada métrica mide algo diferente.
- **[El gráfico de análisis ARPU](arpu)**: incluye las renovaciones de cohortes anteriores, por lo que el número es varias veces superior al ARPU de activación.
- **[Gráfico de ingresos](revenue), filtro de período configurado en "Activation"**: solo cuenta el primer pago de cada usuario. No cuenta las renovaciones realizadas por la cohorte dentro de la ventana de 90 días.
- **[Ingresos por cohorte](analytics-cohorts) (90 días)**: el equivalente más cercano; usa esta métrica como referencia.
## Próximos pasos \{#next-steps\}
Lee el artículo [Gestionar y ejecutar tu plan de crecimiento](autopilot-growth-plan) para aprender a ejecutar pruebas A/B basadas en los resultados del análisis.
Siempre puedes ver los resultados de tu análisis desde la página del Plan de crecimiento. Solo tienes que hacer clic en la pestaña Analysis Results.
---
# File: autopilot-growth-plan
---
---
title: "Gestiona tu plan de crecimiento"
description: "Añade hipótesis personalizadas, archívalas y actualiza el plan de crecimiento."
---
Una vez que completas [el análisis](autopilot-analysis), Adapty te presenta tu plan de crecimiento: una lista de **hipótesis de mejora accionables**. Cada elemento sugiere un nuevo precio o una mejora de diseño.
Abre una hipótesis para [probarla con una prueba A/B](autopilot-execute-plan).
Cada placement tiene su propio plan de crecimiento. A medida que cambian las condiciones del mercado, puedes volver a ejecutar el análisis para actualizar las sugerencias. Las ejecuciones anteriores se guardan en el historial de versiones.
## Hipótesis \{#hypotheses\}
Usa las pestañas en la parte superior del plan de crecimiento para filtrar hipótesis por tipo:
- **Prioridad máxima** incluye las hipótesis de mayor impacto que merecen tu atención. Cuando ninguna hipótesis cumple los requisitos, esta pestaña se oculta.
- **Todas** muestra todas las hipótesis de tu plan activo.
- Las hipótesis de **Precios** exploran nuevos puntos de precio o configuraciones de prueba. Cada una se basa en una recomendación específica del diagnóstico de paywall o del informe de insights de mercado.
- Las hipótesis **Visuales** son sugerencias de mejora de diseño. Pueden implicar cambios en el texto, el diseño o cualquier otro elemento visual.
- Las hipótesis de [**Precios por geo**](#geo-pricing-hypotheses) prueban ajustes de precio específicos por país.
- Las hipótesis [**Archivadas**](#archive-a-hypothesis) son sugerencias que eliminaste de tu plan activo. Puedes restaurarlas en cualquier momento.
Puedes [añadir tus propias hipótesis](#add-your-own-hypothesis), o [archivar](#archive-a-hypothesis) las que no quieras probar.
Prueba estas hipótesis de una en una, en cualquier orden. Las pruebas de precios por región son la excepción: sus audiencias no se solapan, así que pueden ejecutarse en paralelo.
### Hipótesis de precios por región \{#geo-pricing-hypotheses\}
:::important
Las compras únicas no son elegibles para la optimización regional de precios.
:::
Abre la pestaña **Geo-pricing** para ver la lista de recomendaciones de precios por región. Cada recomendación apunta a un país con un único cambio de precio y se ejecuta como una prueba A/B independiente.
Adapty detecta los países que necesitan ajustes de precios y ofrece recomendaciones basadas en datos validadas por el [Índice de Precios de Adapty](https://uploads.adapty.io/adapty_pricing_index.pdf).
## El gráfico de embudo paso a paso \{#funnel-chart-step-by-step\}
Repasemos los elementos de un embudo para entender cómo leer el recorrido del usuario en el gráfico.
### Instalaciones \{#installs\}
La 1ª columna (1) muestra el número de instalaciones. Se presenta como valor absoluto (2) del total de instalaciones (no usuarios únicos) y también como 100%, que es el número de entrada más alto para el cálculo relativo de conversiones posteriores. Si un usuario elimina la app y la vuelve a instalar, se contabilizan dos instalaciones por separado.
El área gris adyacente representa los parámetros de transición entre pasos. El porcentaje de conversión al siguiente paso (Paywall mostrado) se muestra en una etiqueta (3). El porcentaje de abandono y el valor absoluto de la pérdida se muestran a continuación (4).
### Paywall mostrado \{#paywall-displayed\}
La 2ª columna (5) muestra el número de usuarios de la app que vieron un paywall al menos una vez (6). Solo se tienen en cuenta los usuarios cuya instalación ocurrió en el período seleccionado. Si un usuario ve un paywall en el período seleccionado pero la fecha de su instalación está fuera del rango, esa visualización no se contabiliza.
También se muestra el porcentaje de esas visualizaciones respecto al 1er paso (7). Puedes observar que este porcentaje es igual a la bandera gris (3) del 1er paso. Esta igualdad solo se da en estos primeros pasos.
Recopilamos los datos de este paso a partir de todos tus paywalls que usan el método `logShowFlow()` (iOS SDK v4+) / `logShowPaywall()`. Asegúrate de enviar cada visualización de paywall a Adapty mediante este método, tal como se describe en la [documentación](present-remote-config-paywalls#track-paywall-view-events).
El área gris junto a la 2ª columna representa la transición. El porcentaje de conversión al siguiente paso (Trial) se muestra en una bandera (8). El porcentaje de abandono y el valor absoluto de clientes perdidos tras el paywall se muestran a continuación (9).
### Pruebas gratuitas \{#trials\}
La 3.ª columna (10) muestra el número de pruebas gratuitas activadas en los paywalls por los usuarios que instalaron la aplicación dentro del período seleccionado (11). Si el filtro está configurado para productos sin prueba gratuita, este valor es cero y la columna aparece vacía.
Observa también el porcentaje de trials tomado desde el 1er paso, que muestra la conversión de instalaciones a trials (12).
Puede que notes que este porcentaje no coincide ahora con la bandera gris (8) de la conversión del paso anterior. Esto se debe a que comparamos el valor actual con el 1er paso en la parte superior del gráfico y con el paso anterior en las banderas grises.
Por tanto, el área gris junto a la 3ª columna muestra el porcentaje de conversión al siguiente paso (Paid), que se indica en una bandera (13). El porcentaje de abandono y el valor absoluto de clientes que se dieron de baja durante el período de trial se muestran a continuación (14).
### Suscripciones y renovaciones \{#subscriptions-and-renewals\}
La 4ª columna muestra el número de suscripciones activadas (15). Para productos sin período de prueba, este número incluye las suscripciones directas desde un paywall. Para productos con período de prueba, contiene el número de pruebas convertidas en suscripciones de pago. Si tienes ambos tipos de productos, con y sin período de prueba, será la suma de ambos.
El porcentaje en la parte superior muestra la conversión desde las instalaciones (16).
El porcentaje en una bandera gris muestra la conversión al siguiente paso (renovación al 2.º período) (17).
La pérdida antes de la renovación al 2.º período, en porcentaje y valor absoluto, se muestra debajo de la conversión (18).
Este paso da inicio a una secuencia de pasos con una estructura similar. Tras la 2.ª renovación llega la 3.ª, luego la 4.ª, etc. Si hay suficientes datos en el historial de tu app, puedes ver decenas de períodos usando el scroll horizontal. La lógica de estos pasos es siempre la misma:
- porcentaje sobre instalaciones en la parte superior,
- porcentaje sobre el paso anterior en la parte inferior,
- cantidad absoluta de renovaciones en la parte superior,
- cantidad absoluta de cancelaciones en la parte inferior,
- un hover para el pop-up con los motivos de cancelación.
### Razones de abandono \{#churn-reasons\}
Adapty detalla las estadísticas de *abandono* para la etapa de prueba y las siguientes. Todo usuario que entró en una etapa pero no en la siguiente cuenta como una instancia de abandono.
* Si un evento concreto (por ejemplo, la expiración de una prueba o un problema de facturación) fue la causa de la falta de conversión, Adapty muestra la razón.
* El estado **unknown** es un estado temporal. Indica que el usuario aún no ha encontrado el evento que le permite pasar a la siguiente etapa.
En la etapa de prueba, esto suele significar que la prueba aún no ha terminado. Esto ocurre habitualmente al ver embudos para rangos de fechas cortos o días individuales, ya que las pruebas necesitan tiempo para resolverse.
Adapty actualizará la información una vez que el usuario convierta o cancele la prueba.
### Vista de tabla, filtros y exportación CSV \{#table-view-filters-and-csv-export\}
El gráfico de embudo se complementa con una tabla de datos para facilitar el trabajo con los números.
Esta tabla sigue el mismo enfoque del embudo con algunas modificaciones.
Hay columnas que muestran datos de todos los pasos excepto el de la 1.ª suscripción de pago.
En su lugar, hay dos columnas separadas: Install → Paid y Trial → Paid. Muestran el punto clave de conversión en el que un usuario gratuito se convierte en de pago.
Puede parecer que existe una división por tipo de producto: la columna Instalación → Pago muestra solo productos sin períodos de prueba, mientras que la columna Prueba → Pago contiene únicamente productos con períodos de prueba. Pero no es exactamente así. También tenemos en cuenta a aquellos usuarios cuyo período de prueba ha expirado y que compran un producto con período de prueba como si no lo tuviera.
Si profundizas en los números, encontrarás potentes herramientas de filtrado para generar nuevas hipótesis.
Establece condiciones en distintas dimensiones y extrae insights reales basados en datos.
Varía:
1. Tipo de producto: economía, duración, etc.
2. Rango de fechas.
3. Segmentación por país.
4. Atribución de tráfico.
5. Store.
Selecciona Número absoluto, Porcentaje relativo o ambos para ver solo los datos que necesitas.
Por último, a la derecha del panel de control hay un botón para exportar los datos del embudo a CSV. Luego puedes abrirlo en Excel, en Google Sheets, o importarlo a tu propio sistema de análisis.
:::important
Notifica a Adapty si tu aplicación está inscrita en un programa de comisión reducida. Para garantizar cálculos correctos, especifica el estado de tu [Programa para Pequeñas Empresas](app-store-small-business-program) y el [programa de Tarifa de Servicio Reducida](google-reduced-service-fee) en los [ajustes de tu aplicación](general).
:::
---
# File: analytics-retention
---
---
title: "Análisis de retención"
description: "Comprende los análisis de retención de usuarios y optimiza tu estrategia de suscripción."
---
Los gráficos de retención pueden ayudarte a responder las siguientes preguntas:
1. ¿Cómo retiene tu app a los clientes de período en período?
2. ¿Qué productos son más atractivos y fidelizan mejor?
3. ¿Qué grupos de usuarios son más leales?
4. ¿Qué nivel de retención puede usarse como referencia para el crecimiento?
5. Y, por supuesto, cómo ahorrar dinero invirtiendo en la audiencia ya captada en lugar de buscar nuevos usuarios.
Encontrarás información valiosa sobre el comportamiento de los usuarios configurando filtros y grupos.
La retención se calcula con los datos que recopilamos a través del SDK y las notificaciones de la store, sin necesidad de ninguna configuración adicional por tu parte.
### ¿Cómo calculamos la retención? \{#how-do-we-calculate-retention\}
Al observar el gráfico de retención, puedes ver cómo varía el número de usuarios según el paso: trial (si la casilla "mostrar trials" está marcada), el 1.er pago, el 2.º pago, etc. A continuación se explica qué usuarios se contabilizan al seleccionar un rango de fechas para el gráfico de retención.
Por ejemplo, si has seleccionado los últimos 3 meses en el calendario y la casilla "mostrar trials" no está marcada, se contabilizan únicamente los usuarios que hayan realizado su 1.ª suscripción durante ese período. Si la casilla "mostrar trials" está marcada y se han seleccionado los últimos 3 meses, se contabilizan todos los usuarios que hayan iniciado un trial durante ese período. Para estos suscriptores, la retención absoluta en el paso N se muestra como el número de usuarios que realizaron el pago N. El valor relativo de retención para el paso N se calcula como la proporción entre la cantidad absoluta del pago N y el total de suscripciones (o trials) del rango de fechas seleccionado.
:::info
La retención cambia de forma retroactiva
Independientemente de cuándo consultes el gráfico, el número de referencia (100%) permanece igual para el período de tiempo seleccionado. Sin embargo, la retención al siguiente período puede aumentar con el tiempo.
Por ejemplo, en una suscripción mensual, si se realizan 20 primeras compras entre el 1 y el 31 de diciembre, es de esperar que la retención al segundo período vaya creciendo a lo largo de enero (e incluso después) a medida que los usuarios vayan entrando en el siguiente período de suscripción, a tiempo o con algo de retraso por distintos motivos (por ejemplo, el período de gracia).
:::
### Gestión de reembolsos \{#refund-handling\}
Los reembolsos **no** se excluyen de la retención. Un usuario con reembolso sigue contando en la curva de retención, lo que puede hacer que la Retención parezca más alta que las [Suscripciones activas](active-subscriptions) o los [Ingresos](revenue) para la misma cohorte.
Para una comparación completa entre métricas, consulta [Cómo gestionan los reembolsos las métricas](refund-events#how-metrics-handle-refunds).
### Oportunidades de retención \{#retention-opportunities\}
Veamos cómo sacarle el máximo partido a la función de retención de Adapty.
Más allá de la pura pasión por los números, lo que realmente nos interesa es ver el valor de negocio real que surge al aplicar los resultados del análisis. Por eso, conviene pensar primero en los objetivos. Con un análisis profundo de las funciones del gráfico, es útil entender qué impacto puede tener esta información.
Así que veamos juntos el POR QUÉ y el CÓMO.
1 - trabaja con tu audiencia.
Ante todo, la retención tiene que ver con tu audiencia objetivo, sus preferencias y si tu producto cumple o no sus expectativas a lo largo del ciclo de consumo. Si alguna vez te has preguntado cómo medir la relación central de tu negocio que genera dinero, la retención es tu respuesta.
Medir esto es valioso porque, por lo general, vender a un cliente existente es más barato que vender a alguien nuevo. Y ese coste es menor por dos razones: menos esfuerzo de venta y un ticket medio más alto. Así que, cuando la retención baja, puede ser buena idea invertir en la fidelidad de tus suscriptores.
2 - trabaja con el producto.
La segunda razón del POR QUÉ es que los gráficos de retención muestran la vida útil real de consumo de tu producto y te permiten hacer previsiones a largo plazo. Y si quieres mejorar, corrige el trabajo que entrega el producto para cambiar su vida útil, y luego vuelve a hacer previsiones para acercarte a tus objetivos de negocio. Estas actualizaciones pueden formar parte de una visión estratégica que funcione junto con una rutina de previsión. Y sí, este proceso no termina nunca, porque todos corremos rápido para quedarnos en el mismo sitio en un entorno en constante cambio.
3 - trabajar con el mercado.
Moverse más rápido que los principales competidores está bien, pero a veces salir de la carrera habitual puede traer más beneficios. Cuando analizas el comportamiento de los usuarios en diferentes países y stores, algunas particularidades locales pueden abrir insights destacados y nuevas oportunidades para el negocio. El contexto cultural y de mercado puede analizarse desde la perspectiva de la retención para usarlo después en la segmentación y el desarrollo futuro. Por ejemplo, puedes encontrar océanos azules en algunas regiones y crecer allí más rápido.
El uso de los datos de retención no se limita, por supuesto, a esta interpretación básica, pero puede ser un buen punto de partida si quieres obtener valor real rápidamente.
### Curvas, vista de tabla, filtros y exportación CSV \{#curves-table-view-filters-and-csv-export\}
Ahora que estamos en la misma página en cuanto a los objetivos de retención y las formas básicas de interpretación, repasemos las herramientas que lo hacen todo más manejable.
El núcleo de la función de retención en Adapty es el gráfico. Muestra cómo varía el nivel de retención a lo largo de las etapas del ciclo de vida de un cliente.
Las etapas se muestran en el eje horizontal: Trial, Paid (la 1.ª suscripción), P2 (la 2.ª suscripción), P3, P4, etc.
Ten en cuenta que el eje comienza con la etapa Trial únicamente cuando la casilla **Show trials** está seleccionada.
En cuanto al cálculo de datos, esta casilla funciona así: cuando **Show trials** está seleccionada y el eje empieza en la etapa Trial, solo se muestran los escenarios que incluyen trials; no se incluyen transacciones directas desde instalaciones, y la etapa Paid contiene únicamente las transacciones que provienen de trials. Cuando **Show trials** no está seleccionada y el eje comienza en la etapa Paid, ese primer paso incluye todas las primeras transacciones: tanto las que vienen de trials como las que vienen directamente de instalaciones.
Al pasar el cursor sobre el gráfico, se muestra un pop-up con un resumen de los datos. Y si pasas el cursor sobre una columna de la tabla inferior, también verás un pop-up con los datos relevantes del gráfico.
La tabla contiene los mismos agrupamientos y filtros seleccionados para el gráfico.
Combina filtros y agrupaciones para un análisis avanzado. Extrae conclusiones reales a partir de los datos.
Varía:
1. Tipo de producto.
2. Duración.
3. Rango de tiempo.
4. País.
5. Atribución de tráfico.
6. Store.
Usa el control #Absolute y %Relative para ver los datos que necesitas.
Por último, a la derecha del panel de control, hay un botón para exportar los datos del embudo a CSV. Puedes abrirlos en Excel, en Google Sheets o importarlos en tu propio sistema de análisis para seguir analizando y haciendo previsiones en el entorno que prefieras.
:::warning
Asegúrate de indicar que tu app está incluida en el Small Business Program en [Adapty General Settings](https://app.adapty.io/settings/general).
:::
---
# File: analytics-conversion
---
---
title: "Análisis de conversión"
description: "Mide las tasas de conversión de suscripciones con las herramientas de análisis de Adapty."
---
Mientras que los embudos ofrecen una visión general de alto nivel y la retención se centra en la fidelización, el análisis de conversión está diseñado para ayudarte a evaluar la efectividad en cada paso clave del recorrido del usuario, a lo largo del tiempo.
Las conversiones responden a las siguientes preguntas:
1. ¿Cómo cambian las conversiones de la app con el tiempo? ¿Existen tendencias estacionales?
2. ¿Cómo se ven afectadas las conversiones en el momento de actividades de marketing u otras circunstancias nuevas?
3. ¿Cómo responden los usuarios de diferentes regiones a las actualizaciones de tu app?
4. ¿Qué tipos de producto convierten mejor a lo largo del tiempo?
La conversión se calcula con los datos que recopilamos a través del SDK de Adapty y las notificaciones del store, y no requiere ninguna configuración adicional de tu parte.
## Controles principales y gráficos \{#main-controls-and-charts\}
Aunque los ingresos suelen ser la métrica de referencia para medir el éxito, son solo una parte del panorama general. Entender cómo evoluciona tu negocio a lo largo del tiempo, considerando diferentes comportamientos de usuario y etapas del ciclo de vida, es igual de importante. Ahí es donde entra el análisis de conversiones.
Puedes encontrar información más valiosa sobre el comportamiento de los usuarios configurando filtros y grupos. Para identificar y analizar tendencias, controla cómo evolucionan tus conversiones de forma diaria, mensual o anual.
En el lado izquierdo del gráfico encontrarás el control de pasos de conversión. Esto te permite elegir qué conversiones específicas rastrear, como Instalación → Prueba, Prueba → Pago, o Pago → Renovación.
Cada métrica de conversión sigue esta lógica:
- Sea **X** el número de usuarios que entraron al estado inicial en una fecha seleccionada (p. ej., instalaciones).
- Sea **Y** el número de esos usuarios que finalmente alcanzaron el estado objetivo (p. ej., inicio de prueba).
- La tasa de conversión se calcula como: **Conversión = (Y / X) × 100%**
:::note
La fecha que aparece en el gráfico corresponde a cuándo los usuarios entraron al estado inicial (X), es decir, el momento en que se volvieron elegibles para convertir.
:::
A continuación encontrarás la explicación de cada conversión, con un ejemplo de referencia.
### Instalación -> Pago \{#install---paid\}
Esta métrica muestra qué porcentaje de usuarios que instalaron la app en una fecha determinada terminaron comprando su primera suscripción.
La columna **Predicted revenue** muestra los ingresos totales estimados que se espera que genere una cohorte de suscriptores durante el período de tiempo seleccionado tras su creación. Este valor se calcula mediante el modelo de predicción de Adapty, basado en los patrones históricos de retención de cohortes de la app.
La columna **Predicted LTV** muestra el valor de vida estimado de cada usuario en la cohorte seleccionada. Este valor se calcula dividiendo los ingresos predichos entre el número predicho de usuarios de pago en la cohorte.
### Seleccionar el horizonte \{#select-the-horizon\}
Para cambiar el horizonte de predicción, selecciona un valor en el desplegable **Predictions**. Las opciones disponibles son 3, 6, 9, 12, 18 y 24 meses desde la creación de la cohorte.
### Filtrar por producto \{#filter-by-product\}
Puedes filtrar los ingresos proyectados y el LTV por producto. Por defecto, las predicciones se construyen a partir de todos los datos de compra; filtrar por producto muestra la contribución de cada producto.
## Cuándo no hay predicciones disponibles \{#when-predictions-are-unavailable\}
Cuando no se puede generar una predicción para una cohorte, las columnas Predicted Revenue y Predicted LTV muestran guiones largos (—) en lugar de valores. Esto puede ocurrir por varias razones:
- **Tiempo insuficiente desde la creación de la cohorte**: Las predicciones solo están disponibles una vez que la cohorte completa su primer período de renovación: aproximadamente una semana para las suscripciones semanales y unas cuatro semanas para las mensuales.
- **Tamaño de cohorte pequeño**: Hay muy pocos suscriptores de pago para generar una proyección fiable.
- **Comportamiento inusual de la cohorte**: La cohorte se desvía significativamente de los patrones que espera el modelo. Esperar algunas semanas puede resolver esto a medida que se acumulan más datos.
- **Horizonte superado**: La cohorte es más antigua que el horizonte de predicción seleccionado. Por ejemplo, la predicción a 3 meses se oculta tras tres meses, la predicción a 12 meses tras doce meses, y no se muestran predicciones para cohortes con más de 24 meses de antigüedad.
:::warning
Al activar las predicciones, ten en cuenta que puede haber un retraso máximo de 24 horas antes de que los datos de predicción de Revenue y LTV estén disponibles en tu Adapty Dashboard.
:::
---
# File: predictions-in-ab-tests
---
---
title: "Predicciones en pruebas A/B"
description: "Aprende cómo las predicciones en las pruebas A/B ayudan a perfeccionar las estrategias de precios de suscripción."
---
Bienvenido a la documentación de Análisis Predictivo de Adapty para nuestra funcionalidad de pruebas A/B. Esta herramienta te proporcionará información sobre los resultados futuros de tus pruebas A/B en curso y te ayudará a tomar decisiones basadas en datos más rápidamente 🚀 con las predicciones potenciadas por ML de Adapty.
### ¿Qué son las predicciones en pruebas A/B? \{#what-are-ab-test-predictions\}
Las predicciones de pruebas A/B de Adapty utilizan técnicas avanzadas de aprendizaje automático (concretamente modelos de gradient boosting) para pronosticar el potencial de ingresos a largo plazo de los paywalls que se comparan en una prueba A/B.
Este modelo predictivo te permite seleccionar el paywall más efectivo basándote en los ingresos proyectados al cabo de un año, en lugar de basarte únicamente en las métricas que observas mientras la prueba está en curso. Esto te permite decidir el ganador de forma más fiable y rápida, sin tener que esperar semanas a que se acumulen los datos.
### ¿Cómo funciona el modelo? \{#how-does-the-model-work\}
El modelo se entrena con un amplio historial de datos de pruebas A/B procedentes de una gran variedad de apps en distintas categorías. Incorpora un amplio conjunto de características para predecir los ingresos que es probable que genere un paywall en el año siguiente al inicio del experimento. Estas características incluyen:
- Transacciones de usuarios y tasas de conversión en diferentes períodos
- Distribución geográfica de los usuarios
- Plataforma de uso (iOS o Android)
- Tasas de cancelación y reembolso
- Productos de suscripción y sus duraciones (diaria, mensual, anual, etc.)
- Otros datos relacionados con transacciones
El modelo también tiene en cuenta los períodos de prueba en los paywalls, utilizando tasas de conversión históricas para predecir los ingresos como si los usuarios ya hubieran convertido. Esto garantiza una comparación justa entre paywalls con y sin ofertas de prueba, ya que también se tienen en cuenta las pruebas activas que potencialmente podrían generar ingresos en el futuro.
### ¿En qué se diferencia el P2BB Predicho del P2BB normal? \{#how-is-predicted-p2bb-different-from-just-the-p2bb\}
Nuestras pruebas A/B utilizan el enfoque bayesiano: básicamente modelamos la distribución de los ingresos por usuario (o "Ingresos por cada 1.000 usuarios", para ser más precisos) y luego calculamos la probabilidad de que una distribución sea "realmente" mejor que la otra y no por pura casualidad — a esto lo llamamos Probabilidad de ser el mejor o P2BB (puedes obtener más información sobre nuestro enfoque [aquí](maths-behind-it)).
Es importante tener en cuenta que al hacer esto, nos basamos únicamente en los ingresos que se han acumulado durante el tiempo que lleva ejecutándose la prueba. Por tanto, si quisieras realizar una prueba comparando una suscripción anual con una semanal, tendrías que esperar mucho tiempo para entender realmente cuál rinde mejor. Algo similar ocurre cuando comparas suscripciones con período de prueba frente a suscripciones sin período de prueba en una prueba A/B — ya que las pruebas activas que podrían potencialmente cambiar la dinámica del ganador nunca se tienen en cuenta en los ingresos.
Aquí es donde entra en juego nuestro modelo predictivo. Con la distribución de ingresos actual de una prueba A/B y entrenado sobre un amplio conjunto de datos, es capaz de predecir la versión futura de la distribución de ingresos (concretamente tras 1 año). Y tras hacerlo, produce un P2BB predicho — el que obtendrías si ejecutaras la prueba durante todo el año.
Ten en cuenta que a veces el P2BB predicho puede contradecir el P2BB actual. Cuando esto ocurre, resaltamos las filas de variación en amarillo, así:
Consideramos que esto es una señal de que deberías acumular más datos para confirmar el ganador o profundizar en la prueba A/B para averiguar la causa. En general, recomendamos confiar en el P2BB predicho sobre el P2BB actual porque simplemente tiene en cuenta más datos, aunque la decisión final es, por supuesto, tuya.
### Precisión y certeza del modelo \{#model-accuracy-and-certainty\}
El modelo alcanza un alto nivel de precisión, con un Error Porcentual Absoluto Medio (MAPE) ligeramente inferior al 10%. Este nivel de precisión permite a las empresas confiar en las predicciones del modelo al tomar decisiones basadas en datos.
Para garantizar aún más la estabilidad, el modelo emplea un criterio de "certeza" basado en tres factores:
- Un intervalo de predicción estrecho: el modelo tiene confianza en su resultado
- Una cantidad suficiente de suscripciones e ingresos en la prueba
- Han transcurrido al menos 2 semanas desde el inicio de la prueba
Una predicción se considera fiable cuando se cumplen al menos dos de estos tres criterios.
Cuando comienza una nueva prueba A/B, el modelo proporciona una predicción de ingresos por 1.000 usuarios a un año vista (nuestra métrica principal en pruebas A/B) para cada paywall. Las predicciones solo se muestran cuando cumplen los criterios de certeza. Si los datos son insuficientes, el modelo indicará "datos insuficientes para la predicción".
### Limitaciones y consideraciones \{#limitations-and-considerations\}
Aunque nuestro modelo predictivo es una herramienta potente, es importante tener en cuenta sus limitaciones.
El rendimiento del modelo depende de la calidad y representatividad de los datos disponibles. El comportamiento inusual de una cohorte o las apps nuevas que no están incluidas en el conjunto de entrenamiento pueden afectar a la precisión de las predicciones.
No obstante, las predicciones se actualizan diariamente para reflejar los datos y comportamientos de usuario más recientes. Esto garantiza que la información que recibes siempre se basa en los datos más actuales.
🚧 Nota: Esta herramienta es un complemento, no un sustituto, de tu criterio experto y tu comprensión de la dinámica particular de tu app. Utiliza estas predicciones como guía junto con otras métricas y el conocimiento del mercado para tomar decisiones fundamentadas.
---
# File: adapty-ads-manager
---
---
title: "Adapty Ads Manager"
description: "Obtén análisis en tiempo real de Apple Ads y gestiona y optimiza tus campañas"
---
**Adapty Ads Manager** es una plataforma todo en uno diseñada para ayudarte a gestionar, optimizar y escalar tus campañas de Apple Ads de manera más eficiente. Conecta el rendimiento de tus Apple Search Ads con métricas de ingresos clave como instalaciones, trials, suscripciones y valor de vida útil sin necesitar un MMP.
Con análisis en tiempo real, predicciones impulsadas por IA y automatización inteligente, Adapty Ads Manager elimina los tediosos cambios manuales de pujas, las hojas de cálculo y las suposiciones, y los reemplaza con información clara y herramientas que te ayudan a actuar más rápido.
Con Adapty Ads Manager, obtienes:
- **[Resumen](ads-manager-overview)**: Todas las métricas clave de un vistazo — gasto, ingresos, ROAS, CPA y más — cada una con un gráfico de tendencia diaria
- **[Agente de IA](ads-manager-ai-agent)**: Haz preguntas en lenguaje natural y obtén respuestas y recomendaciones de embudo completo
- **Datos de rendimiento en tiempo real**: A lo largo de campañas, grupos de anuncios y palabras clave
- **Seguimiento de ingresos de extremo a extremo**: Desde búsqueda → instalación → prueba → suscripción → LTV
- **Predicciones y recomendaciones de IA**: Para un escalado rentable
- **Gestión masiva**: De pujas, presupuestos, estados y estructuras
- **[Automatizaciones basadas en reglas](ads-manager-automations)**: Gestiona el ciclo de vida completo de las palabras clave
- **[Market Intelligence](ads-manager-market-intelligence)**: Estrategias de palabras clave de la competencia en más de 50 países
- **[Pruebas A/B de CPP](ads-manager-cpp-ab-tests)**: Compara páginas de producto personalizadas entre sí y encuentra la que mejor funciona
## Paso 2. Conecta tu plataforma de anuncios y añade enlaces de seguimiento \{#step-2-connect-your-ad-platform-and-add-tracking-links\}
Adapty usa enlaces de seguimiento para conectar las instalaciones de la app con los datos de campaña.
Debes usar un enlace de seguimiento como URL de destino en cada campaña de anuncios que quieras medir en Adapty Attribution.
Si publicas anuncios en varias plataformas, configura los enlaces de seguimiento para cada plataforma por separado.
Hay dos formas en que Adapty trabaja con las plataformas de anuncios:
- **Integraciones nativas (Meta Ads, TikTok Ads).** Adapty se conecta directamente con la plataforma publicitaria. Los enlaces de seguimiento se generan automáticamente y los parámetros de campaña se rellenan de forma dinámica según dónde se use el enlace. Puedes usar el mismo enlace en diferentes campañas, conjuntos de anuncios o creatividades, y Adapty recibirá automáticamente los datos correctos de campaña y gasto publicitario.
- **Solo enlaces de seguimiento (el resto de plataformas de anuncios).** Adapty no se conecta a la plataforma publicitaria. Los enlaces de seguimiento se crean manualmente y todos los parámetros de campaña deben definirse explícitamente al crear el enlace. Los datos de gasto publicitario no están disponibles en estas plataformas.
3. En el editor de políticas, pega el siguiente JSON y cambia `adapty-s3-integration-test` por el nombre de tu bucket:
```json showLineNumbers title="Json"
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListObjectsInBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::adapty-s3-integration-test"
},
{
"Sid": "AllowAllObjectActions",
"Effect": "Allow",
"Action": "s3:*Object",
"Resource": [
"arn:aws:s3:::adapty-s3-integration-test/*",
"arn:aws:s3:::adapty-s3-integration-test"
]
},
{
"Sid": "AllowBucketLocation",
"Effect": "Allow",
"Action": "s3:GetBucketLocation",
"Resource": "arn:aws:s3:::adapty-s3-integration-test"
}
]
}
```
4. Una vez completada la configuración de la política, puedes añadir etiquetas (opcional) y luego hacer clic en **Next** para continuar al último paso
5. En este paso, pondrás nombre a tu política y simplemente harás clic en el botón **Create policy** para finalizar el proceso de creación
#### 1.2. Crear usuario IAM \{#12-create-iam-user\}
Para que Adapty Attribution pueda subir informes de datos sin procesar a tu bucket, deberás proporcionarle el Access Key ID y el Secret Access Key de un usuario con acceso de escritura al bucket específico.
1. Ve a la consola de IAM y selecciona la [sección Usuarios](https://console.aws.amazon.com/iamv2/home#/users)
2. Haz clic en el botón **Add users**
3. Ponle un nombre al usuario, elige **Access key – Programmatic access** y continúa con los permisos
4. En el siguiente paso, selecciona la opción **Add user to group** y haz clic en el botón **Create group**
5. A continuación, asigna un nombre a tu Grupo de Usuarios y selecciona la política que creaste anteriormente.
6. Una vez seleccionada la política, haz clic en el botón **Create group** para completar el proceso.
7. Una vez creado el grupo, **selecciónalo** y continúa con el siguiente paso
8. Como este es el último paso de esta sección, puedes continuar simplemente haciendo clic en el botón **Create User**
9. Por último, puedes **descargar las credenciales en formato .csv** o copiarlas y pegarlas directamente desde el dashboard
### Paso 2. Configurar la integración en Adapty Attribution \{#step-2-configure-integration-in-adapty-attribution\}
1. Ve a [**Integrations** -> **Amazon S3**](https://app.adapty.io/ua/integrations/s3)
2. Activa el toggle **Export install events to Amazon S3**.
3. Rellena los siguientes campos para establecer la conexión entre Amazon S3 y los perfiles de Adapty Attribution:
| Campo | Descripción |
|:-----------------------------| :----------------------------------------------------------- |
| **Access Key ID** | Un identificador único que se usa para autenticar el acceso de un usuario o aplicación a un servicio de AWS. Encuéntralo en el [archivo csv](ua-amazon-s3#step-1-create-amazon-s3-credentials) descargado. |
| **Secret Access Key** | Una clave privada que se usa junto con el Access Key ID para autenticar el acceso de un usuario o aplicación a un servicio de AWS. Encuéntrala en el [archivo csv](ua-amazon-s3#step-1-create-amazon-s3-credentials) descargado. |
| **S3 Bucket Name** | Un nombre único global que identifica un bucket S3 específico dentro de la nube de AWS. Los buckets S3 son un servicio de almacenamiento simple que permite a los usuarios guardar y recuperar objetos de datos, como archivos e imágenes, en la nube. |
| **Folder Inside the Bucker** | El nombre de la carpeta que quieres tener dentro del bucket S3 seleccionado. Ten en cuenta que S3 simula carpetas mediante prefijos de clave de objeto, que son esencialmente nombres de carpeta. |
| **Region** (Opcional) | Obtén tu región desde la consola de administración de AWS en tu cuenta de usuario IAM. |
## Exportación manual de datos \{#manual-data-export\}
Además de la exportación automática de datos de eventos a Amazon S3, Adapty UA también ofrece la funcionalidad de exportación manual de archivos. Con esta función, puedes seleccionar una fecha concreta para los datos de adquisición de usuarios y exportarlos manualmente a tu bucket de S3. Esto te da mayor control sobre qué datos exportas y cuándo lo haces.
## Estructura de la tabla \{#table-structure\}
En la integración con AWS S3, Adapty Attribution ofrece una tabla para almacenar datos históricos de eventos de instalación. La tabla contiene información sobre el perfil del usuario, ingresos y beneficios, y el store de origen, entre otros datos.
:::warning
Ten en cuenta que esta estructura puede crecer con el tiempo, al añadir datos nuevos nosotros mismos o los terceros con los que trabajamos. Asegúrate de que el código que la procesa sea lo suficientemente robusto y se base en campos concretos, no en la estructura en su conjunto.
:::
Esta es la estructura de la tabla para los eventos:
| Columna | Descripción |
|--------------------------|----------------------------------------------------|
| `adapty_profile_id` | Identificador único de perfil en Adapty |
| `install_id` | Identificador único de instalación |
| `created_at` | Marca de tiempo de creación del registro (ISO 8601)|
| `installed_at` | Marca de tiempo de instalación de la app (ISO 8601)|
| `store` | Store de aplicaciones (`ios`, `android`) |
| `country` | Código de país del usuario (ISO 3166-1 alpha-2) |
| `ip_address` | Dirección IP del cliente |
| `idfa` | Identificador para anunciantes de iOS |
| `idfv` | Identificador para proveedores de iOS |
| `gaid` | ID de publicidad de Google (Android) |
| `android_id` | ID de dispositivo Android |
| `app_set_id` | App Set ID de Android |
| `channel` | Canal de atribución |
| `campaign_id` | Identificador de campaña |
| `campaign_name` | Nombre de la campaña |
| `adset_id` | Identificador del conjunto de anuncios |
| `adset_name` | Nombre del conjunto de anuncios |
| `ad_id` | Identificador del anuncio |
| `ad_name` | Nombre del anuncio |
| `keyword_id` | Identificador de palabra clave |
| `keyword_name` | Nombre de la palabra clave |
| `asa_org_id` | ID de organización de Apple Search Ads |
| `asa_keyword_match_type` | Tipo de concordancia de palabra clave ASA (`Exact`, `Broad`) |
| `asa_attribution` | Datos de atribución ASA (cadena JSON) |
| `asa_conversion_type` | Tipo de conversión ASA |
| `asa_country_or_region` | País o región de ASA |
| `asa_creative_set_name` | Nombre del conjunto creativo ASA |
| `fbclid` | ID de clic de Facebook |
| `ttclid` | ID de clic de TikTok |
| `utm_source` | Parámetro de fuente UTM |
| `utm_medium` | Parámetro de medio UTM |
| `utm_campaign` | Parámetro de campaña UTM |
| `utm_term` | Parámetro de término UTM |
| `utm_content` | Parámetro de contenido UTM |
---
# File: ua-google-cloud-storage
---
---
title: "Google Cloud Storage en Adapty Attribution"
description: "Integra Google Cloud Storage con Adapty Attribution para almacenar de forma segura los datos de adquisición de usuarios."
---
La integración de Adapty Attribution con Google Cloud Storage te permite almacenar de forma segura los datos de tus campañas de adquisición de usuarios en un único lugar centralizado. Podrás guardar los datos de rendimiento de campañas, datos de atribución y eventos de adquisición de usuarios en tu bucket de Google Cloud Storage como archivos .csv.
Para configurar esta integración, tendrás que seguir unos sencillos pasos en la Google Cloud Console y en el Adapty Attribution Dashboard.
:::note
Programación
Adapty Attribution envía tus datos a Google Cloud Storage cada 24 horas a las 4:00 UTC.
Cada archivo contendrá los datos de los eventos creados durante el día natural anterior completo en UTC. Por ejemplo, los datos exportados automáticamente a las 4:00 UTC del 8 de marzo contendrán todos los eventos creados el 7 de marzo entre las 00:00:00 y las 23:59:59 UTC.
:::
## Cómo configurar la integración con Google Cloud Storage \{#how-to-set-up-google-cloud-storage-integration\}
### Paso 1. Crea las credenciales de Google Cloud Storage \{#step-1-create-google-cloud-storage-credentials\}
Esta guía te ayudará a crear las credenciales necesarias en la consola de Google Cloud Platform.
Para que Adapty Attribution pueda subir informes de datos brutos a tu bucket designado, se necesita la clave de la cuenta de servicio, así como acceso de escritura al bucket correspondiente. Al proporcionar la clave de la cuenta de servicio y conceder acceso de escritura al bucket, permites que Adapty Attribution transfiera de forma segura y eficiente los informes de datos brutos desde su plataforma a tu entorno de almacenamiento.
:::warning
Ten en cuenta que solo admitimos la autorización mediante clave HMAC de cuenta de servicio, por lo que es imprescindible asegurarse de que tu clave HMAC de cuenta de servicio tenga los roles "Storage Object Viewer", "Storage Legacy Bucket Writer" y "Storage Object Creator" asignados para permitir el acceso correcto a Google Cloud Storage.
:::
#### 2.1. Crear cuenta de servicio \{#21-create-service-account\}
1. Ve a la sección [IAM](https://console.cloud.google.com/projectselector2/iam-admin/serviceaccounts) de tu cuenta de Google Cloud y elige el proyecto correspondiente o crea uno nuevo
2. A continuación, crea una nueva cuenta de servicio para la atribución de Adapty haciendo clic en el botón **+ CREATE SERVICE ACCOUNT**
3. Rellena los campos del primer paso, ya que el acceso se concederá en una etapa posterior. Para obtener más detalles sobre esta página, consulta la documentación [aquí](https://docs.cloud.google.com/iam/docs/service-accounts-create)
4. Para crear y descargar una [clave JSON privada](https://docs.cloud.google.com/iam/docs/keys-create-delete), ve a la sección KEYS y haz clic en el botón "ADD KEY"
5. En la sección DETAILS, localiza el valor Email vinculado a la cuenta de servicio recién creada y cópialo. Esta información será necesaria en los próximos pasos para autorizar la cuenta y permitirle escribir en el bucket.
#### 2.2. Configurar los permisos del bucket \{#22-configure-bucket-permissions\}
6. Ve a la página de [Buckets](https://console.cloud.google.com/storage/browser) de Google Cloud Storage y selecciona un bucket existente o crea uno nuevo para almacenar los informes de datos de atribución de usuarios de Adapty Attribution
7. Navega a la sección PERMISSIONS y selecciona la opción para [GRANT ACCESS](https://docs.cloud.google.com/identity/docs/how-to?hl=en)
8. En la sección PERMISSIONS, introduce el Email de la cuenta de servicio obtenido en el quinto paso mencionado anteriormente y selecciona el rol Storage Object Creator
9. Por último, haz clic en SAVE para aplicar los cambios
10. Recuerda guardar el nombre del bucket para consultarlo más adelante.
11. Una vez completados estos pasos, habrás finalizado correctamente la configuración necesaria en Google Cloud Console. El último paso consiste en introducir el nombre del bucket y descargar el archivo JSON para usarlo en Adapty Attribution.
### Paso 2. Configurar la integración en Adapty Attribution \{#step-2-configure-integration-in-adapty-attribution\}
1. Ve a [**Integrations** -> **Google Cloud Storage**](https://app.adapty.io/ua/integrations/google-cloud-storage)
2. Activa el toggle **Export install events to Google Cloud Storage**
3. Rellena los campos obligatorios para establecer la conexión entre Google Cloud Storage y Adapty Attribution:
| Campo | Descripción |
|:------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Google Cloud service account key file** | El [archivo de clave JSON](ua-google-cloud-storage#step-1-create-google-cloud-storage-credentials) privado descargado. |
| **Google Cloud bucket name** | El nombre del bucket en Google Cloud Storage donde quieres almacenar tus datos. Debe ser único dentro del entorno de Google Cloud Storage y no puede contener espacios. |
| **Folder inside the bucket** | El nombre de la carpeta dentro del bucket donde quieres almacenar tus datos. Debe ser único dentro del bucket y puede usarse para organizar la información. Este campo es opcional. |
## Exportación manual de datos \{#manual-data-export\}
Además de la exportación automática de datos de eventos a Google Cloud Storage, Adapty UA también ofrece una funcionalidad de exportación manual de archivos. Con esta función, puedes seleccionar una fecha concreta para los datos de adquisición de usuarios y exportarlos manualmente a tu bucket de GCS. Esto te da mayor control sobre los datos que exportas y cuándo lo haces.
## Estructura de la tabla \{#table-structure\}
En la integración con Google Cloud Storage, Adapty Attribution proporciona una tabla para almacenar datos históricos de eventos de instalación. La tabla contiene información sobre el perfil del usuario, los ingresos y los beneficios, y el store de origen, entre otros puntos de datos.
:::warning
Ten en cuenta que esta estructura puede crecer con el tiempo, ya que nosotros o los terceros con los que trabajamos podemos incorporar nuevos datos. Asegúrate de que el código que la procesa sea lo suficientemente robusto y se base en campos específicos, no en la estructura en su conjunto.
:::
Esta es la estructura de la tabla para los eventos:
| Columna | Descripción |
|--------------------------|----------------------------------------------------|
| `adapty_profile_id` | Identificador único del perfil en Adapty |
| `install_id` | Identificador único de instalación |
| `created_at` | Marca de tiempo de creación del registro (ISO 8601)|
| `installed_at` | Marca de tiempo de instalación de la app (ISO 8601)|
| `store` | Store de la app (`ios`, `android`) |
| `country` | Código de país del usuario (ISO 3166-1 alpha-2) |
| `ip_address` | Dirección IP del cliente |
| `idfa` | Identificador para anunciantes de iOS |
| `idfv` | Identificador para vendors de iOS |
| `gaid` | ID de publicidad de Google (Android) |
| `android_id` | ID de dispositivo Android |
| `app_set_id` | App Set ID de Android |
| `channel` | Canal de atribución |
| `campaign_id` | Identificador de campaña |
| `campaign_name` | Nombre de la campaña |
| `adset_id` | Identificador del conjunto de anuncios |
| `adset_name` | Nombre del conjunto de anuncios |
| `ad_id` | Identificador del anuncio |
| `ad_name` | Nombre del anuncio |
| `keyword_id` | Identificador de palabra clave |
| `keyword_name` | Nombre de la palabra clave |
| `asa_org_id` | ID de organización de Apple Search Ads |
| `asa_keyword_match_type` | Tipo de concordancia de palabra clave ASA (`Exact`, `Broad`) |
| `asa_attribution` | Datos de atribución ASA (cadena JSON) |
| `asa_conversion_type` | Tipo de conversión ASA |
| `asa_country_or_region` | País o región ASA |
| `asa_creative_set_name` | Nombre del conjunto creativo ASA |
| `fbclid` | Click ID de Facebook |
| `ttclid` | Click ID de TikTok |
| `utm_source` | Parámetro de fuente UTM |
| `utm_medium` | Parámetro de medio UTM |
| `utm_campaign` | Parámetro de campaña UTM |
| `utm_term` | Parámetro de término UTM |
| `utm_content` | Parámetro de contenido UTM |
---
# File: adapty-mail
---
---
title: "Adapty Mail"
description: "Campañas de email generadas por IA que convierten usuarios en período de prueba en suscriptores de pago."
---
Las integraciones ofrecen las siguientes opciones de configuración que afectan a todos los eventos enviados a través de ella:
| Ajuste | Descripción |
|:--------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Reporting Proceeds** | Selecciona cómo se presentan los valores de ingresos: netos de las comisiones de App Store y Play Store, o brutos (antes de deducciones). Activa la casilla "Send sales as proceeds" para mostrar las ventas como ingresos netos tras descontar las comisiones de App Store / Play Store. |
| **Send Trial Price** | Si está marcado, Adapty transmitirá el precio de la suscripción para el evento Trial Started. |
| **Exclude Historical Events** | Elige excluir los eventos que ocurrieron antes de que el usuario instalara la app con el SDK de Adapty. Esto evita la duplicación de eventos y garantiza informes precisos. Por ejemplo, si un usuario activó una suscripción mensual el 10 de enero y actualizó la app con el SDK de Adapty el 6 de marzo, Adapty omitirá los eventos anteriores al 6 de marzo y conservará los posteriores. |
| **Report User's Currency** | Elige si las ventas se reportan en la divisa del usuario o en USD. |
| **Send User Attributes** | Si deseas enviar atributos específicos del usuario, como preferencias de idioma, y tu plan de OneSignal admite más de 10 etiquetas, selecciona esta opción. Al activarla, se permite incluir información adicional más allá de las 10 etiquetas predeterminadas. Ten en cuenta que superar los límites de etiquetas puede generar errores. |
| **Send Attributions** | Activa esta opción para transmitir información de atribución (por ejemplo, atribución de AppsFlyer) y recibir los detalles correspondientes. |
| **Send Play Store purchase token** | Activa esta opción para recibir el token de Play Store necesario para revalidar la compra si es preciso. Añadirá el parámetro `play_store_purchase_token` al evento. |
| **Delay events with future datetime** | **Solo para AppsFlyer y webhooks personalizados**: Cuando está activado, los eventos de renovación y conversión de trial se envían en la fecha en que realmente ocurren. Cuando está desactivado (por defecto), estos eventos se envían en cuanto se detectan, aunque la fecha sea futura. |
| **Data residency** | **Solo para Mixpanel y Amplitude**: Selecciona la residencia de datos para determinar dónde se procesan y almacenan tus eventos. |
## Configurar los eventos \{#configure-the-events\}
Debajo de las credenciales encontrarás tres grupos de eventos que puedes enviar a la plataforma de integración seleccionada desde Adapty. Debes activar los que necesites.
Es importante tener en cuenta que la personalización de nombres de eventos está disponible en ciertas integraciones, mientras que en otras los nombres de eventos están fijos y no se pueden modificar. Además, con determinadas integraciones como [Airbridge](airbridge#configure-events-and-tags), por ejemplo, tienes la flexibilidad de asociar varios nombres de eventos a un único evento de Adapty. Consulta la lista completa de eventos que ofrece Adapty [aquí](events).
Aunque recomendamos utilizar los nombres de eventos predeterminados de Adapty, tienes la libertad de adaptarlos según tus necesidades específicas.
---
# File: events
---
---
title: "Eventos para enviar a integraciones de terceros"
description: "Realiza el seguimiento de los eventos clave de suscripción con las herramientas de análisis de Adapty."
---
Apple y Google envían los eventos de suscripción directamente a los servidores mediante las [Notificaciones del servidor de App Store](enable-app-store-server-notifications) y las [Notificaciones de desarrollador en tiempo real (RTDN)](enable-real-time-developer-notifications-rtdn). Como resultado, las apps móviles no pueden enviar eventos a los sistemas de análisis en tiempo real de forma fiable. Por ejemplo, si un usuario se suscribe pero nunca vuelve a abrir la app, el desarrollador no recibirá ninguna actualización del estado de la suscripción sin un servidor.
Adapty cubre esta brecha recopilando datos de suscripción y convirtiéndolos en eventos legibles. Estos eventos de integración se envían en formato JSON. Aunque todos los eventos comparten la misma estructura, sus campos varían según el tipo de evento, el store y la configuración específica. Puedes consultar los campos exactos incluidos en cada evento en las páginas de integración correspondientes.
Para entender cómo determinar si un evento se procesó correctamente o si algo salió mal, consulta la página de [estados de eventos](event-statuses).
## Tipos de eventos \{#event-types\}
La mayoría de los eventos se crean y envían a todas las integraciones configuradas si están habilitadas. Sin embargo, el evento **Access level updated** solo se activa si la [integración de webhook](webhook) está configurada y este evento está habilitado. Este evento aparecerá en el [Event Feed](https://app.adapty.io/event-feed) y también se enviará al webhook, pero no se compartirá con otras integraciones.
Si no hay ninguna integración de webhook configurada o este tipo de evento no está habilitado, el evento **Access level updated** no se creará y no aparecerá en el [Event Feed](https://app.adapty.io/event-feed).
| Nombre del evento | Descripción |
|:-----------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| subscription_started | Se activa cuando un usuario activa una suscripción de pago sin período de prueba, es decir, se le cobra de inmediato. |
| subscription_renewed | Ocurre cuando se renueva una suscripción y se cobra al usuario. Este evento comienza a partir de la segunda facturación, tanto en suscripciones con prueba como sin ella. |
| subscription_renewal_cancelled | El usuario ha desactivado la renovación automática de la suscripción. El usuario conserva el acceso a las funciones premium hasta el final del período de suscripción pagado. |
| subscription_renewal_reactivated | Se activa cuando un usuario reactiva la renovación automática de la suscripción. |
| subscription_expired | Se activa cuando una suscripción finaliza por completo tras ser cancelada. Por ejemplo, si un usuario cancela una suscripción el 12 de diciembre pero esta permanece activa hasta el 31 de diciembre, el evento se registra el 31 de diciembre cuando la suscripción expira. |
| subscription_paused | Ocurre cuando un usuario activa la [pausa de suscripción](https://developer.android.com/google/play/billing/lifecycle/subscriptions#pause) (solo Android). |
| subscription_deferred | Se activa cuando una compra de suscripción se [aplaza](https://adapty.io/glossary/subscription-purchase-deferral/), lo que permite a los usuarios retrasar el pago manteniendo el acceso a las funciones premium. Esta función está disponible a través de la Google Play Developer API y puede usarse para pruebas gratuitas o para ayudar a usuarios con dificultades económicas. |
| non_subscription_purchase | Cualquier compra que no sea una suscripción, como el acceso de por vida o productos consumibles como monedas del juego. |
| trial_started | Se activa cuando un usuario activa una suscripción de prueba. |
| trial_converted | Ocurre cuando finaliza una prueba y se cobra al usuario (primera compra). Por ejemplo, si un usuario tiene una prueba hasta el 14 de enero pero se le cobra el 7 de enero, este evento se registra el 7 de enero. |
| trial_renewal_cancelled | El usuario desactivó la renovación automática de la suscripción durante el período de prueba. El usuario conserva el acceso a las funciones premium hasta que finalice la prueba, pero no se le cobrará ni comenzará una suscripción. |
| trial_renewal_reactivated | Ocurre cuando un usuario reactiva la renovación automática de la suscripción durante el período de prueba. |
| trial_expired | Se activa cuando finaliza una prueba sin convertirse en suscripción. |
| entered_grace_period | Ocurre cuando falla un intento de pago y el usuario entra en un período de gracia (si está habilitado). El usuario conserva el acceso premium durante este tiempo. |
| billing_issue_detected | Se activa cuando ocurre un problema de facturación durante un intento de cobro (p. ej., saldo insuficiente en la tarjeta). |
| subscription_refunded | Se activa cuando se reembolsa una suscripción (p. ej., por parte del soporte de Apple). |
| non_subscription_purchase_refunded | Se activa cuando se reembolsa una compra que no es una suscripción. |
| access_level_updated | Ocurre cuando se actualiza el nivel de acceso de un usuario. |
Los eventos anteriores cubren completamente el estado de los usuarios en cuanto a compras. Veamos algunos ejemplos.
### Ejemplo 1 \{#example-1\}
_El usuario activó una suscripción mensual el 1 de abril con un periodo de prueba de 7 días. El día 4, se dio de baja._
En ese caso, se enviarán los siguientes eventos:
1. `trial_started` el 1 de abril
2. `trial_renewal_cancelled` el 4 de abril
3. `trial_expired` el 7 de abril
### Ejemplo 2 \{#example-2\}
_El usuario activó una suscripción mensual el 1 de abril con un periodo de prueba de 7 días. El día 10, se dio de baja._
En ese caso, se enviarán los siguientes eventos:
1. `trial_started` el 1 de abril
2. `trial_converted` el 7 de abril
3. `subscription_renewal_cancelled` el 10 de abril
4. `subscription_expired` el 1 de mayo
Para un desglose detallado de qué eventos se activan en cada escenario, consulta los [flujos de eventos](event-flows).
---
# File: event-flows
---
---
title: "Flujos de eventos"
description: "Descubre esquemas detallados de flujos de eventos de suscripción en Adapty. Aprende cómo se generan y envían los eventos de suscripción a las integraciones, lo que te ayuda a rastrear los momentos clave en el recorrido de tus clientes."
---
En Adapty, recibirás distintos eventos de suscripción a lo largo del ciclo de vida de un cliente en tu app. Estos flujos de suscripción describen los escenarios más habituales para ayudarte a entender qué eventos genera Adapty cuando los usuarios se suscriben, cancelan o reactivan suscripciones.
Ten en cuenta que Apple procesa los pagos de suscripción varias horas antes del inicio/renovación real. En los flujos siguientes, mostramos el inicio/renovación de la suscripción y el cargo al mismo tiempo para mantener los diagramas claros.
Además, los eventos relacionados con la misma acción ocurren de forma simultánea y pueden aparecer en tu **Event Feed** en cualquier orden, que podría diferir de la secuencia mostrada en nuestros diagramas.
## Ciclo de vida de una suscripción \{#subscription-lifecycle\}
### Flujo de compra inicial \{#initial-purchase-flow\}
Este flujo ocurre cuando un cliente compra una suscripción por primera vez sin período de prueba. En esta situación, se crean los siguientes eventos:
- **Subscription started**
- **Access level updated** para conceder acceso al usuario
Cuando llega la fecha de renovación de la suscripción, esta se renueva. En ese caso, se crean los siguientes eventos:
- **Subscription renewal** para iniciar un nuevo período de la suscripción
- **Access level updated** para actualizar la fecha de vencimiento de la suscripción y extender el acceso por otro período
Las situaciones en las que el pago no se realiza correctamente o el usuario cancela la renovación se describen en [Flujo de resultado por problema de facturación](event-flows#billing-issue-outcome-flow) y [Flujo de cancelación de suscripción](event-flows#subscription-cancellation-flow), respectivamente.
### Flujo de cancelación de suscripción \{#subscription-cancellation-flow\}
Cuando un usuario cancela su suscripción, se crean los siguientes eventos:
- **Subscription renewal canceled** para indicar que la suscripción sigue activa hasta el final del período actual, tras el cual el usuario perderá el acceso
- El evento **Access level updated** se crea para deshabilitar la renovación automática del nivel de acceso
Una vez que finaliza la suscripción, se activa el evento **Subscription expired (churned)** para marcar el fin de la suscripción.
Si se aprueba un reembolso, el siguiente evento reemplaza a **Subscription expired (churned)**:
- **Subscription refunded** para finalizar la suscripción y proporcionar detalles sobre el reembolso
En Stripe, una suscripción puede cancelarse de forma inmediata, saltándose el período restante. En ese caso, todos los eventos se crean simultáneamente:
- **Subscription renewal cancelled**
- **Subscription expired (churned)**
- **Access Level updated** para revocar el acceso del usuario
Si se aprueba un reembolso, también se activa el evento **Subscription refunded** cuando se aprueba.
### Flujo de reactivación de suscripción \{#subscription-reactivation-flow\}
Si un usuario cancela una suscripción, esta expira y luego vuelve a comprar la misma suscripción, se creará un evento **Subscription renewed**. Aunque haya un período sin acceso, Adapty lo trata como una única cadena de transacciones vinculadas por el `vendor_original_transaction_id`. Por eso, la recompra se considera una renovación.
Los eventos **Access level updated** se crearán dos veces:
- al finalizar la suscripción, para revocar el acceso del usuario
- al recomprar la suscripción, para conceder el acceso
### Flujo de pausa de suscripción (solo Android) \{#subscription-pause-flow-android-only\}
Este flujo aplica cuando un usuario pausa y luego reanuda una suscripción en Android.
Pausar una suscripción tiene efectos diferidos. Si un usuario pausa una suscripción antes de que se renueve, la suscripción sigue activa y el usuario mantiene el acceso de pago por el resto del período de facturación.
1. Cuando el usuario pausa una suscripción, se activa el evento **Subscription paused (Android only)**.
2. Al final del período de suscripción, Adapty activa el evento **Access level updated** para revocar el acceso del usuario.
3. Cuando el usuario reanuda la suscripción, se activan los siguientes eventos:
- **Subscription renewed**
- **Access level updated** para restablecer el acceso del usuario
Estas suscripciones pertenecerán a la misma cadena de transacciones, vinculadas con el mismo **vendor_original_transaction_id**.
## Flujos de prueba \{#trial-flows\}
Si usas períodos de prueba en tu app, recibirás eventos adicionales relacionados con ellos.
### Flujo de prueba con conversión exitosa \{#trial-with-successful-conversion-flow\}
El flujo más habitual ocurre cuando un usuario inicia una prueba, introduce una tarjeta de crédito y se convierte en suscriptor estándar al finalizar el período de prueba. En este caso, se crean los siguientes eventos en el momento en que comienza la prueba:
- **Trial started** para marcar el inicio de la prueba
- **Access level updated** para conceder acceso
El evento **Trial converted** se crea cuando comienza la suscripción estándar.
### Flujo de prueba sin conversión exitosa \{#trial-without-successful-conversion-flow\}
Si un usuario cancela la prueba antes de que se convierta en una suscripción, se crean los siguientes eventos en el momento de la cancelación:
- **Trial renewal cancelled** para deshabilitar la conversión automática de la prueba en una suscripción
- **Access level updated** para deshabilitar la renovación del acceso
El usuario mantendrá el acceso hasta el final del período de prueba, momento en el que se crea el evento **Trial expired** para marcar su fin.
### Reactivación de suscripción tras un período de prueba expirado \{#subscription-reactivation-after-expired-trial-flow\}
Si un período de prueba expira (por un problema de facturación o cancelación) y el usuario compra una suscripción posteriormente, se crean los siguientes eventos:
- **Access level updated** para conceder acceso al usuario
- **Trial converted**
Aunque haya un intervalo entre el período de prueba y la suscripción, Adapty vincula ambos mediante `vendor_original_transaction_id`. Esta conversión se trata como parte de una cadena de transacciones continua que comienza con un período de prueba de precio cero. Por eso se crea el evento **Trial converted** en lugar de **Subscription started**.
## Cambios de producto \{#product-changes\}
Esta sección recoge los cambios realizados en suscripciones activas, como actualizaciones, degradaciones o compras de un producto de otro grupo.
### Flujo de cambio inmediato de producto \{#immediate-product-change-flow\}
Cuando un usuario cambia de producto, el cambio puede aplicarse en el sistema de forma inmediata antes de que finalice la suscripción (principalmente en casos de mejora o sustitución de producto). En ese momento, al producirse el cambio de producto:
- El nivel de acceso cambia y se crean dos eventos **Access level updated**:
1. Para retirar el acceso al primer producto.
2. Para conceder acceso al segundo producto.
- La suscripción antigua finaliza y se emite un reembolso (se crea el evento **Subscription refunded** con `cancellation_reason` = `upgraded`). Ten en cuenta que no se crea ningún evento **Subscription expired (churned)**; el evento **Subscription refunded** lo reemplaza.
- La nueva suscripción comienza (se crea el evento **Subscription started** para el nuevo producto).
Si un usuario cambia a un plan inferior, la primera suscripción se mantendrá activa hasta el final del período pagado, y cuando termine, será reemplazada por la nueva suscripción de nivel inferior. En este caso, solo se creará de inmediato el evento **Access level updated** para deshabilitar la renovación automática del acceso. El resto de eventos se crearán en el momento en que se produzca el cambio real de suscripción:
- Se crea otro evento **Access level updated** para dar acceso al segundo producto.
- Se crea el evento **Subscription expired (churned)** para finalizar la suscripción del primer producto.
- Se crea el evento **Subscription started** para iniciar una nueva suscripción con el nuevo producto.
### Flujo de cambio de producto diferido \{#delayed-product-change-flow\}
También existe una variante en la que el usuario cambia el producto en el momento de la renovación de la suscripción. Esta variante es muy similar a la anterior: se creará un evento **Access level updated** de inmediato para desactivar la renovación automática del acceso del producto antiguo. El resto de eventos se crearán en el momento en que el usuario realice el cambio de suscripción y este quede registrado en el sistema:
- Se crea otro evento **Access level updated** para conceder acceso al segundo producto.
- Se crea el evento **Subscription expired (churned)** para finalizar la suscripción del primer producto.
- Se crea el evento **Subscription started** para iniciar una nueva suscripción con el nuevo producto.
## Flujo de resultados por problemas de facturación \{#billing-issue-outcome-flow\}
Si los intentos de convertir una prueba o renovar una suscripción fallan por un problema de facturación, lo que ocurre a continuación depende de si hay un período de gracia habilitado.
Con un período de gracia, si el pago tiene éxito, la prueba se convierte o la suscripción se renueva. Si falla, el store seguirá intentando cobrar al usuario por la suscripción y, si sigue fallando, el store terminará la prueba o suscripción por su cuenta.
Por lo tanto, en el momento del problema de facturación, se crean los siguientes eventos en Adapty:
- **Billing issue detected**
- **Entered grace period** (si el período de gracia está habilitado)
- **Access level updated** para mantener el acceso hasta el final del período de gracia
Si el pago se realiza correctamente después, Adapty registra un evento **Trial converted** o **Subscription renewed**, y el usuario no pierde el acceso.
Si el pago falla definitivamente y el store cancela la suscripción, Adapty genera estos eventos:
- **Trial expired** o **Subscription expired (churned)** con `cancellation_reason: billing_error`
- **Access level updated** para revocar el acceso del usuario
Sin un período de gracia, el período de reintento de facturación (el período en el que el store intenta cobrar al usuario de nuevo) comienza de inmediato.
Si el pago nunca se completa antes de que finalice el período de gracia, el flujo es el mismo: se crean los mismos eventos cuando el store termina la suscripción automáticamente:
- Evento **Trial expired** o **Subscription expired (churned)** con un `cancellation_reason` de `billing_error`
- **Access level updated** para revocar el acceso del usuario
## Flujos para compartir compras entre cuentas de usuario \{#sharing-purchases-across-user-accounts-flows\}
Cuando un
A continuación se explican los campos relacionados con la asignación y transferencia del nivel de acceso en los eventos generados en este escenario:
- **Usuario A: Nivel de acceso actualizado (se envía cuando el Usuario A compra una suscripción en la app)**
```json showLineNumbers
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": UserA,
"event_properties": {
"profile_has_access_level": true,
},
"profiles_sharing_access_level": null
}
```
- **Usuario A: Nivel de acceso actualizado (se envía cuando la app se reinstala y el Usuario B inicia sesión, revocando el acceso del Usuario A)**
```json showLineNumbers
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": UserA,
"event_properties": {
"profile_has_access_level": false,
},
"profiles_sharing_access_level": null
}
```
- **Usuario B: Nivel de acceso actualizado (enviado cuando el Usuario B inicia sesión y se concede el acceso)**
```json showLineNumbers
{
"profile_id": "00000000-0000-0000-0000-000000000001",
"customer_user_id": UserB,
"event_properties": {
"profile_has_access_level": true,
},
"profiles_sharing_access_level": null
}
```
### Flujo de acceso compartido entre usuarios \{#shared-access-between-users-flow\}
Esta opción permite que varios usuarios compartan el mismo nivel de acceso si su dispositivo está conectado con el mismo Apple/Google ID. Resulta útil cuando un usuario reinstala la app e inicia sesión con un correo diferente: seguirá teniendo acceso a su compra anterior. Con esta opción, varios usuarios identificados pueden compartir el mismo nivel de acceso. Aunque el nivel de acceso se comparte, todas las transacciones se registran bajo el
A continuación se describen los campos relacionados con la asignación y el uso compartido del nivel de acceso en los eventos generados en este escenario:
**Usuario B: Access level updated (enviado cuando el Usuario B inicia sesión y se concede el acceso)**
```json showLineNumbers
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": UserA,
"event_properties": {
"profile_has_access_level": true,
},
"profiles_sharing_access_level": [
{
"profile_id": "00000000-0000-0000-0000-000000000001,
"customer_user_id": UserB
}
]
}
```
### Flujo de acceso no compartido entre usuarios \{#access-not-shared-between-users-flow\}
Con esta opción, solo el primer perfil de usuario que recibe el nivel de acceso lo conserva de forma permanente. Es ideal cuando las compras deben vincularse a un único
---
# File: event-statuses
---
---
title: "Estados de los eventos de integración"
description: ""
---
Adapty determina la entregabilidad en función del código de estado HTTP, considerando cualquier respuesta fuera del rango `200-399` como un error.
Puedes hacer seguimiento del estado de los eventos de integración en la **Event List** dentro del Adapty Dashboard. El sistema muestra los estados de todas las integraciones habilitadas, independientemente de si un tipo de evento específico está activado para una integración concreta.
- Negro: El evento se envió correctamente.
- Gris: El tipo de evento está deshabilitado para esta integración.
- Rojo: Hay un problema con la integración que requiere atención.
Para más detalles sobre los eventos fallidos, pasa el cursor sobre el nombre de la integración para ver un tooltip con información específica del error.
El **Event Feed** muestra datos de las últimas dos semanas para optimizar el rendimiento. Esta limitación mejora la velocidad de carga de la página, lo que facilita a los usuarios navegar y analizar los eventos de forma eficiente.
---
# File: adjust
---
---
title: "Adjust"
description: "Conecta Adjust con Adapty para un mejor seguimiento de suscripciones y análisis."
---
[Adjust](https://www.adjust.com/) es una de las principales plataformas Mobile Measurement Partner (MMP) que recopila y presenta datos de campañas de marketing. Esto ayuda a las empresas a hacer seguimiento del rendimiento de sus campañas.
Adapty proporciona un conjunto completo de datos que te permite rastrear [eventos de suscripción](events) desde los stores en un solo lugar. Con Adapty, puedes ver fácilmente cómo se comportan tus suscriptores, entender qué les gusta y usar esa información para comunicarte con ellos de forma dirigida y efectiva. Por eso, esta integración te permite rastrear eventos de suscripción en Adjust y analizar con precisión cuántos ingresos generan tus campañas.
La integración entre Adapty y Adjust funciona de dos maneras principales.
1. **Adapty recibe datos de atribución de Adjust**
Una vez que hayas configurado la integración con Adjust, Adapty comenzará a recibir datos de atribución de Adjust. Puedes acceder a estos datos fácilmente y consultarlos en la página de perfil del usuario.
2. **Adapty envía eventos de suscripción a Adjust**
Adapty puede enviar todos los eventos de suscripción configurados en tu integración a Adjust. Como resultado, podrás hacer seguimiento de estos eventos desde el dashboard de Adjust. Esta integración es útil para evaluar la efectividad de tus campañas publicitarias.
## Configurar la integración \{#set-up-integration\}
### Conectar Adapty con Adjust
1. Abre el Adapty Dashboard y ve a [Integrations > Adjust](https://app.adapty.io/integrations/adjust).
2. Activa el toggle en la parte superior de la página.
3. Rellena los campos e introduce tus credenciales de acceso.
3. Si habilitaste la autorización OAuth en la plataforma de Adjust, es obligatorio proporcionar un **OAuth Token** durante el proceso de integración para tus apps de iOS y Android.
4. A continuación, proporciona los **app tokens** para tus apps de iOS y Android. Abre tu dashboard de Adjust y verás tus apps.
:::note
Puede que tengas aplicaciones de Adjust distintas para iOS y Android, por lo que en Adapty dispones de dos secciones independientes para ello. Si solo tienes una aplicación de Adjust, introduce la misma información en ambas.
:::
5. Selecciona tu aplicación de la lista y copia el **App Token**. Pega el token en el campo correspondiente del Adapty Dashboard.
### Configurar eventos y etiquetas \{#configure-events-and-tags\}
Adjust funciona de forma un poco diferente al resto de plataformas. Necesitas crear los eventos manualmente en el dashboard de Adjust, obtener los tokens de evento y copiarlos en los eventos correspondientes de Adapty.
Por tanto, el primer paso es encontrar los tokens de evento de todos los eventos que quieres que Adapty envíe. Para ello:
1. En el dashboard de Adjust, abre tu app y cambia a la pestaña **Events**.
1. Copia el token del evento y pégalo en Adapty. Debajo de las credenciales, hay tres grupos de eventos que puedes enviar a Adjust desde Adapty. Consulta la lista completa de eventos que ofrece Adapty [aquí](events).
Adapty enviará eventos de suscripción a Adjust mediante una integración servidor a servidor, lo que te permitirá ver todos los eventos de suscripción en tu dashboard de Adjust y vincularlos a tus campañas de adquisición.
:::important
Ten en cuenta lo siguiente:
- Adjust no admite eventos con más de 58 días de antigüedad. Si tienes un evento que supera ese límite, Adapty lo enviará a Adjust, pero la fecha y hora del evento se reemplazará por la marca de tiempo actual.
- Adjust no admite IPv6. Si desactivas la recopilación de IP en el SDK en **App settings** o al activar el SDK, puede enviarse únicamente una IPv6 del backend y el seguimiento puede fallar — mantén la recopilación de IP del SDK habilitada para garantizar el uso de IPv4.
:::
### Conecta tu app con Adjust
Después de completar los pasos descritos anteriormente, añade los siguientes dos métodos a tu app. Establecerán la comunicación entre tu app y Adjust:
1. **Para enviar datos de suscripción a Adjust**: Pasa el ID de dispositivo de Adjust al método del SDK `setIntegrationIdentifier()`
2. **Para recibir datos de atribución desde Adjust**: Actualiza los datos de atribución con el método del SDK `updateAttribution()`
Para Adjust versión 5.0 o posterior, usa el siguiente ejemplo:
Ambos se encuentran en tu dashboard de Airbridge, en la sección [Third-party Integrations > Adapty](https://app.airbridge.io/app/testad/integrations/third-party/adapty).
El campo del token de API de Adapty se genera previamente en el backend de Adapty. Debes copiar el valor del token de API de Adapty y pegarlo en el dashboard de Airbridge en el campo Adapty Authorization Token.
### Configurar eventos y etiquetas \{#configure-events-and-tags\}
Debajo de las credenciales encontrarás tres grupos de eventos que puedes enviar a Airbridge desde Adapty.
Simplemente activa los que necesites.
### Conectar tu app con Airbridge \{#connect-your-app-to-airbridge\}
Para la integración, debes pasar `airbridge_device_id` al perfil y llamar a `setIntegrationIdentifier` tal como se muestra en el siguiente ejemplo:
## Configurar la integración \{#set-up-integration\}
### Conectar Adapty con el framework AdServices \{#connect-adapty-to-the-adservices-framework\}
Apple Ads a través de [AdServices](https://developer.apple.com/documentation/adservices) requiere cierta configuración en el Adapty Dashboard, y también necesitarás habilitarlo en el lado de la app. Para configurar Apple Ads usando el framework AdServices a través de Adapty, sigue estos pasos:
#### Paso 1: Obtener la clave pública \{#step-1-obtain-public-key\}
En el Adapty Dashboard, ve a [Settings -> Apple Ads.](https://app.adapty.io/settings/apple-search-ads)
Localiza la clave pública pregenerada (Adapty te proporciona un par de claves) y cópiala.
:::note
Si utilizas un servicio alternativo o tu propia solución para la atribución de Apple Ads, puedes subir tu propia clave privada.
:::
#### Paso 2: Configura la gestión de usuarios en Apple Ads \{#step-2-configure-user-management-on-apple-ads\}
En tu [cuenta de Apple Ads](https://ads.apple.com/app-store), ve a la página **Settings > User Management**. Para que Adapty pueda obtener datos de atribución, necesitas invitar otra cuenta de Apple ID y concederle acceso como API Account Manager. Puedes usar cualquier cuenta a la que tengas acceso o crear una nueva exclusivamente para este fin. Lo importante es que debas poder iniciar sesión en Apple Ads con ese Apple ID.
#### Paso 3: Generar credenciales de API \{#step-3-generate-api-credentials\}
Como siguiente paso, inicia sesión en la cuenta recién añadida en Apple Ads. Ve a Settings -> API en la interfaz de Apple Ads. Pega la clave pública copiada anteriormente en el campo correspondiente. Genera nuevas credenciales de API.
#### Paso 4: Configurar Adapty con las credenciales de Apple Ads \{#step-4-configure-adapty-with-apple-ads-credentials\}
Copia los campos Client ID, Team ID y Key ID de la configuración de Apple Ads. En el Adapty Dashboard, pega estas credenciales en los campos correspondientes.
### Conectar tu app a la red AdServices \{#connect-your-app-to-the-adservices-network\}
Una vez que completes [la configuración del framework AdServices](#connect-the-adservices-framework), Adapty empieza a recopilar automáticamente los datos de atribución de Apple Search Ads. No necesitas añadir ningún código al SDK.
En aplicaciones iOS, estos datos de atribución **siempre** tendrán prioridad sobre los datos de otras fuentes. Si este comportamiento no es el deseado, *desactiva* la atribución de ASA siguiendo las instrucciones a continuación.
## Desactivar la integración \{#disable-integration\}
Para desactivar la atribución de Apple Search Ads, abre la pestaña [**App Settings** -> **Apple Search Ads**](https://app.adapty.io/settings/apple-search-ads) y desactiva el interruptor **Receive Apple Search Ads attribution**.
:::warning
Ten en cuenta que desactivar esto detendrá por completo la recepción de datos de análisis de ASA. Como resultado, ASA dejará de utilizarse en el análisis y no se enviará a las integraciones. Además, SplitMetrics Acquire y Asapty dejarán de funcionar, ya que dependen de la atribución de ASA para operar correctamente.
La atribución recibida antes de este cambio no se verá afectada.
:::
## Subir tus propias claves \{#uploading-your-own-keys\}
:::note
Opcional
Estos pasos no son necesarios para la atribución de Apple Ads, solo para trabajar con otros servicios como Asapty o tu propia solución.
:::
Puedes usar tu propio par de claves pública-privada si estás utilizando otros servicios o una solución propia para la atribución de ASA.
### Paso 1 \{#step-1\}
Genera la clave privada en el Terminal
```text showLineNumbers title="Text"
openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem
```
Súbela en Adapty Settings -> Apple Ads (botón Upload private key)
### Paso 2 \{#step-2\}
Genera la clave pública en el Terminal
```text showLineNumbers title="Text"
openssl ec -in private-key.pem -pubout -out public-key.pem
```
Puedes usar esta clave pública en los ajustes de Apple Ads de la cuenta con el rol API Account Manager. Así podrás usar los valores generados de Client ID, Team ID y Key ID tanto en Adapty como en otros servicios.
---
# File: switch-from-appsflyer-s2s-api-2-to-3
---
---
title: "Cambiar de AppsFlyer S2S API 2 a 3"
description: "Actualiza de AppsFlyer S2S API 2 a 3 en Adapty."
---
Según las [novedades oficiales de AppsFlyer](https://support.appsflyer.com/hc/en-us/articles/20509378973457-Bulletin-Upgrading-the-AppsFlyer-S2S-API), para ofrecer un uso más seguro de la API y reducir el fraude, AppsFlyer ha actualizado su API servidor a servidor (S2S) para eventos in-app. El endpoint actual quedará obsoleto en el futuro, por lo que recomendamos empezar a planificar la migración.
Adapty es compatible con AppsFlyer S2S API 3 y te permite realizar el cambio desde API 2 sin complicaciones. Ten en cuenta que este cambio es unidireccional, por lo que no podrás volver a API 2 una vez realizado.
Para cambiar de AppsFlyer S2S API 2 a 3:
1. Abre el [sitio de AppsFlyer](https://www.appsflyer.com/home) e inicia sesión.
2. Haz clic en **Tu nombre de cuenta** -> **Security Center** en la esquina superior izquierda del dashboard.
3. En la ventana **Manage your account security**, haz clic en el botón **Manage your AppsFlyer API and S2S tokens**.
4. Si no tienes un token S2S, haz clic en el botón **New token**. Si ya lo tienes, continúa con el paso 8.
5. En la ventana **New token**, introduce el nombre del token. Este nombre es solo para tu referencia.
6. Selecciona **S2S** en la lista **Choose type**.
7. No olvides hacer clic en el botón **Create new token** para guardar el nuevo token.
8. En la ventana **Tokens**, copia el token S2S.
9. Abre [**Integrations** -> **AppsFlyer**](https://app.adapty.io/integrations/appsflyer) en el Adapty Dashboard.
10. En el campo **AppsFlyer S2S API**, selecciona **API 3**.
11. Pega la clave S2S copiada en los campos **Dev key for iOS** y **Dev key for Android**.
12. Haz clic en el botón **Save** para confirmar el cambio.
En ese momento, tu integración cambia instantáneamente a AppsFlyer S2S API 3 y los nuevos eventos se enviarán a la nueva URL: `https://api3.appsflyer.com/inappevent`.
---
# File: asapty
---
---
title: "Asapty"
description: "Descubre Asapty y su papel en el ecosistema de suscripciones de Adapty."
---
Con la integración de [Asapty](https://asapty.com/) puedes optimizar tus campañas de Search Ads. Adapty envía eventos de suscripción a Asapty para que puedas crear dashboards personalizados basados en la atribución de Apple Search Ads.
Esta integración en concreto no añade ningún dato de atribución a Adapty, ya que obtenemos todo lo necesario directamente desde [ASA](apple-search-ads).
## Configurar la integración \{#set-up-integration\}
### Conectar Adapty con Asapty \{#connect-adapty-to-asapty\}
Para integrar Asapty, ve a [Integrations > Asapty](https://app.adapty.io/integrations/asapty) en el Adapty Dashboard y rellena el campo con tu Asapty ID.
El Asapty ID se encuentra en la sección Settings > General de tu cuenta de Asapty.
### Configurar eventos y etiquetas \{#configure-events-and-tags\}
Justo debajo de las credenciales encontrarás tres grupos de eventos que puedes enviar a Asapty desde Adapty. Activa únicamente los que necesites. Consulta la lista completa de eventos que ofrece Adapty [aquí](events).
Recomendamos usar los nombres de evento predeterminados que proporciona Asapty, aunque puedes cambiarlos según tus necesidades.
### Conectar tu app con Asapty \{#connect-your-app-to-asapty\}
Una vez completados los pasos anteriores, Adapty recibe automáticamente los datos de atribución de Asapty. No es necesario solicitar explícitamente esos datos en el código de tu aplicación. Para mejorar la precisión de la atribución, configura Asapty para que incluya el `customerUserId` en los datos de cada evento.
## Estructura de eventos de Asapty \{#asapty-event-structure\}
Adapty envía eventos a Asapty mediante una petición GET con parámetros de consulta. Cada URL de evento tiene este aspecto:
```
https://asapty.com/_api/mmpEvents/?source=adapty&asaptyid=a1b2c3d4&keywordid=12345&adgroupid=67890&campaignid=11223&conversiondate=1709294400000&event_name=subscription_renewed&install_time=1709100000&app_name=MyApp&json=%7B%22af_revenue%22%3A%229.99%22%2C%22af_currency%22%3A%22USD%22...%7D
```
Parámetros de consulta:
| Parámetro | Tipo | Descripción |
|:-----------------|:-------|:------------------------------------------------------------------|
| `source` | String | Siempre "adapty". |
| `asaptyid` | String | El Asapty ID de tus credenciales. |
| `keywordid` | String | ID de palabra clave de Apple Search Ads (si está disponible). |
| `adgroupid` | String | ID del grupo de anuncios de Apple Search Ads (si está disponible).|
| `campaignid` | String | ID de campaña de Apple Search Ads (si está disponible). |
| `conversiondate` | Long | Marca de tiempo del evento en **milisegundos**. |
| `event_name` | String | Nombre del evento (mapeado desde el evento de Adapty). |
| `install_time` | Long | Marca de tiempo de la instalación en segundos. |
| `app_name` | String | Título de la app en Adapty (si está disponible). |
| `json` | String | Cadena JSON codificada en URL con los detalles del evento (ver más abajo). |
El parámetro `json` es una cadena JSON codificada en URL que contiene los siguientes campos:
| Parámetro | Tipo | Descripción |
|:--------------------------|:-------|:---------------------------------------------------|
| `af_revenue` | String | Importe de ingresos como cadena de texto. |
| `af_currency` | String | Código de moneda (p. ej., "USD"). |
| `transaction_id` | String | ID de transacción del store. |
| `original_transaction_id` | String | ID de transacción original del store. |
| `purchase_date` | Long | Marca de tiempo de la compra en milisegundos. |
| `original_purchase_date` | Long | Marca de tiempo de la compra original en milisegundos. |
| `environment` | String | `Production` o `Sandbox`. |
| `vendor_product_id` | String | ID del producto en el store. |
| `profile_country` | String | Código de país basado en la IP del usuario. |
| `store_country` | String | Código de país del store del usuario. |
## Solución de problemas \{#troubleshooting\}
- Asegúrate de haber configurado [Apple Search Ads](apple-search-ads) en Adapty y de haber [subido las credenciales](https://app.adapty.io/settings/apple-search-ads); sin ellas, Asapty no funcionará.
- Solo los perfiles con atribución de ASA detallada y no orgánica enviarán sus eventos a Asapty. Verás el mensaje "The user profile is missing the required integration data." si la atribución no es suficiente.
- Los perfiles creados antes de configurar las integraciones no podrán enviar sus eventos a Asapty.
- Si la integración con Adapty no funciona a pesar de estar correctamente configurada, comprueba que el toggle **Receive Apple Search Ads attribution in Adapty** esté activado en la pestaña [**App Settings** -> **Apple Search Ads**](https://app.adapty.io/settings/apple-search-ads).
---
# File: branch
---
---
title: "Branch"
description: "Integra Branch con Adapty para rastrear deep links y conversiones de la app."
---
[Branch](https://www.branch.io/) permite a las empresas llegar a sus usuarios, interactuar con ellos y analizar resultados en distintos dispositivos, canales y plataformas. Es una plataforma intuitiva diseñada para aumentar los ingresos móviles mediante enlaces especializados que funcionan sin problemas en todos los dispositivos, canales y plataformas.
Adapty ofrece un conjunto completo de datos que te permite rastrear [eventos de suscripción](events) desde los stores en un solo lugar. Con Adapty, puedes ver fácilmente el comportamiento de tus suscriptores, conocer sus preferencias y usar esa información para comunicarte con ellos de forma dirigida y efectiva.
La integración entre Adapty y Branch funciona de dos maneras principales.
1. **Recibir datos de atribución de Branch**
Una vez que hayas configurado la integración con Branch, Adapty comenzará a recibir datos de atribución de Branch. Puedes consultar y ver estos datos fácilmente en la página del perfil del usuario.
2. **Envío de eventos de suscripción a Branch**
Adapty puede enviar todos los eventos de suscripción configurados en tu integración a Branch. Como resultado, podrás hacer seguimiento de estos eventos desde el dashboard de Branch.
## Configurar la integración \{#set-up-integration\}
### Conectar Adapty con Branch
Para integrar Branch, ve a [Integrations > Branch](https://app.adapty.io/integrations/branch) en el Adapty Dashboard, activa el interruptor y rellena los campos.
Para obtener el valor de **Branch Key**, abre los [Ajustes de cuenta](https://dashboard.branch.io/account-settings/profile) de Branch y busca el campo **Branch Key**. Úsalo en el campo **Key test** (para Sandbox) o **Key live** (para producción) del Adapty Dashboard. En Branch, cambia entre los entornos Live y Tests para obtener la clave correspondiente.
### Configurar eventos y etiquetas \{#configure-events-and-tags\}
Debajo de las credenciales, encontrarás tres grupos de eventos que puedes enviar a Branch desde Adapty. Activa simplemente los que necesites. Consulta la lista completa de eventos que ofrece Adapty [aquí](events).
Puedes enviar un evento con los ingresos netos \(después del recorte de Apple/Google\) o solo los ingresos brutos. También puedes marcar la casilla para reportar en la moneda del usuario.
Recomendamos usar los nombres de eventos predeterminados que ofrece Adapty, aunque puedes cambiarlos según tus necesidades.
Adapty enviará eventos de suscripción a Branch mediante una integración servidor a servidor, lo que te permitirá ver todos los eventos de suscripción en tu dashboard de Branch y vincularlos a tus campañas de adquisición.
### Conecta tu app con Branch \{#connect-your-app-to-branch\}
1. Llama al método `.setIntegrationIdentifier()` del SDK para inicializar la conexión. Puedes pasar tu Branch Identity ID al parámetro `customerUserId`.
:::note
Los SDKs de terceros generan los IDs de usuario de forma asíncrona. Es posible que el ID no esté disponible cuando se ejecuta `Adapty.activate()`. Si tu **Customer User ID** proviene de uno de estos SDKs, llama a `Adapty.activate()` sin él. Una vez que el ID esté disponible, llama a `setIntegrationIdentifier()` y luego a `identify()` con el CUID.
:::
1. Para encontrar el App ID, abre la página de tu app en [App Store Connect](https://appstoreconnect.apple.com/), ve a la página **App Information** en la sección **General** y busca el **Apple ID** en la parte inferior izquierda de la pantalla.
2. Necesitas una aplicación en la plataforma [Meta for Developers](https://developers.facebook.com/). Inicia sesión en tu app y accede a la configuración avanzada. Encontrarás el **App ID** en la cabecera.
3. Desactiva el seguimiento del lado del cliente en la configuración de tu Meta SDK para evitar el doble conteo de ingresos en Meta Ads Manager. Puedes encontrar este ajuste en tu Meta Developer Console en **App Settings > Advanced Settings**. Establece **Log in-app events automatically** en "No". Esto garantizará que los eventos de ingresos solo se registren a través de la integración de Adapty.
Para rastrear eventos de instalación y uso, deberás activar el Meta SDK en tu código. Puedes encontrar los detalles de implementación en la documentación del Meta SDK para tu plataforma:
- [iOS SDK](https://developers.facebook.com/docs/ios/getting-started)
- [Android SDK](https://developers.facebook.com/docs/android/getting-started)
- [Unity SDK](https://developers.facebook.com/docs/unity/getting-started/canvas)
También puedes usar esta integración con apps Android. Si configuras la configuración del Android SDK en **App Settings**, con introducir el **Facebook App ID** es suficiente.
### Configurar eventos y etiquetas \{#configure-events-and-tags\}
Ten en cuenta que la integración de Facebook Ads está orientada específicamente a empresas que utilizan Meta para sus campañas publicitarias y las optimizan en función del comportamiento de los clientes. Es compatible con los eventos estándar de Meta para fines de optimización. Por ello, no es posible modificar el nombre del evento en la integración de Meta Ads. Adapty mapea automáticamente los eventos de tus clientes a sus correspondientes eventos de Meta para un análisis preciso.
| Evento de Adapty | Evento de Meta Ads |
| :---------------------------- | :-------------------------- |
| Subscription initial purchase | Subscribe |
| Subscription renewed | Subscribe |
| Subscription cancelled | CancelSubscription |
| Trial started | StartTrial |
| Trial converted | Subscribe |
| Trial cancelled | CancelTrial |
| Non subscription purchase | fb_mobile_purchase |
| Billing issue detected | billing_issue_detected |
| Entered grace period | entered_grace_period |
| Auto renew off | auto_renew_off |
| Auto renew on | auto_renew_on |
| Auto renew off subscription | auto_renew_off_subscription |
| Auto renew on subscription | auto_renew_on_subscription |
StartTrial, Subscribe y CancelSubscription son eventos estándar.
Para activar eventos específicos, simplemente activa los que necesites. Si se seleccionan varios nombres de eventos, Adapty consolidará los datos de todos los eventos seleccionados en un único nombre de evento de Adapty.
### Conectar tu app con Facebook Ads \{#connect-your-app-to-facebook-ads\}
Si sigues los pasos anteriores, Facebook recibirá automáticamente los datos de suscripción desde Adapty.
Tras los cambios en el IDFA en iOS 14.5, recomendamos que solicites el `facebookAnonymousId` del usuario a Facebook. De este modo, si el IDFA del usuario no está disponible, la integración seguirá funcionando. Sigue la
Debajo de las credenciales encontrarás tres grupos de eventos que puedes enviar a Singular desde Adapty. Consulta la lista completa de eventos que ofrece Adapty [aquí](events).
Te recomendamos usar los nombres de evento predeterminados que proporciona Adapty, aunque puedes modificarlos según tus necesidades.
Adapty enviará los eventos de suscripción a Singular mediante una integración server-to-server, lo que te permitirá ver todos los eventos de suscripción en tu dashboard de Singular y vincularlos con tus campañas de adquisición.
:::warning
Los perfiles creados antes de configurar las integraciones no podrán enviar sus eventos a Singular.
:::
### Conectar tu app con Singular \{#connect-your-app-to-singular\}
La integración entre Adapty y Singular es server-to-server, por lo que no necesitas añadir ningún código adicional en tu aplicación.
## Estructura del evento \{#event-structure\}
Adapty envía eventos a Singular mediante una solicitud GET con parámetros de consulta. Cada evento tiene esta estructura:
```json
{
"n": "subscription_renewed",
"a": "singular_sdk_key_123",
"p": "iOS",
"i": "com.example.app",
"ip": "192.168.100.1",
"idfa": "00000000-0000-0000-0000-000000000000",
"idfv": "00000000-0000-0000-0000-000000000000",
"ve": "17.0.1",
"att_authorization_status": 3,
"custom_user_id": "user_12345",
"utime": 1709294400,
"amt": 9.99,
"cur": "USD",
"purchase_product_id": "yearly.premium.6999",
"purchase_transaction_id": "GPA.3383...",
"e": "{\"is_revenue_event\":true,\"amt\":9.99,\"cur\":\"USD\",\"purchase_product_id\":\"yearly.premium.6999\",\"purchase_transaction_id\":\"GPA.3383...\"}"
}
```
Donde:
| Parámetro | Tipo | Descripción |
|:---------------------------|:--------|:---------------------------------------------------------------|
| `n` | String | El nombre del evento (mapeado desde el evento de Adapty). |
| `a` | String | Tu Singular SDK Key. |
| `p` | String | Plataforma ("iOS" o "Android"). |
| `i` | String | ID de la app en el store (Bundle ID). |
| `ip` | String | Dirección IP del usuario. |
| `idfa` | String | **Solo iOS**. ID for Advertisers (en mayúsculas). |
| `idfv` | String | **Solo iOS**. ID for Vendors (en mayúsculas). |
| `aifa` | String | **Solo Android**. Google Advertising ID (en minúsculas). |
| `andi` | String | **Solo Android**. Android ID (en minúsculas). |
| `asid` | String | **Solo Android**. App Set ID (en minúsculas). |
| `ve` | String | Versión del sistema operativo. |
| `att_authorization_status` | Integer | **Solo iOS**. Estado ATT (p. ej., `3` para autorizado). |
| `custom_user_id` | String | El Customer User ID del usuario. |
| `utime` | Long | Marca de tiempo UNIX del evento en segundos. |
| `amt` | Float | Importe de los ingresos. |
| `cur` | String | Código de moneda (p. ej., "USD"). |
| `purchase_product_id` | String | El ID del producto en el store. |
| `purchase_transaction_id` | String | ID de transacción original. |
| `e` | String | Cadena JSON con los detalles del evento (ver más abajo). |
El parámetro `e` (datos de evento personalizados) es una cadena codificada en JSON que contiene:
| Parámetro | Tipo | Descripción |
|:--------------------------|:--------|:-----------------------------------------------|
| `is_revenue_event` | Boolean | `true` si el evento incluye ingresos. |
| `amt` | Float | Importe de los ingresos. |
| `cur` | String | Código de moneda. |
| `purchase_product_id` | String | El ID del producto en el store. |
| `purchase_transaction_id` | String | ID de transacción original. |
---
# File: tenjin
---
---
title: "Integración con Tenjin"
description: ""
---
Tenjin es una plataforma de atribución y análisis móvil para desarrolladores de apps y marketers. Proporciona herramientas para medir y optimizar campañas de adquisición de usuarios, ofreciendo información detallada sobre el rendimiento de la app y el comportamiento de los usuarios. Con su enfoque transparente y flexible, Tenjin agrega datos de redes publicitarias y stores de aplicaciones, lo que permite a los equipos analizar el ROI, rastrear conversiones y monitorear métricas clave de rendimiento.
Al reenviar [eventos de suscripción](events) a Tenjin, puedes ver exactamente de dónde provienen las conversiones y qué campañas generan más valor en todos los canales, plataformas y dispositivos. En esencia, los dashboards de Tenjin ofrecen analíticas avanzadas para campañas de marketing.
Al reenviar la atribución de Tenjin a Adapty, enriqueces las analíticas de Adapty con criterios de filtrado adicionales que puedes usar en análisis de cohortes y conversiones.
Esta integración funciona de dos maneras principales:
1. **Recibir datos de atribución de Tenjin**
Una vez integrado, Adapty recopila datos de atribución de Tenjin. Puedes consultar esta información en la página de perfil del usuario en el Adapty Dashboard.
2. **Enviar eventos de suscripción a Tenjin**
Adapty envía eventos de compra a Tenjin en tiempo real. Estos eventos ayudan a evaluar la efectividad de tus campañas publicitarias directamente en el dashboard de Tenjin.
| Característica de integración | Descripción |
| ----------------------------- | ------------------------------------------------------------ |
| Frecuencia | Tiempo real |
| Dirección de datos | Transmisión bidireccional:
3. Inicia sesión en el [Tenjin Dashboard](https://tenjin.com/).
4. Ve a **Configuration** -> **Apps** en el menú de navegación.
5. Selecciona la app de tu plataforma (iOS o Android) y ve a la pestaña **App and SDK**.
6. En la pestaña **App and SDK**, haz clic en **Copy** en la columna **SDK Key**. Si todavía no tienes una SDK key, haz clic en el botón **Generate SDK Key** para crear una.
7. Vuelve al Adapty Dashboard y pega el SDK Key copiado en el campo correspondiente a tu plataforma:
- Para apps iOS: pégalo en el campo **iOS SDK Key** o **iOS Sandbox SDK Key**
- Para apps Android: pégalo en el campo **Android SDK Key** o **Android Sandbox SDK Key**
:::info
Tenjin no dispone de un modo Sandbox específico para la integración server-to-server. Usa una app de Tenjin separada o la misma clave tanto para eventos de producción como de sandbox.
:::
8. Si tienes apps en ambas plataformas, repite los pasos 5-7 para la otra plataforma.
9. (opcional) Ajusta la sección **How the revenue data should be sent** si es necesario. Para una explicación detallada de sus opciones, consulta los [Ajustes de integración](configuration#integration-settings).
10. Haz clic en **Save** para finalizar la configuración.
Adapty enviará ahora los eventos de compra a Tenjin y recibirá datos de atribución. Puedes ajustar el intercambio de eventos en la sección **Events names**.
### Configurar eventos y etiquetas \{#configure-events-and-tags\}
Tenjin solo acepta eventos de compra y **Trial started**. En la sección **Events names**, selecciona qué eventos compartir con Tenjin según tus objetivos de seguimiento.
### Conecta tu app a Tenjin \{#connect-your-app-to-tenjin\}
Usa el método del SDK `Adapty.updateAttribution()` para obtener datos de atribución de Tenjin y enviarlos a Adapty.
2. Activa **Amplitude integration** para habilitarla.
3. Rellena los campos de la integración:
| Campo | Descripción |
| ------------------------------------------ | ------------------------------------------------------------ |
| **Amplitude iOS/ Android/ Stripe API key** | Introduce la **API Key** de Amplitude para iOS/ Android/ Stripe en Adapty. Encuéntrala en **Project settings** dentro de Amplitude. Para más ayuda, consulta la [documentación de Amplitude](https://amplitude.com/docs/apis/authentication). Comienza con las claves de **Sandbox** para pruebas y luego cambia a las claves de **Production** tras pruebas exitosas. |
4. Ajustes opcionales para mayor personalización:
| Parámetro | Descripción |
| --------------------------------------- | ------------------------------------------------------------ |
| **How the revenue data should be sent** | Elige si enviar los ingresos brutos o los ingresos después de impuestos y comisiones. Consulta [Comisión del store e impuestos](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue) para más detalles. |
| **Exclude historical events** | Elige excluir los eventos anteriores a la instalación del SDK de Adapty para evitar datos duplicados. Por ejemplo, si un usuario se suscribió el 10 de enero pero instaló el SDK de Adapty el 6 de marzo, Adapty solo enviará eventos a partir del 6 de marzo. |
| **Send User Attributes** | Selecciona esta opción para enviar atributos específicos del usuario, como preferencias de idioma. |
| **Always populate user_id** | Adapty envía automáticamente `device_id` como `amplitudeDeviceId`. Para `user_id`, esta configuración define el comportamiento:
Recomendamos usar los nombres de eventos predeterminados que proporciona Adapty. No obstante, puedes cambiarlos según tus necesidades. Adapty enviará los eventos de suscripción a Amplitude mediante una integración servidor a servidor, lo que te permitirá ver todos los eventos de suscripción en tu dashboard de Amplitude.
### Configuración del SDK \{#sdk-configuration\}
Usa el método `setIntegrationIdentifier()` para establecer el parámetro `amplitude_device_id`. Es imprescindible configurarlo para que la integración funcione.
Si tienes registro de usuarios, también puedes pasar `amplitude_user_id`.
:::note
Los SDKs de terceros generan los IDs de usuario de forma asíncrona. Es posible que el ID no esté disponible cuando se ejecuta `Adapty.activate()`. Si tu **Customer User ID** proviene de uno de estos SDKs, llama a `Adapty.activate()` sin él. Una vez que el ID esté disponible, llama a `setIntegrationIdentifier()` y luego a `identify()` con el CUID.
:::
4. Ve a [Integrations > AppMetrica](https://app.adapty.io/integrations/appmetrica) en el Adapty Dashboard
5. Pega tus credenciales de AppMetrica.
### Eventos y etiquetas \{#events-and-tags\}
Adapty te permite enviar tres grupos de eventos a AppMetrica. Puedes habilitar los eventos que necesitas para rastrear el rendimiento de tu app. Para ver la lista completa de eventos disponibles, consulta nuestra [documentación de eventos](events).
:::note
AppMetrica sincroniza los eventos cada 4 horas, por lo que puede haber un retraso antes de que los eventos aparezcan en tu dashboard.
:::
:::tip
Recomendamos usar los nombres de eventos predeterminados de Adapty para mantener la coherencia, aunque puedes personalizarlos para que coincidan con tu configuración de análisis existente.
:::
### Configuración de ingresos \{#revenue-settings\}
De forma predeterminada, Adapty envía los datos de ingresos como propiedades en los eventos, que aparecen en el informe de Events de AppMetrica. Puedes configurar cómo se calculan y muestran estos datos:
- **Revenue calculation**: Elige cómo se calculan los valores de ingresos para que coincidan con tus necesidades de informes financieros:
- **Gross revenue**: Muestra los ingresos totales antes de cualquier deducción, útil para rastrear el importe completo que pagan los clientes
- **Proceeds after store commission**: Muestra los ingresos después de deducir las comisiones de App Store/Play Store, lo que te ayuda a rastrear los ingresos reales
- **Proceeds after store commission and taxes**: Muestra los ingresos netos después de las comisiones del store y los impuestos aplicables, lo que ofrece la imagen más precisa de tus ganancias
- **Report user's currency**: Cuando está habilitado, las ventas se informan en la moneda local del usuario, lo que facilita el análisis de ingresos por región. Cuando está deshabilitado, todas las ventas se convierten a USD para mantener informes coherentes en diferentes mercados.
- **Send revenue events**: Habilita esta opción para que los datos de ingresos aparezcan no solo en el informe de Events, sino también en el informe [In-app and ad revenue](https://appmetrica.yandex.com/docs/en/mobile-reports/revenue-report) de AppMetrica. Asegúrate de no enviar ingresos desde ningún otro lugar, ya que esto podría generar duplicados.
- **Exclude historical events**: Cuando está habilitado, Adapty no enviará eventos que ocurrieron antes de que el usuario instalara la app con el SDK de Adapty. Esto ayuda a evitar la duplicación de datos si ya estabas enviando eventos a analytics antes de integrar Adapty.
### Configuración del SDK \{#sdk-configuration\}
Para habilitar la integración con AppMetrica en tu app, necesitas configurar dos identificadores:
1. `appmetrica_device_id`: Necesario para la integración básica
2. `appmetrica_profile_id`: Opcional, pero recomendado si tu app tiene registro de usuarios
Usa el método `setIntegrationIdentifier()` para establecer estos valores. A continuación se muestra cómo implementarlo en cada plataforma:
:::note
Los SDKs de terceros generan los IDs de usuario de forma asíncrona. Es posible que el ID no esté disponible cuando se ejecuta `Adapty.activate()`. Si tu **Customer User ID** proviene de uno de estos SDKs, llama a `Adapty.activate()` sin él. Una vez que el ID esté disponible, llama a `setIntegrationIdentifier()` y luego a `identify()` con el CUID.
:::
### Cómo encontrar tu token de Mixpanel \{#finding-your-mixpanel-token\}
Para obtener tu **Mixpanel Token**:
1. Inicia sesión en tu [Mixpanel Dashboard](https://mixpanel.com/settings/project/).
2. Abre **Settings** y selecciona **Organization Settings**.
3. En la barra lateral izquierda, ve a **Projects** y selecciona tu proyecto.
## Cómo funciona la integración \{#how-the-integration-works\}
Adapty mapea automáticamente las propiedades de evento relevantes —como el ID de usuario y los ingresos— a las [propiedades nativas de Mixpanel](https://docs.mixpanel.com/docs/data-structure/user-profiles). Esto garantiza un seguimiento e informes precisos de los eventos relacionados con suscripciones.
Además, Adapty acumula datos de ingresos por usuario y actualiza sus [Propiedades de Perfil de Usuario](https://docs.mixpanel.com/docs/data-structure/user-profiles), incluidas `subscription state` y `subscription product ID`. Una vez recibido un evento, Mixpanel actualiza los campos correspondientes en tiempo real.
## Eventos y etiquetas \{#events-and-tags\}
Debajo de las credenciales, hay tres grupos de eventos que puedes enviar a Mixpanel desde Adapty. Simplemente activa los que necesites. Consulta la lista completa de eventos que ofrece Adapty [aquí](events).
Recomendamos usar los nombres de evento predeterminados que ofrece Adapty. Pero puedes cambiarlos según tus necesidades.
## Configuración del SDK \{#sdk-configuration\}
Usa el método `.setIntegrationIdentifier()` para configurar `mixpanelUserId`. Si no se establece, Adapty usa tu ID de usuario (`customerUserId`) o, si es nulo, el ID de Adapty. Asegúrate de que el ID de usuario que usas para enviar datos a Mixpanel desde tu app sea el mismo que envías a Adapty.
:::note
Los SDKs de terceros generan los IDs de usuario de forma asíncrona. Es posible que el ID no esté disponible cuando se ejecuta `Adapty.activate()`. Si tu **Customer User ID** proviene de uno de estos SDKs, llama a `Adapty.activate()` sin él. Una vez que el ID esté disponible, llama a `setIntegrationIdentifier()` y luego a `identify()` con el CUID.
:::
2. Inicia sesión en el [PostHog Dashboard](https://posthog.com/).
3. Ve a **Settings -> Project**.
4. En la ventana **Project**, desplázate hacia abajo hasta la sección **Project ID** y copia la **Project API key**.
5. Pega la API key en el campo **Project API key** del Adapty Dashboard. PostHog no tiene un modo Sandbox específico para la integración servidor a servidor.
6. Elige tu **PostHog Deployment**:
| Opción | Descripción |
| ------ | ----------- |
| us/eu | Despliegues de PostHog alojados por defecto. |
| Custom | Para instancias autoalojadas. Introduce la URL de tu instancia en el campo **PostHog Instance URL**. |
7. (Opcional) Si usas un despliegue de PostHog autoalojado, introduce la dirección de tu despliegue en el campo **PostHog Instance URL**.
8. (opcional) Ajusta opciones como **Reporting Proceeds**, **Exclude Historical Events**, **Report User's Currency** y **Send Trial Price**. Consulta [Configuración de la integración](configuration#integration-settings) para más detalles sobre estas opciones.
9. (opcional) También puedes personalizar qué eventos se envían a PostHog en la sección **Events names**. Desactiva los eventos que no necesites o cámbiales el nombre según convenga.
10. Haz clic en **Save** para finalizar la configuración.
## Configuración del SDK \{#sdk-configuration\}
Para habilitar la recepción de datos de atribución desde PostHog, pasa el valor `distinctId` a Adapty tal como se muestra a continuación:
:::note
Los SDKs de terceros generan los IDs de usuario de forma asíncrona. Es posible que el ID no esté disponible cuando se ejecuta `Adapty.activate()`. Si tu **Customer User ID** proviene de uno de estos SDKs, llama a `Adapty.activate()` sin él. Una vez que el ID esté disponible, llama a `setIntegrationIdentifier()` y luego a `identify()` con el CUID.
:::
Abre tu cuenta de SplitMetrics Acquire, pasa el cursor sobre uno de los logos de MMP y haz clic en el botón **Settings**. Encuentra tu Client ID en el diálogo, en el punto **5**, cópialo y pégalo en Adapty como **Client ID**.
También tendrás que introducir el Apple App ID para usar la integración. Para encontrarlo, abre la página de tu app en App Store Connect, ve a la **App Information page** en la sección **General** y localiza el **Apple ID** en la parte inferior izquierda de la pantalla.
## Eventos y etiquetas \{#events-and-tags\}
Debajo de las credenciales encontrarás tres grupos de eventos que puedes enviar a SplitMetrics Acquire desde Adapty. Activa simplemente los que necesites. Consulta la lista completa de eventos que ofrece Adapty [aquí](events).
Te recomendamos usar los nombres de evento predeterminados que proporciona Adapty. Sin embargo, puedes cambiarlos según tus necesidades. Adapty enviará los eventos de suscripción a SplitMetrics Acquire mediante una integración servidor a servidor, lo que te permitirá ver todos los eventos de suscripción en tu dashboard de SplitMetrics.
## Configuración del SDK \{#sdk-configuration\}
No es necesario configurar nada en el SDK, aunque te recomendamos enviar `customerUserId` a Adapty para mayor precisión.
:::warning
Asegúrate de haber configurado [Apple Search Ads](apple-search-ads) en Adapty y de haber [subido las credenciales](https://app.adapty.io/settings/apple-search-ads); sin ellas, SplitMetrics Acquire no funcionará.
:::
## Solución de problemas \{#troubleshooting\}
Si la integración con SplitMetrics Acquire no funciona a pesar de estar correctamente configurada:
- Asegúrate de haber activado el interruptor **Receive Apple Search Ads attribution in Adapty** en [App Settings -> Apple Search Ads tab](https://app.adapty.io/settings/apple-search-ads), de haber configurado [Apple Search Ads](apple-search-ads) en Adapty y de haber [subido las credenciales](https://app.adapty.io/settings/apple-search-ads); sin ellas, SplitMetric no funcionará.
- Comprueba que los perfiles tengan atribución ASA no orgánica. Solo los perfiles con atribución ASA detallada y no orgánica enviarán sus eventos a Adapty.
## Estructura de eventos de SplitMetrics Acquire \{#splitmetrics-acquire-event-structure\}
Adapty envía eventos a SplitMetrics Acquire mediante una solicitud GET usando parámetros de consulta. Cada evento tiene la siguiente estructura:
```json
{
"source": "Apple Search Ads",
"app_id": "123456789",
"name": "subscription_renewed",
"type": "subscription_renewed",
"revenue": 9.99,
"currency": "USD",
"tap_time": "2024-03-01 12:00:00",
"open_time": "2024-03-01 12:05:00",
"event_time": "2024-03-02 12:00:00",
"adaccount_id": "123456",
"campaign_id": "123456789",
"adgroup_id": "123456789",
"keyword_id": "123456789",
"creative_set_id": "123456789",
"Ad_id": "123456789",
"country_or_region": "US",
"conversion_type": "Download",
"user_id": "user_12345",
"att_status": "3",
"device_type": "iphone",
"app_version": "1.2.3",
"sdk_version": "2.10.0",
"ios_version": "17.2",
"event_value": "{\"vendor_product_id\":\"yearly.premium.6999\",\"original_transaction_id\":\"GPA.3383...\"}",
"event_id": "123e4567-e89b-12d3-a456-426614174000"
}
```
Donde:
| Parámetro | Tipo | Descripción |
|:--------------------|:-------|:----------------------------------------------------------------------------------------------------------------------------------|
| `source` | String | Siempre "Apple Search Ads". |
| `app_id` | String | Apple App ID. |
| `name` | String | Nombre del evento (mapeado desde el evento de Adapty). |
| `type` | String | Tipo de evento (igual que `name`). |
| `revenue` | Float | Importe de ingresos. |
| `currency` | String | Código de moneda. |
| `tap_time` | String | Fecha y hora del tap en el anuncio. |
| `open_time` | String | Fecha y hora de la apertura de la app (instalación). |
| `event_time` | String | Fecha y hora del evento. |
| `adaccount_id` | String | ID de organización de ASA. |
| `campaign_id` | String | ID de campaña de ASA. |
| `adgroup_id` | String | ID de grupo de anuncios de ASA. |
| `keyword_id` | String | ID de palabra clave de ASA. |
| `creative_set_id` | String | ID de conjunto creativo de ASA. |
| `Ad_id` | String | ID de anuncio de ASA. |
| `country_or_region` | String | País o región del store. |
| `conversion_type` | String | Tipo de conversión (p. ej., "Download"). |
| `user_id` | String | Customer User ID o Adapty Profile ID. |
| `att_status` | String | Estado de uso de seguimiento (0-3). |
| `device_type` | String | Tipo de dispositivo (p. ej., "iphone", "ipad"). |
| `app_version` | String | Versión de la aplicación. |
| `sdk_version` | String | Versión del SDK de Adapty. |
| `ios_version` | String | Versión de iOS. |
| `event_value` | String | Cadena JSON con todos los [detalles del evento](webhook-event-types-and-fields#for-most-event-types) disponibles. |
| `event_id` | String | ID de evento único (UUID). |
---
# File: braze
---
---
title: "Braze"
description: "Integra Braze con Adapty para una mejor interacción con clientes y notificaciones push."
---
Como una de las principales soluciones de captación de clientes, [Braze](https://www.braze.com/) ofrece una amplia gama de herramientas para notificaciones push, email, SMS y mensajería in-app. Al integrar Adapty con Braze, puedes acceder fácilmente a todos tus eventos de suscripción en un solo lugar, lo que te permite activar comunicaciones automatizadas basadas en esos eventos.
Adapty proporciona un conjunto completo de datos que te permite rastrear [eventos de suscripción](events) de todas las stores en un solo lugar y puede usarse para actualizar los perfiles de tus usuarios en Braze. Con Adapty, puedes ver fácilmente el comportamiento de tus suscriptores, conocer sus preferencias y utilizar esa información para comunicarte con ellos de forma dirigida y efectiva. Por tanto, esta integración te permite rastrear eventos de suscripción en tu dashboard de Braze y relacionarlos con tus [campañas de adquisición.](https://www.braze.com/product/journey-orchestration)
Adapty envía eventos de suscripción, propiedades de usuario y compras a Braze, para que puedas crear comunicaciones dirigidas a clientes mediante notificaciones push de Braze tras una integración sencilla y rápida, tal como se describe a continuación.
## Cómo configurar la integración con Braze \{#how-to-set-up-braze-integration\}
Para integrar Braze, ve a [Integrations -> Braze](https://app.adapty.io/integrations/braze), activa el interruptor y rellena los campos.
El primer paso del proceso de integración es proporcionar las credenciales necesarias para establecer una conexión entre tus perfiles de Braze y Adapty. Necesitarás la **REST API Key**, tu **Braze Instance ID** y los **App IDs** para iOS y Android para que la integración funcione correctamente:
1. La **REST API Key** se puede crear en **Braze Dashboard** → **Settings** → **API Keys**. Asegúrate de que tu clave tenga el permiso `users.track` al crearla:
2. Para obtener el **Braze Instance ID**, fíjate en la URL de tu Braze Dashboard y accede a la sección de [Braze Docs](https://www.braze.com/docs/api/basics/#endpoints) donde se especifica el ID de instancia. Tendrá un formato regional como US-03, EU-01, etc.
3. Los App IDs de iOS y Android también se encuentran en Braze Dashboard → Settings → API Keys. Cópialos desde aquí:
## Eventos, atributos de usuario y compras \{#events-user-attributes-and-purchases\}
Justo debajo de las credenciales hay tres grupos de eventos que puedes enviar a Braze desde Adapty. Activa simplemente los que necesites. También puedes cambiar los nombres de los eventos según lo que necesites enviar a Braze. Consulta la lista completa de eventos que ofrece Adapty [aquí](events):
Adapty enviará eventos de suscripción y atributos de usuario a Braze mediante una integración servidor a servidor, lo que te permitirá verlos en tu Braze Dashboard y configurar campañas basándote en ellos.
Para los eventos que generan ingresos, como las conversiones de prueba y las renovaciones, Adapty enviará esta información a Braze como compras.
[Aquí](messaging#event-properties) encontrarás las especificaciones completas de las propiedades de los eventos que se envían a Braze.
:::note
Atributos de usuario útiles
Adapty envía algunos atributos de usuario para la integración con Braze de forma predeterminada. Puedes consultar la lista que se muestra a continuación para determinar cuáles se adaptan mejor a tus necesidades.
:::
| Atributo de usuario | Tipo | Valor |
|--------------|----|-----|
| `adapty_customer_user_id` | String | Contiene el valor del identificador único del usuario definido por el cliente. Se puede encontrar tanto en el [Dashboard](profiles-crm) de Adapty como en Braze. |
| `adapty_profile_id` | String | Contiene el valor del identificador único del Perfil de Usuario de Adapty, que se puede encontrar en el [Dashboard](profiles-crm) de Adapty. |
| `environment` | String | Indica si el usuario opera en un entorno sandbox o de producción.
Los valores son `Sandbox` o `Production`
| | `store` | String |Contiene el nombre de la Store utilizada para realizar la compra.
Valores posibles:
`app_store` o `play_store`.
| | `vendor_product_id` | String |Contiene el valor del ID de producto en la store de Apple/Google.
p. ej., org.locals.12345
| | `subscription_expires_at` | String |Contiene la fecha de vencimiento de la suscripción más reciente.
El formato del valor es:
YYYY-MM-DDTHH:mm:ss.SSS+TZ
p. ej., 2023-02-15T17:22:03.000+0000
| | `active_subscription` | String | El valor se establecerá en `true` en cualquier evento de compra o renovación, o en `false` si la suscripción ha expirado. | | `period_type` | String |Indica el tipo de período más reciente para la compra o renovación.
Los valores posibles son
`trial` para un período de prueba o `normal` para el resto.
| Todos los valores float se redondearán a int. Los strings permanecen igual. Además de la lista predefinida de etiquetas disponibles, es posible enviar [atributos personalizados](segments#custom-attributes) mediante etiquetas. Esto permite mayor flexibilidad en el tipo de datos que se pueden incluir con la etiqueta y puede resultar útil para rastrear información específica relacionada con un producto o servicio. Todos los atributos de usuario personalizados se envían automáticamente a Braze si el usuario marca la casilla **Send user attributes** en [la página de integración](https://app.adapty.io/integrations/braze). ## Configuración del SDK \{#sdk-configuration\} Para vincular perfiles de usuario en Adapty y Braze, debes configurar el SDK de Braze con el mismo ID de usuario que Adapty o usar su método `.changeUser()`:
2. Activa el interruptor de la integración.
3. Introduce tu **OneSignal App ID**.
Para configurar la integración con OneSignal, ve a [Integrations -> OneSignal](https://app.adapty.io/integrations/onesignal) en tu Adapty Dashboard, activa el interruptor y configura las credenciales de la integración.
## Obtén tu OneSignal App ID \{#retrieving-your-onesignal-app-id\}
Encuentra tu **OneSignal App ID** en tu [OneSignal Dashboard](https://dashboard.onesignal.com/login):
1. Ve a **Settings** → **Keys & IDs**.
2. Copia tu **OneSignal App ID** y pégalo en el campo **App ID** del Adapty Dashboard.
Puedes encontrar más información sobre el OneSignal ID en la [siguiente documentación.](https://documentation.onesignal.com/docs/en/keys-and-ids)
### Configuración de eventos \{#configuring-events\}
Adapty te permite enviar tres grupos de eventos a OneSignal. Activa los que necesites en el Adapty Dashboard. Puedes consultar la lista completa de eventos disponibles con su descripción detallada [aquí](events).
Adapty envía eventos de suscripción a OneSignal mediante una integración servidor a servidor, lo que te permite rastrear toda la actividad relacionada con suscripciones en OneSignal.
:::warning
A partir del 17 de abril de 2023, el plan gratuito de OneSignal ya no admite esta integración. Solo está disponible en los planes **Growth**, **Professional** y superiores. Para más información, consulta [Precios de OneSignal](https://onesignal.com/pricing).
:::
## Etiquetas personalizadas \{#custom-tags\}
Esta integración actualiza y asigna diversas propiedades a tus usuarios de Adapty como etiquetas, que luego se envían a OneSignal. Consulta la lista de etiquetas a continuación para encontrar las que mejor se adapten a tus necesidades.
:::warning
OneSignal tiene un límite de etiquetas. Esto incluye tanto las etiquetas generadas por Adapty como cualquier etiqueta existente en OneSignal. Superar el límite puede causar errores al enviar eventos.
:::
| Etiqueta | Tipo | Descripción |
|---|----|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `adapty_customer_user_id` | String | El identificador único del usuario en tu app. Debe ser coherente en tu sistema, Adapty y OneSignal. |
| `adapty_profile_id` | String | El ID del perfil de usuario de Adapty, disponible en tu [Adapty Dashboard](profiles-crm). |
| `environment` | String | `Sandbox` o `Production`, indica el entorno actual del usuario. |
| `store` | String | Store donde se compró el producto. Opciones: **app_store**, **play_store**, **stripe** o el nombre de tu [store personalizada](custom-store). |
| `vendor_product_id` | String | El ID del producto en el store (p. ej., `org.locals.12345`). |
| `subscription_expires_at` | String | Fecha de expiración de la última suscripción (`YYYY-MM-DDTHH:MM:SS+0000`, p. ej., `2023-02-10T17:22:03.000000+0000`). |
| `last_event_type` | String | El tipo de evento más reciente de la [lista de eventos de Adapty](events).
1. El **App ID** se encuentra en tu dashboard de Pushwoosh.
2. El **Auth token** se encuentra en la sección API Access dentro de la configuración de Pushwoosh.
## Eventos y etiquetas \{#events-and-tags\}
Debajo de las credenciales encontrarás tres grupos de eventos que puedes enviar a Pushwoosh desde Adapty. Activa simplemente los que necesites. También puedes cambiar los nombres de los eventos antes de enviarlos a Pushwoosh. Consulta la lista completa de eventos que ofrece Adapty [aquí](events).
Adapty enviará los eventos de suscripción a Pushwoosh mediante una integración server-to-server, lo que te permitirá ver todos los eventos de suscripción en tu Pushwoosh Dashboard.
:::note
Etiquetas personalizadas
Con Adapty también puedes usar tus propias etiquetas personalizadas para la integración con Pushwoosh. Consulta la lista de etiquetas que se muestra a continuación para determinar cuál se adapta mejor a tus necesidades.
:::
| Etiqueta | Tipo | Valor |
|---|----|-----|
| `adapty_customer_user_id` | String | Contiene el valor del identificador único del usuario, que puede encontrarse en el lado de Pushwoosh. |
| `adapty_profile_id` | String | Contiene el valor del identificador único del perfil de usuario de Adapty, que puede encontrarse en tu [dashboard](profiles-crm) de Adapty. |
| `environment` | String | Indica si el usuario opera en un entorno sandbox o de producción.
Los valores son `Sandbox` o `Production`.
| | `store` | String |Contiene el nombre del store utilizado para realizar la compra.
Valores posibles:
`app_store` o `play_store`.
| | `vendor_product_id` | String |Contiene el valor del Product ID en la store de Apple o Google.
p. ej., org.locals.12345
| | `subscription_expires_at` | String |Contiene la fecha de expiración de la última suscripción.
El formato del valor es:
año-mes díaTHhora:minuto:segundo
p. ej., 2023-02-10T17:22:03.000000+0000
| | `last_event_type` | String | Indica el tipo del último evento recibido de la lista de [eventos estándar de Adapty](events) que has habilitado para la integración. | | `purchase_date` | String |Contiene la fecha de la última transacción (compra original o renovación).
El formato del valor es:
año-mes díaTHhora:minuto:segundo
p. ej., 2023-02-10T17:22:03.000000+0000
| | `original_purchase_date` | String |Contiene la fecha de la primera compra según la transacción.
El formato del valor es:
año-mes díaTHhora:minuto:segundo
p. ej., 2023-02-10T17:22:03.000000+0000
| | `active_subscription` | String | El valor se establecerá en `true` ante cualquier evento de compra o renovación, o en `false` si la suscripción ha expirado. | | `period_type` | String |Indica el tipo de período más reciente para la compra o renovación.
Los valores posibles son
`trial` para un período de prueba o `normal` para el resto.
| Todos los valores float se redondearán a int. Las cadenas de texto permanecen igual. Además de la lista predefinida de etiquetas disponibles, es posible enviar [atributos personalizados](segments#custom-attributes) mediante etiquetas. Esto ofrece mayor flexibilidad en el tipo de datos que se pueden incluir y resulta útil para rastrear información específica relacionada con un producto o servicio. Todos los atributos personalizados de usuario se envían automáticamente a Pushwoosh si el usuario marca la casilla **Send user custom attributes** en [la página de integración](https://app.adapty.io/integrations/pushwoosh). ## Configuración del SDK \{#sdk-configuration\} Para vincular Adapty con Pushwoosh, necesitas enviarnos el valor `HWID`:
2. Dale cualquier nombre (`Adapty`, por ejemplo) y agrégala a tu workspace:
### 2\. Dar permiso para publicar y obtener un token para tu app \{#2-give-permission-to-post-and-get-a-token-for-your-app\}
Serás redirigido a la página de tu app en Slack.
1. Desplázate hacia abajo y haz clic en **Permissions**:
2. Tras la redirección, desplázate hacia abajo hasta **Scopes** y haz clic en **Add an OAuth Scope**:
3. Otorga los permisos `chat:write`, `chat:write.public` y `chat:write.customize`. Estos son necesarios para publicar en tus canales y personalizar los mensajes:
4. Desplázate de nuevo hasta la parte superior de la página y haz clic en **Install to Workspace**:
5. Haz clic en **Allow**:
Después de esto, serás redirigido a la misma página, pero ahora tendrás disponible un OAuth Token (`xoxb-...`). Esto es exactamente lo que necesitas para completar la configuración:
### 3\. Configurar la integración en Adapty \{#3-configure-the-integration-in-adapty\}
1. Ve a [**Integrations** → **Slack**](https://app.adapty.io/integrations/slack):
2. Pega el token `xoxb-...` del paso anterior y elige en qué canales publicará la app. Puedes configurar la integración para recibir eventos solo en producción, en sandbox o en ambos. También puedes elegir en qué moneda se mostrarán los mensajes (la original o convertida a USD).
:::note
Ten en cuenta que si quieres publicar mensajes de Adapty en un canal privado, deberás añadir manualmente la app `Adapty` que creaste en Slack a ese canal. De lo contrario, no funcionará.
:::
3. Por último, puedes elegir qué eventos quieres recibir en **Events**:
¡Listo!
Los eventos se enviarán a los canales que hayas especificado. Podrás ver los ingresos cuando corresponda y consultar el perfil del cliente en Adapty:
---
# File: s3-exports
---
---
title: "Amazon S3"
description: "Exporta datos de suscripción a S3 para análisis avanzados e informes."
---
La integración de Adapty con Amazon S3 te permite almacenar de forma segura los datos de eventos y visitas a paywalls en un único lugar centralizado. Podrás guardar tus [eventos de suscripción](events) en tu bucket de Amazon S3 como archivos .csv.
Para configurar esta integración, deberás seguir unos sencillos pasos en la consola de AWS y en el Adapty Dashboard.
:::note
Programación
Adapty envía tus datos cada **24h** a las 4:00 UTC.
Cada archivo contendrá los datos de los eventos creados durante el día calendario anterior completo en UTC. Por ejemplo, los datos exportados automáticamente a las 4:00 UTC del 8 de marzo contendrán todos los eventos creados el 7 de marzo desde las 00:00:00 hasta las 23:59:59 UTC.
:::
## Cómo configurar la integración con Amazon S3 \{#how-to-set-up-amazon-s3-integration\}
Para empezar a recibir datos, necesitarás las siguientes credenciales:
1. Access key ID
2. Secret access key
3. S3 bucket name
4. Folder name inside the S3 bucket
:::note
Directorios anidados
Puedes especificar directorios anidados en el campo S3 bucket name, por ejemplo: adapty-events/com.sample-app
:::
Para integrar Amazon S3, ve a [**Integrations** -> **Amazon S3**](https://app.adapty.io/integrations/s3), activa el interruptor y rellena los campos.
En primer lugar, introduce las credenciales para establecer la conexión entre Amazon S3 y los perfiles de Adapty.
En el Adapty Dashboard, los siguientes campos son necesarios para configurar la conexión:
| Campo | Descripción |
| :--- | :--- |
| **Access Key ID** | Identificador único que se usa para autenticar el acceso de un usuario o aplicación a un servicio de AWS. Encuéntralo en el [archivo csv](s3-exports#how-to-create-amazon-s3-credentials) descargado. |
| **Secret Access Key** | Clave privada que se usa junto con el Access Key ID para autenticar el acceso de un usuario o aplicación a un servicio de AWS. Encuéntrala en el [archivo csv](s3-exports#how-to-create-amazon-s3-credentials) descargado. |
| **S3 Bucket Name** | Nombre único a nivel global que identifica un bucket de S3 específico dentro de la nube de AWS. Los buckets de S3 son un servicio de almacenamiento simple que permite a los usuarios guardar y recuperar objetos de datos, como archivos e imágenes, en la nube. |
| **Folder Inside the Bucker** | El nombre de la carpeta que quieres crear dentro del bucket de S3 seleccionado. Ten en cuenta que S3 simula carpetas mediante prefijos de clave de objeto, que son esencialmente nombres de carpetas. |
## Cómo crear credenciales de Amazon S3 \{#how-to-create-amazon-s3-credentials\}
Esta guía te ayudará a crear las credenciales necesarias en tu consola de AWS.
### 1\. Crear política de acceso \{#create-access-policy\}
Primero, ve al [Panel de políticas de IAM](https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/policies) en tu consola de AWS y selecciona la opción **Create Policy**.
En el editor de políticas, pega el siguiente JSON y cambia `adapty-s3-integration-test` por el nombre de tu bucket:
```json showLineNumbers title="Json"
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowListObjectsInBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::adapty-s3-integration-test"
},
{
"Sid": "AllowAllObjectActions",
"Effect": "Allow",
"Action": "s3:*Object",
"Resource": [
"arn:aws:s3:::adapty-s3-integration-test/*",
"arn:aws:s3:::adapty-s3-integration-test"
]
},
{
"Sid": "AllowBucketLocation",
"Effect": "Allow",
"Action": "s3:GetBucketLocation",
"Resource": "arn:aws:s3:::adapty-s3-integration-test"
}
]
}
```
Una vez completada la configuración de la política, puedes añadir etiquetas (opcional) y hacer clic en **Next** para continuar con el paso final. En este paso, deberás asignar un nombre a tu política y simplemente hacer clic en el botón **Create policy** para finalizar el proceso de creación.
### 2\. Crear un usuario IAM \{#2-create-iam-user\}
Para que Adapty pueda subir informes de datos brutos a tu bucket, deberás proporcionarles el Access Key ID y el Secret Access Key de un usuario con acceso de escritura al bucket específico.
Para ello, ve a la consola de IAM y selecciona la [sección Users](https://console.aws.amazon.com/iamv2/home#/users). Desde allí, haz clic en el botón **Add users**.
Dale un nombre al usuario, elige **Access key – Programmatic access** y continúa con los permisos.
Para el siguiente paso, selecciona la opción **Add user to group** y luego haz clic en el botón **Create group**.
A continuación, asigna un nombre a tu Grupo de Usuarios y selecciona la política que creaste anteriormente. Una vez seleccionada, haz clic en el botón **Create group** para completar el proceso.
Una vez creado el grupo con éxito, **selecciónalo** y continúa con el siguiente paso.
Como este es el último paso de esta sección, puedes continuar haciendo clic en el botón **Create User**.
Por último, puedes **descargar las credenciales en formato .csv** o copiarlas y pegarlas directamente desde el dashboard.
## Exportación manual de datos \{#manual-data-export\}
Además de la exportación automática de datos de eventos a Amazon S3, Adapty también ofrece una funcionalidad de exportación manual de archivos. Con esta función, puedes seleccionar un intervalo de tiempo específico para los datos de eventos y exportarlos a tu bucket de S3 de forma manual. Esto te da mayor control sobre los datos que exportas y cuándo los exportas.
El rango de fechas especificado se usará para exportar los eventos creados desde la Fecha A 00:00:00 UTC hasta la Fecha B 23:59:59 UTC.
## Estructura de la tabla \{#table-structure\}
En la integración con AWS S3, Adapty proporciona una tabla para almacenar datos históricos de eventos de transacciones y visitas a paywalls. La tabla contiene información sobre el perfil del usuario, los ingresos y beneficios, y el store de origen, entre otros datos. En esencia, estas tablas registran todas las transacciones generadas por una app durante un período de tiempo determinado.
:::warning
Ten en cuenta que esta estructura puede crecer con el tiempo, con nuevos datos introducidos por nosotros o por los terceros con los que trabajamos. Asegúrate de que tu código que la procesa sea lo suficientemente robusto y se base en los campos específicos, pero no en la estructura en su conjunto.
:::
Aquí está la estructura de la tabla para los eventos:
:::note
Adapty convierte otras divisas a USD según el tipo de cambio de [currencylayer.com](https://currencylayer.com/) (actualizado cada 8 horas). El tipo de cambio se **fija en el momento de la transacción** — los cambios futuros no afectan al resultado de la conversión.
:::
| Columna | Descripción |
|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **profile_id** | ID de usuario de Adapty. |
| **event_type** | Nombre del evento en minúsculas. Consulta la sección [Eventos](events) para conocer los tipos de eventos. |
| **event_datetime** | Fecha en formato ISO 8601. |
| **transaction_id** | Identificador único de una transacción, como una compra o renovación. |
| **original_transaction_id** | Identificador de la transacción de compra original. |
| **subscription_expires_at** | Fecha de vencimiento de la suscripción. Normalmente en el futuro. |
| **environment** | Puede ser Sandbox o Production. |
| **revenue_usd** | Ingresos en USD. Puede estar vacío. |
| **proceeds_usd** | Ingresos netos en USD. Puede estar vacío. |
| **net_revenue_usd** | Ingresos netos (tras impuestos) en USD. Puede estar vacío. |
| **tax_amount_usd** | Importe deducido en concepto de impuestos en USD. Puede estar vacío. |
| **revenue_local** | Ingresos en moneda local. Puede estar vacío. |
| **proceeds_local** | Ingresos netos en moneda local. Puede estar vacío. |
| **net_revenue_local** | Ingresos netos (tras impuestos) en moneda local. Puede estar vacío. |
| **tax_amount_local** | Importe deducido en concepto de impuestos en moneda local. Puede estar vacío. |
| **customer_user_id** | ID de usuario del desarrollador. Por ejemplo, puede ser tu UUID de usuario, email u otro identificador. Null si no lo has configurado. |
| **store** | Puede ser _app_store_ o _play_store_. |
| **product_id** | ID del producto en Apple App Store, Google Play Store o Stripe. |
| **base_plan_id** | [ID del plan base](https://support.google.com/googleplay/android-developer/answer/12154973) en Google Play Store o [ID de precio](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) en Stripe. |
| **developer_id** | ID del desarrollador (SDK) del paywall donde se originó la transacción. |
| **ab_test_name** | Nombre de la prueba A/B donde se originó la transacción. |
| **ab_test_revision** | Revisión de la prueba A/B donde se originó la transacción. |
| **paywall_name** | Nombre del paywall donde se originó la transacción. |
| **paywall_revision** | Revisión del paywall donde se originó la transacción. |
| **profile_county** | País del perfil determinado por Adapty a partir de la IP. |
| **install_date** | Fecha de instalación en formato ISO 8601. |
| **idfv** | [identifierForVendor](https://developer.apple.com/documentation/uikit/uidevice/identifierforvendor) en dispositivos iOS |
| **idfa** | [advertisingIdentifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/advertisingidentifier) en dispositivos iOS |
| **advertising_id** | El Advertising ID es un código único asignado por el sistema operativo Android que los anunciantes pueden usar para identificar de forma única el dispositivo de un usuario. |
| **ip_address** | IP del dispositivo (puede ser IPv4 o IPv6, con preferencia por IPv4 cuando esté disponible). Se actualiza cada vez que cambia la IP del dispositivo. |
| **cancellation_reason** | Motivo por el que el usuario canceló una suscripción.
Puede ser:
**iOS & Android** _voluntarily_cancelled_, _billing_error_, _refund_
**iOS** _price_increase_, _product_was_not_available_, _unknown_, _upgraded_
**Android** _new_subscription_replace_, _cancelled_by_developer_
| | **android_app_set_id** | Un [AppSetId](https://developer.android.com/design-for-safety/privacy-sandbox/reference/adservices/appsetid/AppSetId): ID único por dispositivo y por cuenta de desarrollador, restablecible por el usuario, para casos de uso publicitario sin monetización. | | **android_id** | En Android 8.0 (nivel de API 26) y versiones superiores, un número de 64 bits (expresado como cadena hexadecimal), único para cada combinación de clave de firma de la app, usuario y dispositivo. Para más detalles, consulta la [documentación para desarrolladores de Android](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID). | | **device** | Nombre del modelo de dispositivo visible para el usuario final. | | **currency** | Código de moneda de 3 letras (ISO-4217) de la transacción. | | **store_country** | País del perfil determinado por la store de Apple/Google. | | **attribution_source** | Fuente de atribución. | | **attribution_network_user_id** | ID asignado al usuario por la fuente de atribución. | | **attribution_status** | Puede ser organic, non_organic o unknown. | | **attribution_channel** | Nombre del canal de marketing. | | **attribution_campaign** | Nombre de la campaña de marketing. | | **attribution_ad_group** | Grupo de anuncios de atribución. | | **attribution_ad_set** | Conjunto de anuncios de atribución. | | **attribution_creative** | Palabra clave creativa de atribución. | | **attributes** | JSON de [atributos de usuario personalizados](setting-user-attributes#custom-user-attributes). Incluye los atributos personalizados que hayas configurado para enviar desde tu app móvil. Para enviarlo, activa la opción **Send User Attributes** en la página [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). | | **integration_ids** | Todos los IDs de integración asociados a un perfil. Diccionario. Ejemplo: {'mixpanel_user_id': 'mixpanelUserId-test', 'facebook_anonymous_id': 'facebookAnonymousId-test'} | Here is the table structure for the paywall visits: | Columna | Descripción | | :-------------------- | :------------------------------------------------------------------------------------------------------------------ | | **profile_id** | ID de usuario de Adapty. | | **customer_user_id** | ID de usuario del desarrollador. Por ejemplo, puede ser tu UUID de usuario, email o cualquier otro ID. Null si no lo configuraste. | | **profile_country** | País del perfil determinado por la store de Apple/Google. | | **install_date** | Fecha ISO 8601 en que se produjo la instalación. | | **store** | Puede ser _app_store_ o _play_store_. | | **paywall_showed_at** | La fecha en que el paywall se mostró al cliente. | | **developer_id** | ID de desarrollador (SDK) del paywall donde se originó la transacción. | | **ab_test_name** | Nombre de la prueba A/B donde se originó la transacción. | | **ab_test_revision** | Revisión de la prueba A/B donde se originó la transacción. | | **paywall_name** | Nombre del paywall donde se originó la transacción. | | **paywall_revision** | Revisión del paywall donde se originó la transacción. | ## Eventos y etiquetas \{#events-and-tags\} Puedes gestionar qué datos comunica la integración. La integración ofrece las siguientes opciones de configuración: | Parámetro | Descripción | | :--------------------------------- | :----------------------------------------------------------- | | **Exclude Historical Events** | Elige excluir los eventos que ocurrieron antes de que el usuario instalara la app con el SDK de Adapty. Esto evita la duplicación de eventos y garantiza informes precisos. Por ejemplo, si un usuario activó una suscripción mensual el 10 de enero y actualizó la app con el SDK de Adapty el 6 de marzo, Adapty omitirá los eventos anteriores al 6 de marzo y conservará los posteriores. | | **Include events without profile** | Elige incluir las transacciones que no están vinculadas a un perfil de usuario en Adapty. Esto puede incluir compras realizadas antes de instalar el SDK de Adapty o transacciones recibidas desde las notificaciones del servidor del store que no pueden asociarse inmediatamente a un usuario concreto. | | **Send User Attributes** | Si deseas enviar atributos específicos del usuario, como preferencias de idioma, y tu plan de OneSignal admite más de 10 etiquetas, selecciona esta opción. Al activarla, se permite incluir información adicional más allá de las 10 etiquetas predeterminadas. Ten en cuenta que superar los límites de etiquetas puede provocar errores. |
Debajo de los ajustes de integración, hay tres grupos de eventos que puedes exportar, enviar y almacenar en Amazon S3 desde Adapty. Activa los que necesites. Consulta la lista completa de eventos que ofrece Adapty [aquí](events).
---
# File: google-cloud-storage
---
---
title: "Google Cloud Storage"
description: "Integra Google Cloud Storage con Adapty para almacenamiento seguro de datos."
---
Activa la integración con Google Cloud Storage para almacenar de forma segura los [eventos de suscripción](events) y los [datos de visitas a paywalls](paywall-metrics) en un único lugar centralizado: tu bucket de Google Cloud Storage.
Cada día a las 4AM UTC, Adapty subirá archivos .csv con los datos del día anterior a tus buckets. Puedes elegir si quieres recibir datos de **eventos**, datos de **visitas a paywalls**, o **ambos**. También puedes exportar estos datos [manualmente](#manual-data-export) en cualquier momento y para cualquier período de tiempo.
Para configurar la integración, [genera una clave de acceso al bucket](#create-google-cloud-storage-credentials) en tu consola de Google Cloud y [agrégala a tu configuración de Adapty](#set-up-google-cloud-storage-integration).
## Programación y duración de las subidas \{#upload-schedule-and-duration\}
Adapty sube datos a Google Cloud Storage cada 24 horas, a las 04:00 UTC.
Los archivos contienen datos de los eventos creados durante el día natural anterior (UTC). El archivo subido el 8 de marzo incluirá todos los eventos creados el 7 de marzo, de 00:00:00 a 23:59:59 UTC.
El proceso puede tardar varias horas, dependiendo del número total de archivos en cola y del volumen de datos que hayas solicitado. Si Adapty incluye datos históricos en tu primera subida, tardará más que las subidas diarias posteriores.
## Configurar la integración con Google Cloud Storage \{#set-up-google-cloud-storage-integration\}
Necesitas una clave de cuenta de servicio de Google Cloud válida con **acceso de escritura**. Para generarla, sigue los pasos de la sección [crear credenciales](#create-google-cloud-storage-credentials).
:::warning
Puedes usar distintos buckets con diferentes credenciales para eventos y visitas a paywalls. Sin embargo, si **cualquiera** de las credenciales es inválida, [**ambas subidas fallarán**](#troubleshooting).
:::
Ve a [**Integrations** -> **Google Cloud Storage**](https://app.adapty.io/integrations/google-cloud-storage) y abre la pestaña correspondiente (**Events** o **Paywall visits**). Activa la integración.
Sube el archivo con tu **clave de cuenta de servicio de Google Cloud**. Especifica el **bucket** y la **carpeta** de destino. Guarda los cambios.
### Configuración opcional para datos de eventos \{#optional-settings-for-event-data\}
Puedes especificar qué eventos incluir en el informe y definir nombres personalizados para ellos. Consulta el artículo de [eventos](events) para ver la lista completa de eventos disponibles.
| Nombre | Valor predeterminado | Descripción |
| ------------------------------ | ----------------- | ----------- |
| Exclude historical events | true | Excluye información sobre eventos ocurridos antes de integrar el SDK de Adapty en tu app. Un usuario compró una suscripción mensual el 10 de enero. La actualización del 1 de marzo de tu aplicación fue la primera en incluir el SDK de Adapty.
Si este ajuste está **activado**, el informe no incluirá el evento "subscription started" de enero ni el evento "subscription renewed" de febrero. **Sí** incluirá el evento "subscription renewed" del 10 de marzo.
El motivo por el que el usuario canceló una suscripción.
Valores posibles:
**iOS y Android** — *voluntarily_cancelled*, *billing_error*, *refund*
**Solo iOS** — *price_increase*, *product_was_not_available*, *unknown*, *upgraded*
**Solo Android** — *new_subscription_replace*, *cancelled_by_developer*
| | **android_app_set_id** | Un [AppSetId](https://developer.android.com/design-for-safety/privacy-sandbox/reference/adservices/appsetid/AppSetId): ID único por dispositivo y cuenta de desarrollador, restablecible por el usuario, para casos de uso publicitario sin monetización. | | **android_id** | En Android 8.0 (nivel de API 26) y versiones superiores, un número de 64 bits (expresado como cadena hexadecimal), único para cada combinación de clave de firma de app, usuario y dispositivo. Para más detalles, consulta la [documentación para desarrolladores de Android](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID). | | **device** | Nombre del modelo de dispositivo visible para el usuario final. | | **currency** | Código de divisa de 3 letras (ISO-4217) de la transacción. | | **store_country** | País del perfil determinado por Apple/Google store. | | **attribution_source** | Fuente de atribución. | | **attribution_network_user_id** | ID asignado al usuario por la fuente de atribución. | | **attribution_status** | Puede ser organic, non_organic o unknown. | | **attribution_channel** | Nombre del canal de marketing. | | **attribution_campaign** | Nombre de la campaña de marketing. | | **attribution_ad_group** | Grupo de anuncios de atribución. | | **attribution_ad_set** | Conjunto de anuncios de atribución. | | **attribution_creative** | Palabra clave creativa de atribución. | | **attributes** | JSON con los [atributos personalizados del usuario](setting-user-attributes#custom-user-attributes). Incluirá todos los atributos personalizados que hayas configurado para enviar desde tu app móvil. Para enviarlo, activa la opción **Send User Attributes** en la página [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). | | **integration_ids** | Todos los IDs de integración asociados a un perfil. Diccionario. Ejemplo: {'mixpanel_user_id': 'mixpanelUserId-test', 'facebook_anonymous_id': 'facebookAnonymousId-test'} | ### Visitas a paywalls \{#paywall-visits\} | Columna | Descripción | | :-------------------- | :----------------------------------------------------------------------------------------------------------- | | **profile_id** | ID de usuario de Adapty. | | **customer_user_id** | ID de usuario del desarrollador. Por ejemplo, puede ser tu UUID de usuario, email u otro identificador. Nulo si no lo has definido. | | **profile_country** | País del perfil determinado por Apple/Google store. | | **install_date** | Fecha en formato ISO 8601 de cuando ocurrió la instalación. | | **store** | Puede ser *app_store* o *play_store*. | | **paywall_showed_at** | La fecha en que se mostró el paywall al cliente. | | **developer_id** | ID de desarrollador (SDK) del paywall donde se originó la transacción. | | **ab_test_name** | Nombre de la prueba A/B donde se originó la transacción. | | **ab_test_revision** | Revisión de la prueba A/B donde se originó la transacción. | | **paywall_name** | Nombre del paywall donde se originó la transacción. | | **paywall_revision** | Revisión del paywall donde se originó la transacción. | ## Solución de problemas \{#troubleshooting\} Adapty comprueba la validez de tus claves de acceso **antes** de comenzar la subida. Aunque solo una de tus claves de Google Cloud Storage sea inválida, Adapty **cancela la subida** y genera un error. Para garantizar subidas ininterrumpidas, reemplaza tus claves antes de que expiren. Si actualizas la clave de **eventos**, no olvides actualizar también la clave de **visitas a paywalls**, y viceversa. --- # File: webhook-event-types-and-fields --- --- title: "Tipos de eventos y campos de webhook" description: "" --- Adapty envía webhooks en respuesta a eventos de suscripción. Esta sección define estos tipos de eventos y los datos que contiene cada webhook. ## Tipos de eventos de webhook \{#webhook-event-types\} Puedes enviar todos los tipos de eventos a tu webhook o elegir solo algunos. Consulta nuestros [Flujos de eventos](event-flows) para saber qué tipo de datos entrantes esperar y cómo construir tu lógica de negocio en torno a ellos. Puedes desactivar los tipos de eventos que no necesites cuando [configures tu integración de Webhook](set-up-webhook-integration#configure-webhook-integration-in-the-adapty-dashboard). También puedes reemplazar los IDs de eventos predeterminados de Adapty por los tuyos propios si es necesario. | Nombre del evento | Descripción | |:-----------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | subscription_started | Se activa cuando un usuario activa una suscripción de pago sin período de prueba, es decir, se le cobra de inmediato. | | subscription_renewed | Ocurre cuando se renueva una suscripción y se cobra al usuario. Este evento comienza a partir de la segunda facturación, tanto en suscripciones con prueba como sin ella. | | subscription_renewal_cancelled | El usuario ha desactivado la renovación automática de la suscripción. El usuario conserva el acceso a las funciones premium hasta el final del período de suscripción pagado. | | subscription_renewal_reactivated | Se activa cuando un usuario reactiva la renovación automática de la suscripción. | | subscription_expired | Se activa cuando una suscripción finaliza por completo tras ser cancelada. Por ejemplo, si un usuario cancela una suscripción el 12 de diciembre pero esta permanece activa hasta el 31 de diciembre, el evento se registra el 31 de diciembre cuando la suscripción expira. | | subscription_paused | Ocurre cuando un usuario activa la [pausa de suscripción](https://developer.android.com/google/play/billing/lifecycle/subscriptions#pause) (solo Android). | | subscription_deferred | Se activa cuando una compra de suscripción se [aplaza](https://adapty.io/glossary/subscription-purchase-deferral/), lo que permite a los usuarios retrasar el pago manteniendo el acceso a las funciones premium. Esta función está disponible a través de la Google Play Developer API y puede usarse para pruebas gratuitas o para ayudar a usuarios con dificultades económicas. | | non_subscription_purchase | Cualquier compra que no sea una suscripción, como el acceso de por vida o productos consumibles como monedas del juego. | | trial_started | Se activa cuando un usuario activa una suscripción de prueba. | | trial_converted | Ocurre cuando finaliza una prueba y se cobra al usuario (primera compra). Por ejemplo, si un usuario tiene una prueba hasta el 14 de enero pero se le cobra el 7 de enero, este evento se registra el 7 de enero. | | trial_renewal_cancelled | El usuario desactivó la renovación automática de la suscripción durante el período de prueba. El usuario conserva el acceso a las funciones premium hasta que finalice la prueba, pero no se le cobrará ni comenzará una suscripción. | | trial_renewal_reactivated | Ocurre cuando un usuario reactiva la renovación automática de la suscripción durante el período de prueba. | | trial_expired | Se activa cuando finaliza una prueba sin convertirse en suscripción. | | entered_grace_period | Ocurre cuando falla un intento de pago y el usuario entra en un período de gracia (si está habilitado). El usuario conserva el acceso premium durante este tiempo. | | billing_issue_detected | Se activa cuando ocurre un problema de facturación durante un intento de cobro (p. ej., saldo insuficiente en la tarjeta). | | subscription_refunded | Se activa cuando se reembolsa una suscripción (p. ej., por parte del soporte de Apple). | | non_subscription_purchase_refunded | Se activa cuando se reembolsa una compra que no es una suscripción. | | access_level_updated | Ocurre cuando se actualiza el nivel de acceso de un usuario. | :::note `subscription_renewal_reactivated` lleva el ID del producto **anterior** — el que estaba activo cuando el usuario canceló — incluso si el usuario reactivó la suscripción comprando un producto diferente. Apple mantiene el mismo `original_transaction_id` a lo largo de la cadena cancelación → reactivación, por lo que este evento refleja el producto original. El nuevo producto aparece en el siguiente evento `subscription_renewed`, cuando comienza la facturación del nuevo producto. ::: ## Estructura de los eventos de webhook \{#webhook-event-structure\} Adapty solo te enviará los eventos que hayas seleccionado en la sección **Events names** de la página [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). Los eventos del webhook se serializan en JSON. El cuerpo de la solicitud `POST` enviada a tu servidor contendrá el evento serializado dentro de la estructura que se muestra a continuación. Todos los eventos siguen la misma estructura, aunque sus campos varían según el tipo de evento, el store y tu configuración específica. Los atributos de usuario son los [atributos de usuario personalizados](setting-user-attributes#custom-user-attributes) que hayas configurado, por lo que contienen lo que tú hayas definido. Los campos de datos de atribución también son iguales para todos los tipos de eventos; sin embargo, la lista de atribuciones dependerá de las fuentes de atribución que uses en tu app. A continuación puedes ver un ejemplo de evento: ```json title="Json" showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem", "idfv": "00000000-0000-0000-0000-000000000000", "idfa": "00000000-0000-0000-0000-000000000000", "advertising_id": "00000000-0000-0000-0000-000000000000", "profile_install_datetime": "2000-01-31T00:00:00.000000+0000", "user_agent": "ExampleUserAgent/1.0 (Device; OS Version) Browser/Engine", "email": "john.doe@company.com", "event_type": "subscription_started", "event_datetime": "2000-01-31T00:00:00.000000+0000", "event_properties": { "store": "play_store", "currency": "USD", "price_usd": 4.99, "profile_id": "00000000-0000-0000-0000-000000000000", "cohort_name": "All Users", "environment": "Production", "price_local": 4.99, "original_price_usd": 4.99, "original_price_local": 4.99, "discount_amount_usd": 0, "discount_amount_local": 0, "base_plan_id": "b1", "developer_id": "onboarding_placement", "ab_test_name": "onboarding_ab_test", "ab_test_revision": 1, "paywall_name": "UsedPaywall", "proceeds_usd": 4.2315, "variation_id": "00000000-0000-0000-0000-000000000000", "purchase_date": "2024-11-15T10:45:36.181000+0000", "store_country": "AR", "event_datetime": "2000-01-31T00:00:00.000000+0000", "proceeds_local": 4.2415, "tax_amount_usd": 0, "transaction_id": "0000000000000000", "net_revenue_usd": 4.2415, "profile_country": "AR", "paywall_revision": "1", "profile_event_id": "00000000-0000-0000-0000-000000000000", "tax_amount_local": 0, "net_revenue_local": 4.2415, "vendor_product_id": "onemonth_no_trial", "profile_ip_address": "10.10.1.1", "consecutive_payments": 1, "rate_after_first_year": false, "original_purchase_date": "2000-01-31T00:00:00.000000+0000", "original_transaction_id": "0000000000000000", "subscription_expires_at": "2000-01-31T00:00:00.000000+0000", "profile_has_access_level": true, "profile_total_revenue_usd": 4.99, "promotional_offer_id": null, "store_offer_category": null, "store_offer_discount_type": null }, "event_api_version": 1, "profiles_sharing_access_level": [{"profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem"}], "attributions": { "appsflyer": { "ad_set": "Keywords 1.12", "status": "non_organic", "channel": "Google Ads", "ad_group": null, "campaign": "Social media influencers - Rest of the world", "creative": null, "created_at": "2000-01-31T00:00:00.000000+0000" } }, "user_attributes": {"Favourite_color": "Violet", "Pet_name": "Fluffy"}, "integration_ids": {"firebase_app_instance_id": "val1", "branch_id": "val2", "one_signal_player_id": "val3"}, "play_store_purchase_token": { "product_id": "product_123", "purchase_token": "token_abc_123", "is_subscription": true } } ``` ### Campos del evento \{#event-fields\} Los parámetros de evento son los mismos para todos los tipos de evento. | **Campo** | **Tipo** | **Descripción** | |---|---|---| | **advertising_id** | UUID | ID de publicidad (solo Android). | | **attributions** | JSON | [Datos de atribución](webhook-event-types-and-fields#attributions). Se incluye si **Send Attribution** está habilitado en los [ajustes del Webhook](https://app.adapty.io/integrations/customwebhook). | | **customer_user_id** | String | ID de usuario de tu app (UUID, email u otro ID) si lo has definido en el código de tu app al [identificar usuarios](ios-quickstart-identify). Si no identificas usuarios en el código de la app o este usuario en concreto es anónimo (no ha iniciado sesión), este campo es `null`. | | **email** | String | Email del usuario si lo has definido mediante el método [`updateProfile`](setting-user-attributes) del SDK de Adapty o al crear/actualizar perfiles a través de la API del servidor. Si no pasas el valor `email` al SDK o al método de la API, este campo es `null`. | | **event_api_version** | Integer | Versión de la API de Adapty (actual: `1`). | | **event_datetime** | ISO 8601 | La hora efectiva (de negocio) del evento, como la fecha de compra para una compra o la fecha de expiración para una expiración — no cuando Adapty recibió o envió el evento. Formato [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) (p. ej., `2020-07-10T15:00:00.000000+0000`). Consulta la nota a continuación sobre el orden. | | **event_properties** | JSON | [Propiedades del evento](webhook-event-types-and-fields#event-properties). | | **event_type** | String | Nombre del evento en formato Adapty. Consulta [Tipos de eventos de Webhook](webhook-event-types-and-fields#webhook-event-types) para ver la lista completa. | | **idfa** | UUID | ID de publicidad (solo Apple). **IDFA** en el perfil en el [Adapty Dashboard](https://app.adapty.io/profiles/users). Puede ser `null` si no está disponible debido a restricciones de seguimiento, modo infantil o ajustes de privacidad. | | **idfv** | UUID | Identificador para proveedores (IDFV), único por desarrollador. **IDFV** en el perfil en el [Adapty Dashboard](https://app.adapty.io/profiles/users). | | **integration_ids** | JSON | IDs de integración del usuario si los has definido mediante el método `setIntegrationIdentifier` del SDK de Adapty o al crear/actualizar perfiles a través de la API del servidor. `null` si no están disponibles o las integraciones están deshabilitadas. | | **play_store_purchase_token** | JSON | [Token de compra de Play Store](webhook-event-types-and-fields#play-store-purchase-token), incluido si **Send Play Store purchase token** está habilitado en los [ajustes del Webhook](https://app.adapty.io/integrations/customwebhook). | | **profile_id** | UUID | ID de perfil generado automáticamente por Adapty para cada perfil. Un mismo ID de Apple/Google puede estar asociado a diferentes IDs de perfil si no identificas usuarios o permites compras antes del inicio de sesión. Más información sobre [cómo funciona Adapty con perfiles padre/heredero](how-profiles-work#parent-and-inheritor-profiles). | | **profile_install_datetime** | ISO 8601 | Marca de tiempo de instalación en formato [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) (p. ej., `2020-07-10T15:00:00.000000+0000`). | | **profiles_sharing_access_level** | JSON | Lista de usuarios que [comparten el nivel de acceso](general#6-sharing-paid-access-between-user-accounts) excluyendo el perfil de usuario actual. Si el uso compartido de niveles de acceso está habilitado en tu app, esta lista incluye otros perfiles que se han usado con el mismo ID de Apple/Google.Aunque los valores de atributos personalizados en el código de la app para móvil pueden definirse como floats o strings, los atributos recibidos a través de la API del servidor o importación histórica pueden llegar en distintos formatos. En ese caso, los valores booleanos y enteros se convertirán a floats.
| :::note `event_datetime` refleja cuándo ocurrió un evento en el ciclo de vida de la suscripción, no cuándo Adapty lo procesó o entregó. Por este motivo, varios eventos pueden compartir el mismo `event_datetime` o llegar fuera de orden cronológico. Por ejemplo, un evento `subscription_expired` puede tener un `event_datetime` anterior al de un evento `subscription_renewal_cancelled` que Adapty entrega antes que él. No uses `event_datetime` para ordenar eventos. En su lugar, ordénalos por tu propio tiempo de recepción y elimina duplicados usando `profile_event_id` o los IDs de transacción. ::: ### Atribuciones \{#attributions\} Para enviar los datos de atribución, activa la opción **Send Attribution** en la página [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). Si has activado el envío de datos de atribución y tienes configuradas las [integraciones de atribución](attribution-integration), los datos a continuación se enviarán con el evento para cada fuente. Los mismos datos de atribución se envían a todos los tipos de eventos. ```json title="Json" showLineNumbers { "attributions": { "appsflyer": { "ad_set": "sample_ad_set_123", "status": "non_organic", "channel": "sample_channel", "ad_group": "sample_ad_group_456", "campaign": "sample_ios_campaign", "creative": "sample_creative_789", "created_at": "2000-01-31T00:00:00.000000+0000", "network_user_id": "0000000000000-0000000" } } } ``` | Nombre del campo | Tipo de campo | Descripción | | :------------------ | :------------ | :------------------------------------------------- | | **ad_set** | String | Conjunto de anuncios de atribución. | | **status** | String | Puede ser `organic`, `non_organic,` o `unknown`. | | **channel** | String | Nombre del canal de marketing. | | **ad_group** | String | Grupo de anuncios de atribución. | | **campaign** | String | Nombre de la campaña de marketing. | | **creative** | String | Palabra clave creativa de atribución. | | **created_at** | Fecha ISO 8601 | Fecha y hora de creación del registro de atribución. | | **network_user_id** | String | ID asignado al usuario por la fuente de atribución. | ### IDs de integración \{#integration-ids\} Los siguientes IDs de integración se utilizan actualmente en los eventos: - `adjust_device_id` - `airbridge_device_id` - `amplitude_device_id` - `amplitude_user_id` - `appmetrica_device_id` - `appmetrica_profile_id` - `appsflyer_id` - `branch_id` - `facebook_anonymous_id` - `firebase_app_instance_id` - `mixpanel_user_id` - `pushwoosh_hwid` - `one_signal_player_id` - `one_signal_subscription_id` - `tenjin_analytics_installation_id` - `posthog_distinct_user_id` ### Token de compra de Play Store \{#play-store-purchase-token\} Este campo incluye todos los datos necesarios para revalidar una compra si es preciso. Solo se envía si la opción **Send Play Store purchase token** está habilitada en la [configuración de la integración de Webhook](https://app.adapty.io/integrations/customwebhook). | Campo | Tipo | Descripción | | :------------------ | :------ | :----------------------------------------------------------- | | **product_id** | String | El identificador único del producto (SKU) comprado en Play Store. | | **purchase_token** | String | Token generado por Google Play para identificar de forma única esta transacción de compra. | | **is_subscription** | Boolean | Indica si el producto comprado es una suscripción (`true`) o una compra única (`false`). | ### Propiedades de eventos \{#event-properties\} Las propiedades de los eventos pueden variar según el tipo de evento e incluso entre eventos del mismo tipo. Por ejemplo, un evento originado en el App Store no incluirá propiedades específicas de Android como `base_plan_id`. El evento [Nivel de acceso actualizado](webhook-event-types-and-fields#for-access-level-updated-event) tiene propiedades específicas, por lo que le hemos dedicado una sección aparte. Del mismo modo, hemos separado las [Propiedades adicionales de eventos fiscales y de ingresos](webhook-event-types-and-fields#additional-tax-and-revenue-event-properties), ya que son exclusivas de ciertos tipos de eventos. #### Para la mayoría de los tipos de eventos \{#for-most-event-types\} Las propiedades de los eventos son consistentes para la mayoría de los tipos de eventos (excepto para el evento **Access Level Updated**, que se describe en su propia sección). A continuación se muestra una tabla completa con las propiedades e indicaciones sobre si pertenecen a eventos específicos. :::note Adapty convierte otras divisas a USD según el tipo de cambio de [currencylayer.com](https://currencylayer.com/) (actualizado cada 8 horas). El tipo de cambio se **fija en el momento de la transacción** — los cambios futuros no afectan al resultado de la conversión. ::: | Campo | Tipo | Descripción | |:------------------------------|:--------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **ab_test_name** | String | Nombre de la [prueba A/B de Adapty](ab-tests) en la que se originó la transacción. | | **ab_test_revision** | Integer | Revisión de la prueba A/B en la que se originó la transacción. | | **base_plan_id** | String | [ID del plan base](https://support.google.com/googleplay/android-developer/answer/12154973) en Google Play Store o [ID de precio](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices) en Stripe. | | **cancellation_reason** | String |Posibles motivos de cancelación: `voluntarily_cancelled`, `billing_error`, `price_increase`, `product_was_not_available`, `refund`, `cancelled_by_developer`, `new_subscription_replace`, `upgraded`, `unknown`, `adapty_revoked`.
Presente en los siguientes tipos de evento:
`subscription_cancelled`, `subscription_refunded` y `trial_cancelled`. | | **cohort_name** | String | El nombre de la [audiencia](audience) que determinó qué paywall se mostró al usuario. | | **consecutive_payments** | Integer | El número de períodos que un usuario lleva suscrito sin interrupciones. Incluye el período actual. | | **currency** | String | Moneda local. | | **developer_id** | String | El ID del [placement](placements) en el que se originó la transacción. | | **discount_amount_local** | Float | El descuento aplicado a la transacción: el precio estándar menos el importe realmente cobrado, antes de la comisión de Apple/Google, en moneda local. `0` para una compra a precio completo. En una prueba gratuita, equivale al precio estándar completo (`original_price_local`), ya que no se cobra nada. `null` cuando se aplicó una oferta pero el precio estándar es desconocido (véase `original_price_local`). Siempre `null` para las ofertas de pago anticipado de App Store: el cargo único cubre varios períodos de facturación, por lo que no puede compararse con el precio estándar por período. | | **discount_amount_usd** | Float | El valor de `discount_amount_local` en USD. | | **environment** | String | Los valores posibles son `Sandbox` o `Production`. | | **event_datetime** | ISO 8601 date | La fecha y hora del evento. Igual que en el nivel raíz del evento. | | **original_price_local** | Float | El precio estándar del producto sin descuento antes de la comisión de Apple/Google, en moneda local. En las suscripciones, este es el precio de renovación. Equivale a `price_local` en una compra a precio completo y siempre equivale a `price_local` en compras únicas, ya que las stores no reportan un precio estándar separado para ellas. `null` para una compra con descuento cuando la store no reporta un precio estándar fiable (por ejemplo, la renovación automática está desactivada, la renovación aún lleva una oferta, o hay un cambio de producto pendiente). | | **original_price_usd** | Float | Igual que `original_price_local`, en USD. | | **original_purchase_date** | ISO 8601 date | En las suscripciones recurrentes, la compra original es la primera transacción de la cadena; su ID, denominado ID de transacción original, vincula la cadena de renovaciones. Las transacciones posteriores son extensiones de esta. La fecha de compra original es la fecha y hora de esa primera transacción. | | **original_transaction_id** | String |En las suscripciones recurrentes, este es el ID de transacción original que vincula la cadena de renovaciones. La transacción original es la primera de la cadena; las posteriores son extensiones de ella.
Si no hay extensiones, `original_transaction_id` coincide con store_transaction_id.
| | **paywall_name** | String | Nombre del paywall en el que se originó la transacción. | | **paywall_revision** | String | Revisión del paywall en el que se originó la transacción. El valor predeterminado es 1. | | **price_local** | Float | El importe cobrado por la transacción antes de la comisión de Apple/Google, en moneda local. `null` para las pruebas gratuitas, ya que no se cobra nada. | | **price_usd** | Float | El importe cobrado por la transacción antes de la comisión de Apple/Google, en USD. `null` para las pruebas gratuitas, ya que no se cobra nada. | | **profile_country** | String | Determinado por Adapty a partir de la IP del perfil. | | **profile_event_id** | UUID | ID de evento único que puede usarse para deduplicación. | | **profile_has_access_level** | Boolean | Booleano que indica si el perfil tiene un nivel de acceso activo. | | **profile_id** | UUID | ID de perfil generado por Adapty. Igual que en el nivel raíz del evento. | | **profile_ip_address** | String | IP del perfil (puede ser IPv4 o IPv6; se prefiere IPv4 cuando está disponible). `null` si **Collect users' IP addresses** está desactivado en los [ajustes de la app](https://app.adapty.io/settings/general). | | **profile_total_revenue_usd** | Float | Ingresos totales del perfil con los reembolsos descontados. | | **promotional_offer_id** | String | El ID de Adapty de la [oferta promocional](offers) utilizada. Este ID se establece al crear una oferta en el dashboard. | | **purchase_date** | ISO 8601 date | La fecha y hora de la compra del producto. | | **rate_after_first_year** | Boolean | Booleano que indica que la suscripción cumple los requisitos para una tasa de comisión reducida (habitualmente el 15%) tras un año de renovación continua. Las tasas de comisión varían según la elegibilidad al programa y el país. Consulta [Comisión de la store e impuestos](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue) para más detalles. | | **store** | String | Store donde se realizó la compra. Valores estándar: **app_store**, **play_store**, **stripe**, **paddle**.ID del producto en Apple App Store, Google Play Store o Stripe.
Si se concedió acceso sin una transacción real en la store, `vendor_product_id` será uno de los siguientes:
En las suscripciones recurrentes, es el ID de transacción original que vincula la cadena de renovaciones. La transacción original es la primera de la cadena; las transacciones posteriores son extensiones de esta.
Si no hay extensiones, `original_transaction_id` coincide con store_transaction_id.
El identificador de transacción de la compra original. | | **paywall_name** | String | Nombre del paywall donde se originó la transacción. | | **paywall_revision** | String | Revisión del paywall donde se originó la transacción. El valor predeterminado es 1. | | **profile_country** | String | Determinado por Adapty a partir de la IP del perfil. | | **profile_event_id** | UUID | ID único del evento que puede usarse para deduplicación. | | **profile_has_access_level** | Boolean | Booleano que indica si el perfil tiene un nivel de acceso activo. | | **profile_id** | UUID | ID interno del perfil de usuario de Adapty. | | **profile_ip_address** | String | IP del perfil (puede ser IPv4 o IPv6, con preferencia por IPv4 cuando esté disponible). `null` si **Collect users' IP addresses** está desactivado en los [ajustes de la app](https://app.adapty.io/settings/general). | | **profile_total_revenue_usd** | Float | Ingresos totales del perfil, incluidos los reembolsos. | | **purchase_date** | ISO 8601 date | La fecha y hora de compra del producto. | | **renewed_at** | ISO 8601 date | Fecha y hora en que se renovará el acceso. | | **starts_at** | ISO 8601 date | Fecha y hora en que comienza el nivel de acceso. | | **store** | String | Store donde se adquirió el producto. Valores estándar: **app_store**, **play_store**, **stripe**, **paddle**.ID del producto en el store (Apple/Google/Stripe).
Si el acceso se otorgó sin una transacción real en el store, `vendor_product_id` será uno de los siguientes:
1. **Configuras tu endpoint:** 1. Asegúrate de que tu servidor pueda procesar las solicitudes de Adapty con el encabezado **Content-Type** configurado como `application/json`. 2. Configura tu servidor para recibir la solicitud de verificación de Adapty y responder con cualquier estado `2xx` y un cuerpo JSON. 3. [Gestiona los eventos de suscripción](#subscription-events) una vez verificada la conexión. 2. **Configuras y activas la integración del webhook** en el [Adapty Dashboard](#configure-webhook-integration-in-the-adapty-dashboard). También puedes [mapear los eventos de Adapty a nombres de eventos personalizados](#configure-webhook-integration-in-the-adapty-dashboard). Te recomendamos probar en el entorno **Sandbox** antes de pasar a producción. 3. **Adapty envía una solicitud de verificación** a tu servidor. 4. **Tu servidor responde** con un estado `2XX` y un cuerpo JSON. 5. **Una vez que Adapty recibe una respuesta válida, comienza a enviar eventos de suscripción.** ## Configura tu servidor para procesar las solicitudes de Adapty \{#set-up-your-server-to-process-adapty-requests\} Adapty enviará a tu endpoint de webhook 2 tipos de solicitudes: 1. [Solicitud de verificación](#verification-request): la solicitud inicial para verificar que la conexión está configurada correctamente. Esta solicitud no contendrá ningún evento y se enviará en el momento en que hagas clic en el botón **Save** en la integración de Webhook del Adapty Dashboard. Para confirmar que tu endpoint recibió correctamente la solicitud de verificación, tu endpoint debe responder con la respuesta de verificación. 2. [Evento de suscripción](#subscription-events): una solicitud estándar que el servidor de Adapty envía cada vez que se crea un evento en él. Tu servidor no necesita responder con ninguna respuesta específica. Lo único que necesita el servidor de Adapty es recibir una respuesta HTTP estándar con código 200 si recibe el mensaje correctamente. ### Solicitud de verificación Después de habilitar la integración de webhook en el Adapty Dashboard, Adapty enviará una solicitud POST de verificación que contiene un objeto JSON vacío `{}` como cuerpo. Configura tu endpoint para que tenga el **encabezado Content-Type** como `application/json`, es decir, el endpoint de tu servidor debe esperar que la solicitud webhook entrante tenga su payload en formato JSON. Tu servidor debe responder con un código de estado 2xx y enviar cualquier respuesta JSON válida, por ejemplo: ```json title="Json" {} ``` Una vez que Adapty recibe la respuesta de verificación en el formato correcto y con un código de estado 2xx, tu integración de webhook con Adapty está completamente configurada. ### Eventos de suscripción \{#subscription-events\} Los eventos de suscripción se envían con la cabecera **Content-Type** establecida en `application/json` y contienen datos del evento en formato JSON. Para conocer los posibles tipos de eventos y las estructuras de solicitud, consulta [Tipos de eventos y campos del webhook](webhook-event-types-and-fields). ## Configurar la integración de webhook en el Adapty Dashboard \{#configure-webhook-integration-in-the-adapty-dashboard\} Dentro de Adapty, puedes configurar flujos separados para los eventos de producción y los eventos de prueba recibidos desde el entorno sandbox de Apple o Stripe, o desde la cuenta de prueba de Google. :::tip Adapty admite una URL de webhook por entorno (producción y sandbox). Para enviar eventos a varios servicios, apunta el webhook a tu propio backend y distribúyelos desde allí. ::: Para los eventos de producción, usa el campo **Production endpoint URL** para especificar la URL a la que se enviarán los callbacks. Además, configura el campo **Authorization header value for production endpoint** — la cabecera que usará tu servidor para autenticar los eventos de Adapty. Ten en cuenta que el valor especificado en el campo **Authorization header value for production endpoint** se usará como cabecera `Authorization` exactamente tal como se proporciona, sin ningún cambio ni añadido. Para los eventos de prueba, utiliza los campos **Sandbox endpoint URL** y **Authorization header value for sandbox endpoint** según corresponda. Para configurar la integración con webhook: 1. Abre [Integrations -> Webhook](https://app.adapty.io/integrations/customwebhook) en tu Adapty Dashboard.
2. Activa el interruptor para iniciar la integración.
4. Rellena los campos de la integración:
| Campo | Descripción |
| ------------------------------------------------------ | ------------------------------------------------------------ |
| **Production endpoint URL** | La URL que usa Adapty para enviar solicitudes HTTP POST de eventos en producción. |
| **Authorization header value for production endpoint** | El encabezado que tu servidor usará para autenticar las solicitudes de Adapty en producción. Ten en cuenta que utilizaremos el valor especificado en este campo como encabezado `Authorization` exactamente como se proporcione, sin ningún cambio ni adición.
Aunque no es obligatorio, se recomienda encarecidamente para mayor seguridad.
| Además, para tus necesidades de pruebas en el entorno sandbox, hay otros dos campos disponibles: | Campo de prueba | Descripción | | ----------------------------------------------------- | ------------------------------------------------------------ | | **Sandbox endpoint URL** | La URL que usa Adapty para enviar solicitudes HTTP POST de eventos en el entorno sandbox. | | **Authorization header value for sandbox endpoint** |El encabezado que usará tu servidor para autenticar las solicitudes de Adapty durante las pruebas en el entorno sandbox. Ten en cuenta que usaremos el valor especificado en este campo como encabezado `Authorization` exactamente como se proporcionó, sin ningún cambio ni adición.
Aunque no es obligatorio, se recomienda encarecidamente para mayor seguridad.
| 4. (opcional) Elige los eventos que quieres recibir y asigna sus nombres. Consulta nuestros [Flujos de eventos](event-flows) para ver qué eventos se disparan en cada situación. Si los IDs de tus eventos son distintos a los que usa Adapty, mantenlos tal como están en tu sistema y sustituye los IDs de eventos predeterminados de Adapty por los tuyos en la sección **Events names** de la página [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook). El ID de evento puede ser cualquier cadena; simplemente asegúrate de que el ID de evento en tu servidor de procesamiento de webhooks coincida con el que introdujiste en el Adapty Dashboard. No puedes dejar el ID de evento vacío para los eventos habilitados.
5. Los campos y opciones adicionales no son obligatorios; úsalos según necesites:
| Ajuste | Descripción |
| :------------------------------------ | :----------------------------------------------------------- |
| **Send Trial Price** | Cuando está activado, Adapty incluirá el precio de la suscripción en los campos `price_local` y `price_usd` para el evento **Trial Started**. |
| **Exclude Historical Events** | Permite excluir eventos ocurridos antes de que el usuario instalara la app con el SDK de Adapty. Esto evita la duplicación de eventos y garantiza informes precisos. Por ejemplo, si un usuario activó una suscripción mensual el 10 de enero y actualizó la app con el SDK de Adapty el 6 de marzo, Adapty omitirá los eventos anteriores al 6 de marzo y conservará los posteriores. |
| **Send user attributes** | Activa esta opción para enviar atributos específicos del usuario, como preferencias de idioma. Estos atributos aparecerán en el campo `user_attributes`. Consulta [Campos del evento](webhook-event-types-and-fields#event-fields) para más información. |
| **Send attribution** | Activa esta opción para incluir información de atribución (p. ej., datos de AppsFlyer) en el campo `attributions`. Consulta la sección [Datos de atribución](webhook-event-types-and-fields#attributions) para más detalles. |
| **Send Play Store purchase token** | Activa esta opción para recibir el token de Play Store necesario para la revalidación de compras, si fuera necesario. Al activarla, se añadirá el parámetro `play_store_purchase_token` al evento. Para más detalles sobre su contenido, consulta la sección [Token de compra de Play Store](webhook-event-types-and-fields#play-store-purchase-token). |
6. Recuerda hacer clic en el botón **Save** para confirmar los cambios.
En el momento en que hagas clic en el botón **Save**, Adapty enviará una solicitud de verificación y esperará la respuesta de verificación de tu servidor.
### Elige los eventos a enviar y mapea los nombres de eventos \{#choose-events-to-send-and-map-event-names\}
Elige los eventos que quieres recibir en tu servidor activando el interruptor correspondiente. Si los nombres de tus eventos son distintos a los que usa Adapty y necesitas mantener los tuyos, puedes configurar el mapeo reemplazando los nombres de eventos predeterminados de Adapty por los tuyos en la sección **Events names** de la página [Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook).
El nombre del evento puede ser cualquier cadena de texto. No puedes dejar los campos vacíos para los eventos habilitados. Si borraste accidentalmente el nombre de un evento de Adapty, siempre puedes copiarlo desde el artículo [Eventos para enviar a integraciones de terceros](events).
## Manejar eventos de webhook \{#handle-webhook-events\}
Los webhooks generalmente se entregan entre 5 y 60 segundos después de que ocurre el evento. Sin embargo, los eventos de cancelación pueden tardar hasta 2 horas en entregarse tras la cancelación de una suscripción por parte del usuario.
Si el código de estado de respuesta de tu servidor está fuera del rango 200-404, Adapty reintenta la entrega con retroceso exponencial. El primer reintento ocurre aproximadamente **1 minuto** después del fallo inicial, duplicándose en cada intento sucesivo — hasta 9 reintentos distribuidos a lo largo de 24 horas. Te recomendamos que configures tu webhook para realizar solo una validación básica del cuerpo del evento de Adapty antes de responder. Si tu servidor no puede procesar el evento y no quieres que Adapty reintente, usa un código de estado dentro del rango 200-404. Además, gestiona cualquier tarea que consuma tiempo de forma asíncrona y responde a Adapty con rapidez. Si Adapty no recibe respuesta en 10 segundos, considerará el intento como fallido y lo reintentará.
---
# File: test-webhook
---
---
title: "Probar la integración de webhook"
description: "Prueba las integraciones de webhook en Adapty para automatizar el seguimiento de eventos de suscripción."
---
Una vez que hayas configurado tu integración, es momento de probarla. Puedes probar tanto la integración en sandbox como la de producción. Te recomendamos empezar con la de sandbox y validar al máximo en ella:
- Los eventos se envían y se entregan correctamente.
- Configuraste correctamente las opciones para eventos históricos, el precio de la suscripción para el evento **Trial started**, la atribución, los atributos de usuario y el token de compra de Google Play Store para que se envíen o no con un evento.
- Mapeaste los nombres de los eventos correctamente y tu servidor puede procesarlos.
## Cómo probar \{#how-to-test\}
Antes de empezar a probar una integración, asegúrate de haber:
1. Configurado la integración de webhook según se describe en el tema [Configurar la integración de webhook](set-up-webhook-integration).
2. Configurado el entorno según se describe en los temas [Probar compras in-app en Apple App Store](test-purchases-in-sandbox) y [Probar compras in-app en Google Play Store](testing-on-android). Asegúrate de haber compilado tu app de prueba en el entorno sandbox y no en producción.
3. Realizado una compra / iniciado una prueba / solicitado un reembolso que genere el evento que elegiste enviar al webhook. Por ejemplo, para obtener el evento **Subscription started**, realiza una nueva suscripción.
## Validación del resultado \{#validation-of-the-result\}
### Resultado exitoso al enviar eventos \{#successful-sending-events-result\}
En caso de una integración exitosa, el evento aparecerá en la sección **Last sent events** de la integración y tendrá el estado **Success**.
### Resultado fallido al enviar eventos \{#unsuccessful-sending-events-result\}
| Problema | Solución |
|-----|--------|
| El evento no apareció | Tu compra no se realizó y, por lo tanto, el evento no se creó. Consulta el tema [Solución de problemas con compras de prueba](troubleshooting-test-purchases) para encontrar la solución. |
| El evento apareció y tiene el estado **Sending failed** | Determinamos la entregabilidad en función del estado HTTP y consideramos todo lo que esté **fuera del rango 200-399** como un fallo.
Para obtener más información sobre el problema, pasa el cursor sobre el estado **Sending failed** de tu evento fallido como se muestra a continuación.
|
---
# File: handle-integration-errors
---
---
title: "Gestionar errores en integraciones"
description: "Gestionar errores en integraciones"
---
Al usar cualquier integración de atribución, mensajería o analíticas, puede que encuentres algunos errores comunes. Consulta esta guía para los casos de solución de problemas.
## Discrepancia de datos \{#data-discrepancy\}
**Motivo**: Esto puede ocurrir porque no todos tus usuarios usan la versión de la app que tiene el SDK de Adapty.
**Solución**: Para garantizar la consistencia de los datos, puedes obligar a tus usuarios a actualizar la app a una versión con el SDK de Adapty.
## Errores de red \{#network-errors\}
**Motivo**: Lo más probable es que no haya habido conexión a internet entre el servidor de Adapty y el servidor de la integración.
**Solución**: Estos problemas normalmente no duran mucho y solo afectan a un pequeño número de eventos.
## El servidor de integración no pudo procesar el evento \{#integration-server-failed-to-process-the-event\}
**Motivo**: La integración está configurada incorrectamente.
**Solución**: Consulta el artículo sobre la integración en nuestra documentación. Asegúrate de haber completado todos los pasos de configuración tanto en el Adapty Dashboard, como en el lado de la herramienta de terceros y en el código de tu app.
## Datos de integración faltantes \{#missing-integration-data\}
**Motivo**: Al perfil le falta algún ID específico de la integración. Esto puede ocurrir cuando la integración no está configurada correctamente en el código de la app.
**Solución**: Consulta el artículo sobre la integración en nuestra documentación. Asegúrate de haber implementado los métodos de los fragmentos de código en el código de tu app, y de que estos métodos interactúen realmente con los perfiles de tus usuarios.
## Credenciales de integración faltantes \{#missing-integration-credentials\}
**Motivo**: Faltan algunas credenciales de integración o son incorrectas.
**Solución**: Comprueba todas las credenciales de esa integración en el Adapty Dashboard. El problema puede deberse a un desajuste de versión o de entorno.
## El evento ha expirado \{#the-event-has-expired\}
**Motivo**: La opción **Exclude historical events** está habilitada en la configuración de la integración, y la fecha de creación del evento es anterior a la fecha de creación del perfil en nuestro sistema.
Esto puede ocurrir si una cadena de transacciones que comenzó hace muchos años llega a Adapty mediante la validación de recibos para un perfil creado recientemente.
**Solución**: Asegúrate de que esto no ocurra con nuevos eventos. Si quieres enviar eventos históricos a la integración, desactiva **Exclude historical events**.
## Tipo de evento desactivado/no compatible \{#disabledunsupported-event-type\}
**Motivo**: El evento no está soportado por esta integración, o lo desactivaste al configurarla. Por ejemplo, los eventos `access_level_updated` no están soportados por la mayoría de las integraciones.
**Solución**: Consulta en la documentación de la integración si esta soporta ese tipo de evento. Si es así, en el Adapty Dashboard, asegúrate de que ese tipo de evento esté habilitado en la configuración de la integración.
---
# File: manage-adapty-with-ai
---
---
title: "Gestiona Adapty con agentes de IA y herramientas de codificación"
description: "Todas las formas de usar Adapty con IA: integra el SDK con un agente de codificación, consulta analíticas con un LLM y dale a tu herramienta de IA la documentación de Adapty."
---
Adapty funciona con herramientas de codificación y agentes de IA. Úsalos para integrar el SDK, consultar tus analíticas o buscar documentación de Adapty sin salir de tu editor. Esta página lista lo que está disponible y para quién es cada herramienta.
## Integra el SDK de Adapty con IA \{#integrate-the-adapty-sdk-with-ai\}
Dos formas de añadir el SDK de Adapty a tu app con una herramienta de codificación con IA. Ambas funcionan con Cursor, Claude y otros asistentes de IA.
### Integración basada en skills \{#skill-based-integration\}
El skill de integración del SDK de Adapty ejecuta toda la integración desde tu herramienta de codificación con IA con un solo comando. Úsalo cuando quieras una configuración guiada y automatizada.
Elige tu plataforma: [iOS](adapty-sdk-integration-skill) · [Android](adapty-sdk-integration-skill-android) · [React Native](adapty-sdk-integration-skill-react-native) · [Flutter](adapty-sdk-integration-skill-flutter) · [Unity](adapty-sdk-integration-skill-unity) · [Kotlin Multiplatform](adapty-sdk-integration-skill-kmp) · [Capacitor](adapty-sdk-integration-skill-capacitor)
### Integración paso a paso \{#step-by-step-integration\}
Guía a tu herramienta de IA por la integración etapa a etapa, dándole la documentación adecuada en orden. Úsalo cuando quieras revisar cada paso a medida que avanzas.
Elige tu plataforma: [iOS](adapty-cursor) · [Android](adapty-cursor-android) · [React Native](adapty-cursor-react-native) · [Flutter](adapty-cursor-flutter) · [Unity](adapty-cursor-unity) · [Kotlin Multiplatform](adapty-cursor-kmp) · [Capacitor](adapty-cursor-capacitor)
## Gestiona Adapty desde la línea de comandos \{#manage-adapty-from-the-command-line\}
La [CLI para desarrolladores de Adapty](developer-cli-quickstart) te permite gestionar tus entidades de Adapty — apps, niveles de acceso, productos, paywalls y placements — desde el terminal, sin abrir el dashboard. Al ser una herramienta de línea de comandos, tu agente de codificación con IA puede ejecutarla directamente.
## Consulta tus datos \{#ask-about-your-data\}
Apunta un agente de codificación con IA a la API de exportación de analíticas para consultar tus métricas en lenguaje natural: ingresos, retención, LTV y más. No se necesita servidor MCP.
[Consulta a la IA sobre tus datos analíticos](export-analytics-with-ai)
## Dale a tu herramienta de IA la documentación de Adapty \{#give-your-ai-tool-the-adapty-docs\}
### Documentación en texto plano \{#plain-text-docs\}
Toda la documentación de Adapty está disponible en Markdown: añade `.md` a la URL de la página o haz clic en **Copy for LLM** debajo del título. Para un contexto más amplio, dale a tu herramienta el índice [`llms.txt`](https://adapty.io/docs/es/llms.txt) o un subconjunto específico de plataforma como [`ios-llms.txt`](https://adapty.io/docs/es/ios-llms.txt).
### Context7 \{#context7\}
[Context7](https://context7.com/adaptyteam/adapty-docs) es un servidor MCP que sirve la documentación de Adapty a tu herramienta de IA, pero solo indexa fragmentos de código, no el texto completo. Úsalo para obtener ejemplos de código rápidos; para una guía completa, dale a tu herramienta la documentación en texto plano mencionada arriba. Context7 funciona con Cursor, Claude Code, Windsurf y otras herramientas compatibles con MCP.
---
# File: export-analytics-with-ai
---
---
title: "Pregunta a la IA sobre tus datos de analíticas"
description: "Consulta tus analíticas de Adapty en lenguaje natural con un agente de codificación de IA, usando la API de Export Analytics."
---
Pregunta a un agente de codificación con IA sobre tu analítica de Adapty en lenguaje natural — ingresos, conversiones, retención, LTV — y deja que obtenga los datos por ti. Apunta una herramienta que pueda hacer llamadas a la API hacia la [API de exportación de analítica](https://adapty.io/docs/es/export-analytics-api.md), y consultará tus métricas bajo demanda.
## Qué puedes consultar \{#what-you-can-ask-about\}
La Export Analytics API devuelve las mismas métricas que ves en los gráficos del Adapty Dashboard. Cada métrica tiene su propia operación:
| Métrica | Qué cubre | Operación |
| --- | --- | --- |
| Ingresos, MRR, ARR, ARPU | Dinero generado a lo largo del tiempo, agrupado por período, país o campaña | [retrieveAnalyticsData](https://adapty.io/docs/es/api-export-analytics/operations/retrieveAnalyticsData.md) |
| Retención de cohortes | Cuánto tiempo siguen pagando los suscriptores de una cohorte determinada | [retrieveCohortData](https://adapty.io/docs/es/api-export-analytics/operations/retrieveCohortData.md) |
| Tasas de conversión | Cuántos usuarios avanzan de un paso o canal al siguiente | [retrieveConversionData](https://adapty.io/docs/es/api-export-analytics/operations/retrieveConversionData.md) |
| Churn y embudo | Dónde abandonan los usuarios y con qué rapidez se dan de baja | [retrieveFunnelData](https://adapty.io/docs/es/api-export-analytics/operations/retrieveFunnelData.md) |
| Valor del ciclo de vida (LTV) | Ingresos medios por segmento de usuarios a lo largo del tiempo | [retrieveLTVData](https://adapty.io/docs/es/api-export-analytics/operations/retrieveLTVData.md) |
| Retención | Porcentaje de usuarios que siguen activos tras un número determinado de días | [retrieveRetentionData](https://adapty.io/docs/es/api-export-analytics/operations/retrieveRetentionData.md) |
Para ver la lista completa de parámetros y filtros, consulta la [referencia de la API](https://adapty.io/docs/es/api-export-analytics.md).
## Antes de empezar \{#before-you-start\}
Necesitas tres cosas:
- **Una cuenta de Adapty con datos**: La API devuelve las mismas métricas que los gráficos del dashboard, así que tu app ya debe recopilar analíticas.
- **Una clave de API secreta**: Encuéntrala en [App settings → General](https://app.adapty.io/settings/general), en el campo **Secret key**. Las claves son específicas por app, así que usa una clave distinta para cada una. Guárdala en una variable de entorno (por ejemplo, `ADAPTY_SECRET_KEY`) para que tu agente pueda leerla sin que tengas que pegarla en el chat.
- **Una herramienta de IA capaz de llamar APIs**: Por ejemplo, Claude Code, Cursor o Claude Desktop con una herramienta de fetch. Las herramientas de chat básicas como claude.ai o ChatGPT no pueden llamar a la API directamente.
## Dale a tu agente la especificación de la API \{#give-your-agent-the-api-spec\}
La [especificación OpenAPI](https://adapty.io/docs/es/api-specs/export-analytics-api.yaml) describe cada endpoint, la cabecera de autenticación, el cuerpo de la solicitud y ejemplos de respuesta. Una vez que tu agente tenga la especificación, construye solicitudes correctas sin que tengas que escribir ningún código.
Dale a tu agente la especificación mediante la URL:
- **Pega la URL**: Si tu agente puede obtener URLs, dale `https://adapty.io/docs/es/api-specs/export-analytics-api.yaml` y pídele que lea la especificación.
- **Usa una herramienta de fetch**: Si tu agente tiene una herramienta para recuperar URLs (por ejemplo, un servidor MCP de fetch), apúntala a la misma URL.
La especificación establece la URL base en `https://api-admin.adapty.io`, así que tu agente tiene todo lo que necesita una vez que tu clave esté en el entorno.
## Pregunta sobre tus datos \{#ask-about-your-data\}
Con la especificación cargada y tu clave en una variable de entorno, describe en lenguaje natural la métrica que necesitas.
Ejemplos de prompts:
```
What was my MRR at the end of each month this year, and how does it compare to last year?
Show my trial-to-paid conversion rate for the last 90 days, broken down by product.
Which countries drive the most revenue from my yearly subscription? Top 10.
How is week-1 retention trending for subscribers who started in the last 6 months?
What's the refund rate on my annual plan since launch, by month?
Compare LTV for paid-campaign users vs. organic over the last year, and export it as CSV.
```
El agente asigna tu solicitud a la operación correcta, lee la clave del entorno y devuelve los datos. Las respuestas son JSON por defecto. Pide CSV cuando quieras un archivo listo para hoja de cálculo — el agente establece `format` a `csv` en el cuerpo de la solicitud.
:::warning
Guarda tu clave secreta en una variable de entorno, no la pegues en el chat ni la incluyas en un archivo de reglas. Las claves son específicas de la app, así que rótala en **Settings → General** si se filtra. Consulta [rotar las claves de API](https://adapty.io/docs/es/export-analytics-api-authorization.md).
:::
## Configura una vez para reutilizar \{#set-up-once-for-repeated-use\}
Para no repetir la configuración en cada sesión, guarda la especificación y la clave donde tu agente pueda reutilizarlas:
- **Guarda el enlace de la spec**: Añade la URL de la spec a las reglas o al archivo de memoria de tu agente (por ejemplo, un archivo `CLAUDE.md` o las reglas de Cursor) para que se cargue en cada sesión.
- **Guarda la clave en tu entorno**: Mantén `ADAPTY_SECRET_KEY` en el perfil de tu shell o en el almacén de secretos de la herramienta para no tener que pegarla nunca más.
- **Guarda prompts reutilizables o crea una skill personalizada**: Conserva tus preguntas habituales como prompts guardados, o envuélvelas en una skill personalizada o en un slash command para que tu agente genere un informe cuando lo necesites.
## Límites \{#limits\}
Ten en cuenta estas restricciones:
- **Límite de velocidad**: La API permite 2 solicitudes por segundo por clave de API. Si se supera, devuelve un error `429 Too Many Requests`. Indica a tu agente que espere y reintente al recibir un `429`.
- **Claves por aplicación**: Cada clave funciona para una sola app. Para obtener datos de varias apps, proporciona la clave correspondiente a cada una.
- **Formato de salida**: Las respuestas son JSON por defecto. Establece `format` como `csv` en el cuerpo de la solicitud para exportar en CSV.
Para conocer todas las reglas de autenticación y formato de solicitud, consulta [Autorización y formato de solicitud](https://adapty.io/docs/es/export-analytics-api-authorization.md).
---
# File: handle-webhooks-with-ai
---
---
title: "Gestiona eventos de suscripción de Adapty con webhooks"
description: "Recibe y gestiona eventos de suscripción de Adapty en tu servidor con webhooks — configuración del endpoint, autenticación, payload y pruebas en una sola página."
---
Los webhooks permiten que tu servidor reciba eventos de suscripción de Adapty en tiempo real — compras, renovaciones, cancelaciones, problemas de facturación y reembolsos — para que puedas otorgar acceso, sincronizar tu backend o activar flujos de trabajo. Esta guía te lleva desde el endpoint hasta una integración verificada y probada en una sola página, y muestra cómo hacer que un agente de codificación con IA escriba el handler para tu stack.
:::tip
¿Usando un agente de codificación con IA? Haz clic en **Copy for LLM** bajo el título y pega toda esta página en tu agente — tiene la configuración, el payload y la lógica del handler que necesita.
:::
## Cómo funcionan los webhooks de Adapty \{#how-adapty-webhooks-work\}
- **Unidireccional y en tiempo real**: Adapty envía un `POST` HTTP a tu servidor cuando ocurre un evento — sin polling.
- **Dos tipos de solicitud**: Una solicitud de verificación única (enviada al guardar la integración) y los eventos de suscripción continuos.
- **Una URL por entorno**: Configuras un endpoint independiente para producción y para el sandbox.
- **Debes confirmar cada solicitud**: Responde con un estado `2xx` rápidamente; Adapty reintentará en caso de fallo.
## Crea tu endpoint \{#build-your-endpoint\}
Crea un endpoint HTTPS público que gestione dos tipos de solicitudes:
- **Solicitud de verificación**: Se envía una vez cuando guardas la integración. Tiene un cuerpo JSON vacío (`{}`). Responde con un estado `2xx` y un cuerpo JSON.
- **Eventos de suscripción**: Solicitudes `POST` continuas con el evento en el cuerpo. Responde `200` en menos de 10 segundos y realiza cualquier tarea pesada de forma asíncrona.
Elige una cadena secreta y guárdala como variable de entorno (por ejemplo, `ADAPTY_WEBHOOK_SECRET`). En cada petición, comprueba que el encabezado `Authorization` coincide con ella y rechaza la petición si no coincide — el mismo secreto lo introducirás en el dashboard a continuación.
```javascript title="webhook.js"
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.ADAPTY_WEBHOOK_SECRET;
app.post("/adapty/webhook", (req, res) => {
// 1. Verify the shared secret Adapty echoes back.
if (req.get("Authorization") !== WEBHOOK_SECRET) {
return res.sendStatus(401);
}
// 2. Acknowledge fast, then process asynchronously.
res.status(200).json({});
// 3. The verification request has an empty body — nothing to handle.
const event = req.body;
if (!event.event_type) return;
switch (event.event_type) {
case "subscription_started":
case "subscription_renewed":
case "trial_converted":
// Grant or extend access.
break;
case "subscription_expired":
case "subscription_refunded":
// Revoke access.
break;
default:
break;
}
});
app.listen(3000);
```
Despliega el endpoint en una URL HTTPS pública antes de configurar la integración: Adapty envía la solicitud de verificación en el momento en que guardas.
### Eventos clave y el payload \{#key-events-and-the-payload\}
Todos los eventos comparten el mismo sobre. Los campos varían según el tipo de evento, el store y las opciones que hayas activado. Aquí tienes un ejemplo reducido del evento `subscription_started`:
```json title="Example event"
{
"profile_id": "00000000-0000-0000-0000-000000000000",
"customer_user_id": "UserIdInYourSystem",
"event_type": "subscription_started",
"event_datetime": "2024-11-15T10:45:36.181000+0000",
"event_properties": {
"store": "play_store",
"currency": "USD",
"price_usd": 4.99,
"vendor_product_id": "onemonth_no_trial",
"transaction_id": "0000000000000000",
"original_transaction_id": "0000000000000000",
"subscription_expires_at": "2024-12-15T10:45:36.181000+0000",
"profile_event_id": "00000000-0000-0000-0000-000000000000"
},
"event_api_version": 1
}
```
Los eventos que gestionarás con más frecuencia:
| Tipo de evento | Se activa cuando |
| --- | --- |
| `subscription_started` | Un usuario inicia una suscripción de pago |
| `subscription_renewed` | Una suscripción se renueva y se cobra con éxito |
| `subscription_renewal_cancelled` | Un usuario desactiva la renovación automática (el acceso dura hasta la fecha de expiración) |
| `subscription_expired` | El acceso termina después de que una suscripción no renovada caduca |
| `trial_started` | Un usuario inicia una prueba gratuita |
| `trial_converted` | Una prueba se convierte en una suscripción de pago |
| `billing_issue_detected` | Falla el pago de una renovación |
| `subscription_refunded` | Se reembolsa una compra de suscripción |
Para la lista completa de eventos y cada campo, consulta [Tipos de eventos y campos de webhook](https://adapty.io/docs/es/webhook-event-types-and-fields.md).
:::warning
No ordenes los eventos por `event_datetime` — es el momento de negocio del evento, por lo que los eventos pueden llegar desordenados o compartir el mismo timestamp. Ordénalos por tu propio tiempo de recepción y deduplícalos usando `profile_event_id` o los IDs de transacción.
:::
## Configura el webhook en Adapty \{#configure-the-webhook-in-adapty\}
1. Abre [Integrations → Webhook](https://app.adapty.io/integrations/customwebhook) en el Adapty Dashboard.
2. Activa la integración.
3. En **Production endpoint URL**, introduce la URL HTTPS del endpoint que has desplegado.
4. En **Authorization header value for production endpoint**, introduce el mismo secreto que comprueba tu endpoint. Adapty envía este valor en el header `Authorization` en cada petición. Es opcional, pero muy recomendable.
5. Para probar primero en sandbox, rellena también **Sandbox endpoint URL** y su **Authorization header value**.
6. Haz clic en **Save**. Adapty envía inmediatamente la solicitud de verificación a tu endpoint, que responde con un `2xx` para completar la configuración.
Para elegir qué eventos enviar, asignar nombres de eventos o habilitar campos opcionales (precio de prueba, eventos históricos, atribución, atributos de usuario, token de Play Store), consulta [Configurar la integración de webhook](https://adapty.io/docs/es/set-up-webhook-integration.md).
## Constrúyelo con tu agente de programación IA \{#build-it-with-your-ai-coding-agent\}
Dale a tu agente de programación IA esta guía y la documentación de referencia en Markdown (añade `.md` a cualquier URL de página), indícale tu stack y deja que genere el handler:
- [Tipos de eventos y campos del webhook](https://adapty.io/docs/es/webhook-event-types-and-fields.md)
- [Configurar la integración de webhook](https://adapty.io/docs/es/set-up-webhook-integration.md)
Ejemplo de prompt:
```
Read these Adapty webhook docs, then write a webhook handler for my Express app:
verify the Authorization header against ADAPTY_WEBHOOK_SECRET, answer the
verification request, acknowledge events with 200, and grant or revoke access
based on event_type.
```
The agent writes the handler code, but it can't deploy your endpoint or configure the dashboard — host the endpoint yourself and set the URL and secret in **Integrations → Webhook**.
## Prueba tu webhook \{#test-your-webhook\}
Prueba en el sandbox antes de pasar a producción:
1. Configura el endpoint de sandbox y el secreto tal como se describe arriba.
2. En tu app de sandbox, realiza una compra, inicia una prueba o emite un reembolso para activar un evento.
3. Abre la sección **Last sent events** de la integración. Un evento entregado correctamente muestra el estado **Success**.
Si un evento muestra **Sending failed**, tu servidor devolvió un estado fuera del rango 200–399 — pasa el cursor sobre el estado para ver los detalles. Para ver el proceso de prueba completo, consulta [Probar la integración de webhook](https://adapty.io/docs/es/test-webhook.md).
## Límites \{#limits\}
- **Responde en menos de 10 segundos**: Si Adapty no recibe respuesta a tiempo, considera el intento como fallido y reintenta.
- **Reintentos**: Si tu código de estado está fuera del rango 200–404, Adapty reintenta con retroceso exponencial — hasta 9 reintentos en 24 horas.
- **Retraso en cancelaciones**: Los eventos de cancelación pueden tardar hasta 2 horas en llegar.
- **Una URL por entorno**: Para enviar eventos a varios servicios, apunta el webhook a tu propio backend y distribúyelos desde allí.
---
# File: server-side-api-with-ai
---
---
title: "Verificar y otorgar acceso a suscripciones desde tu backend"
description: "Usa la API de servidor de Adapty para comprobar si un usuario tiene una suscripción activa y otorgar acceso manualmente, con ayuda de un agente de codificación con IA."
---
Desde tu backend, usa la API de servidor de Adapty para comprobar si un usuario tiene una suscripción activa y para conceder acceso manualmente. Esta guía cubre las dos llamadas más comunes — `getProfile` y `grantAccessLevel` — y muestra cómo hacer que un agente de codificación con IA escriba la integración para tu stack.
:::tip
¿Usas un agente de codificación con IA? Haz clic en **Copy for LLM** debajo del título y pega toda esta página en tu agente — contiene las llamadas, los campos y los detalles que necesita.
:::
## Antes de empezar \{#before-you-start\}
- **Una clave de API secreta**: Encuéntrala en [App settings → General](https://app.adapty.io/settings/general), en el campo **Secret key**. Las claves son específicas de cada app. Guárdala en una variable de entorno (por ejemplo, `ADAPTY_SECRET_KEY`) y envíala como `Authorization: Api-Key {key}`.
- **La URL base**: Todas las solicitudes van a `https://api.adapty.io`.
- **Una forma de identificar al usuario**: Envía `adapty-customer-user-id` (tu propio ID de usuario — solo funciona si identificas a los usuarios en la app) o `adapty-profile-id` (el ID de perfil de Adapty). Son intercambiables; usa uno.
## Comprobar una suscripción \{#check-a-subscription\}
Para comprobar el estado, llama a `getProfile` con `GET` y pasa el identificador de usuario como encabezado — no hay cuerpo de solicitud.
```javascript title="check-access.js"
const res = await fetch("https://api.adapty.io/api/v2/server-side-api/profile/", {
headers: {
"Authorization": `Api-Key ${process.env.ADAPTY_SECRET_KEY}`,
"adapty-customer-user-id": userId,
},
});
const { data } = await res.json();
function hasActiveAccess(profile, accessLevelId = "premium") {
const level = profile.access_levels?.find(a => a.access_level_id === accessLevelId);
if (!level) return false;
if (level.is_in_grace_period) return true;
if (!level.expires_at) return true; // lifetime / non-expiring
return new Date(level.expires_at) > new Date(); // not expired yet
}
if (hasActiveAccess(data)) {
// unlock premium features
}
```
A diferencia del perfil del SDK, la respuesta del servidor **no tiene campo `is_active`**. Determina el estado tú mismo a partir de `access_levels[].expires_at`: `null` significa acceso de por vida, una fecha futura significa activo y una fecha pasada significa expirado. Trata `is_in_grace_period` como aún activo. Para ver todos los campos de perfil y nivel de acceso, consulta [getProfile](https://adapty.io/docs/es/api-adapty/operations/getProfile.md).
## Conceder acceso manualmente \{#grant-access-manually\}
Para desbloquear funciones de pago sin una compra —códigos promocionales, acceso para inversores o beta testers, casos de soporte— llama a `grantAccessLevel` con `POST`.
```javascript title="grant-access.js"
await fetch("https://api.adapty.io/api/v2/server-side-api/purchase/profile/grant/access-level/", {
method: "POST",
headers: {
"Authorization": `Api-Key ${process.env.ADAPTY_SECRET_KEY}`,
"adapty-customer-user-id": userId,
"Content-Type": "application/json",
},
body: JSON.stringify({ access_level_id: "premium" }), // add "expires_at" for temporary access
});
```
Dos cosas a tener en cuenta:
- **El nivel de acceso debe existir previamente** en tu dashboard (**Access levels**) — `access_level_id` es su identificador, no un nombre nuevo.
- **Las concesiones manuales no aparecen en los análisis**. Solo se entregan a tu integración de webhook y al Event Feed, por lo que los gráficos de ingresos y conversión no las reflejarán.
Para los detalles de solicitud y respuesta, consulta [grantAccessLevel](https://adapty.io/docs/es/api-adapty/operations/grantAccessLevel.md).
## Constrúyelo con tu agente de código IA \{#build-it-with-your-ai-coding-agent\}
Dale a tu agente de código IA esta guía y la especificación de la API en Markdown (añade `.md` a cualquier URL de página), indícale tu stack y deja que escriba las llamadas:
- [Especificación OpenAPI](https://adapty.io/docs/es/api-specs/adapty-api.yaml)
- [getProfile](https://adapty.io/docs/es/api-adapty/operations/getProfile.md)
- [grantAccessLevel](https://adapty.io/docs/es/api-adapty/operations/grantAccessLevel.md)
Ejemplo de prompt:
```
Using the Adapty server-side API spec, write backend functions to check whether a
user has an active "premium" access level (GET /profile/, derive status from
expires_at — there's no is_active field) and to grant it (grantAccessLevel).
Authenticate with ADAPTY_SECRET_KEY and identify users by adapty-customer-user-id.
```
The agent writes the code, but it can't run your backend or set your keys — you provide the secret key and the user identifiers.
## Límites \{#limits\}
- **Límite de velocidad**: Hasta 40.000 solicitudes por minuto por app.
- **Claves específicas por app**: Cada clave funciona para una sola app; usa la clave correspondiente para cada app.
- **Se requiere un identificador**: Cada solicitud necesita `adapty-customer-user-id` o `adapty-profile-id`.
---
# File: test-purchases-in-sandbox
---
---
title: "Pruebas en sandbox"
description: "Prueba compras en el entorno sandbox para garantizar transacciones sin problemas."
---
Una vez que hayas configurado todo en el Adapty Dashboard y en tu aplicación móvil, es momento de realizar pruebas de compras in-app.
**Nota:** ninguna de las herramientas de prueba cobra a los usuarios cuando prueban comprar un producto. La App Store no envía correos electrónicos por compras ni reembolsos realizados en los entornos de prueba.
:::note
**Las transacciones en sandbox se excluyen de todos los gráficos de análisis.** Siguen apareciendo en las páginas de perfil individuales y en el feed de eventos.
:::
:::info
Para proceder con las pruebas de compras in-app, asegúrate de que:
- Has completado las guías de [inicio rápido](quickstart) sobre integración con la store, añadir productos e integración del SDK de Adapty.
- Tu producto está marcado como [**Ready to submit**](InvalidProductIdentifiers#step-2-check-products) en App Store Connect.
:::
## Pruebas en sandbox \{#sandbox-testing\}
2. Introduce los datos del usuario de prueba. Asegúrate de definir el **Country or Region** que quieres probar, ya que afecta a la disponibilidad de productos en esa región y a la moneda de compra.
:::tip
- Si usas Gmail o iCloud, puedes reutilizar tu dirección de correo existente con [subdireccionamiento con signo más](https://www.wikihow.com/Use-Plus-Addressing-in-Gmail).
- Puedes usar una dirección de correo aleatoria que ni siquiera exista, pero asegúrate de rechazar la autenticación de dos factores (2FA) cuando inicies sesión en un dispositivo de prueba más adelante.
:::
3. Haz clic en **Create**.
### Paso 2. Activar el modo de desarrollador \{#step-2-enable-the-developer-mode\}
:::note
Omite este paso si el modo de desarrollador ya está **activado** en tu dispositivo de prueba o si **no tienes un Mac**.
:::
Necesitarás un Mac con Xcode instalado y el cable de tu dispositivo de prueba:
1. Abre Xcode en tu Mac. Si vas a probar compras in-app con TestFlight, solo necesitas tener Xcode instalado; no hace falta tener ninguna app abierta.
2. Conecta tu dispositivo de prueba al Mac con el cable.
3. Ve a **Settings > Privacy & Security > Developer Mode** en tu dispositivo de prueba y activa el **Developer Mode**.
### Paso 3. Descarga la app desde TestFlight \{#step-3-download-the-app-from-testflight\}
:::info
Este paso solo aplica si estás probando con TestFlight. Si estás compilando la app en Xcode, omite este paso.
:::
Para más información sobre cómo enviar tu app a TestFlight, consulta la [documentación de Apple](https://developer.apple.com/documentation/StoreKit/testing-in-app-purchases-with-sandbox#Prepare-for-sandbox-testing).
Antes de descargar la app de TestFlight, asegúrate de que en tu dispositivo de prueba estás conectado con tu Apple Account de producción. Luego descarga desde TestFlight la app que quieres probar.
:::danger
No abras la aplicación una vez descargada. Continúa directamente con los siguientes pasos.
Si la abriste por accidente, elimínala de tu dispositivo de prueba y descárgala de nuevo. De lo contrario, tu historial de compras podría no estar limpio y las pruebas de compras in-app producirán errores.
:::
### Paso 4. Cambia a la cuenta de prueba Sandbox \{#step-4-switch-to-sandbox-test-account\}
4. Desplázate hacia abajo hasta la sección **Sandbox Apple Account** y pulsa **Sign In**.
5. Inicia sesión con las credenciales de tu Sandbox Apple Account.
### Paso 5. Borrar el historial de compras \{#step-5-clear-purchase-history\}
Si acabas de crear una nueva cuenta de prueba de Sandbox y has cambiado a ella, puedes saltarte este paso, ya que solo aplica cuando repites pruebas con la misma cuenta de Sandbox.
1. Ve a **Settings > Developer > Sandbox Apple Account** en tu dispositivo de prueba.
2. Selecciona **Manage** en el menú emergente.
3. Ve a **Account Settings** y pulsa **Clear Purchase History**.
:::danger
Este paso es obligatorio cada vez que repitas las pruebas con la misma cuenta de prueba de Sandbox. En ese caso, también tendrás que [cerrar sesión en tu cuenta de prueba de Sandbox](#step-4-switch-to-sandbox-test-account) y volver a iniciar sesión para borrar la caché del historial de compras en el dispositivo de prueba.
:::
### Paso 6. Compilar en Xcode y ejecutar \{#step-6-build-in-xcode-and-run\}
:::info
Este paso solo aplica si estás probando con una compilación de Xcode. Si usas TestFlight, omite este paso.
:::
1. Conecta tu dispositivo de prueba al Mac.
2. Abre Xcode.
3. Haz clic en **Run** en la barra de herramientas o selecciona **Product > Run** para compilar y ejecutar la app en el dispositivo conectado.
Si la compilación es correcta, Xcode lanzará la app en tu dispositivo y abrirá una sesión de depuración en el área de debug.
Tu app ya está lista para pruebas en el dispositivo.
### Paso 7. Realiza una compra de prueba \{#step-7-make-test-purchase\}
Abre la app y realiza tu compra de prueba a través de un paywall.
Una vez hecho, consulta el artículo sobre [validación de compras de prueba](validate-test-purchases) para revisar los resultados.
### Paso 8. Sigue probando \{#step-8-keep-testing\}
Tu entorno de pruebas ya está listo. Si quieres volver a probarlo, [borra el historial de compras de la cuenta sandbox](https://developer.apple.com/help/app-store-connect/test-in-app-purchases/manage-sandbox-apple-account-settings/).
## Problemas de prueba \{#testing-issues\}
A continuación se describen los problemas más comunes que puedes encontrar al probar una app.
### Problemas con TestFlight \{#testflight-issues\}
No puedes borrar tu historial de compras **si usas TestFlight sin una cuenta de prueba de Sandbox**, lo que genera varios problemas y resultados de prueba incorrectos.
Si olvidaste accidentalmente [cambiar a la cuenta de prueba de Sandbox](#step-4-switch-to-sandbox-test-account) y abriste la app aunque sea una vez, TestFlight asocia tu historial de compras con tu cuenta de Apple de producción, lo que provoca problemas inesperados.
Para solucionarlo, sigue estos pasos:
1. Elimina la app del dispositivo de prueba.
2. Sigue los pasos para las [pruebas en Sandbox](#sandbox-testing).
:::note
Es importante no solo reinstalar la aplicación, sino también cambiar a la cuenta de prueba Sandbox, borrar el historial de compras e iniciarla con la cuenta de prueba Sandbox.
:::
### Problemas con los niveles de acceso compartidos \{#shared-access-levels-issues\}
Si repites las pruebas con la misma cuenta de prueba de Sandbox, es posible que encuentres un comportamiento inesperado con los [niveles de acceso compartidos](sharing-paid-access-between-user-accounts) para el usuario de prueba.
Para comprobar si el usuario tiene un nivel de acceso heredado, ve a [Profiles & Segments](https://app.adapty.io/profiles/users) desde el Adapty Dashboard y abre el perfil del usuario.
Si el usuario tiene un nivel de acceso heredado, sigue estos pasos para obtener resultados de prueba precisos:
1. Elimina el perfil principal.
2. Elimina la app del dispositivo de prueba.
3. [Descarga la app desde TestFlight](#step-3-download-the-app-from-testflight).
4. [Cambia a la cuenta de prueba de Sandbox](#step-4-switch-to-sandbox-test-account).
5. [Borra el historial de compras](#step-5-clear-purchase-history).
6. [Abre la app y realiza tu compra de prueba](#step-6-make-test-purchase).
:::note
Borrar el historial de compras es lo que restablece la compra en el lado del store. Eliminar el perfil principal solo borra el registro en el lado de Adapty. Para entender por qué una cuenta reutilizada mantiene el acceso y qué acciones de restablecimiento funcionan realmente, consulta [Restablecer la suscripción de un tester](#resetting-a-testers-subscription).
:::
### Actualización de la app en TestFlight \{#updating-app-in-testflight\}
Si la app de TestFlight se ha actualizado:
1. Elimina la app del dispositivo de prueba.
2. [Descarga la app desde TestFlight](#step-3-download-the-app-from-testflight).
3. [Cambia a la cuenta de prueba Sandbox](#step-4-switch-to-sandbox-test-account).
4. [Borra el historial de compras](#step-5-clear-purchase-history).
5. [Abre la app y realiza tu compra de prueba](#step-6-make-test-purchase).
## Restablecer la suscripción de un tester \{#resetting-a-testers-subscription\}
En el entorno sandbox, una compra pertenece a la **cuenta sandbox de Apple**, no al perfil de Adapty. Las acciones que realices en el perfil —eliminarlo o editar su nivel de acceso— no eliminan la compra de la cuenta del store. En el siguiente reinstalado o sincronización, el SDK vuelve a asociar la misma transacción y el tester recupera el acceso.
La siguiente tabla muestra qué cambia con cada acción de restablecimiento y qué ve el tester después.
| Acción | Perfil de Adapty | Cuenta sandbox de Apple | Acceso del tester después |
| :-------------------------------------------------------------------------------- | :------------------------------------------------------ | :---------------------- | :------------------------------------------------------------------------------------------------- |
| Eliminar el perfil en el Adapty Dashboard | Eliminado | Sin cambios | **Regresa** — al reinstalar, un nuevo perfil vuelve a enlazar la misma cadena de transacciones |
| Eliminar el perfil mediante la [API de eliminación de perfil](api-adapty/operations/deleteProfile) | Eliminado | Sin cambios | **Regresa** — igual que eliminarlo en el Dashboard |
| Añadir una fecha de expiración pasada mediante **Add access level** | Sobreescrito en la siguiente sincronización | Sin cambios | **Regresa** en la siguiente renovación — la suscripción activa vuelve a aplicar una fecha de expiración futura |
| Llamar a la [API de revocación de nivel de acceso](api-adapty/operations/revokeAccessLevel) | Expira ahora, dispara `access_level_updated` (`is_active=false`) | Sin cambios | **Regresa** en la siguiente renovación o reinstalación — no es un reinicio de sandbox fiable |
| Cancelar la suscripción en la cuenta sandbox | Sin cambio directo | Suscripción cancelada | Las renovaciones se detienen, el acceso termina cuando expira el período actual y el tester puede volver a comprar el producto |
| Iniciar sesión con una cuenta sandbox de Apple nueva | Perfil nuevo | Cuenta nueva y vacía | **Limpio** — recomendado para pruebas repetidas |
### Restablecer un tester a un estado limpio \{#reset-a-tester-to-a-clean-state\}
Para probar el flujo de compra varias veces, usa una cuenta sandbox de Apple nueva para cada prueba en lugar de restablecer el perfil. Sigue el [Paso 1](#step-1-create-sandbox-test-account-in-app-store-connect) para crear la cuenta y el [Paso 4](#step-4-switch-to-sandbox-test-account) para cambiar a ella en el dispositivo. Si reutilizas una cuenta sandbox existente, [borra su historial de compras](#step-5-clear-purchase-history) primero — eliminar el perfil de Adapty no lo borra.
### Eliminar el acceso a un tester existente \{#remove-access-from-an-existing-tester\}
Para quitar el acceso a un tester, no retrocedas la fecha de expiración ni llames a la API Revoke access level. En sandbox, la suscripción se renueva automáticamente cada pocos minutos. Cada renovación restaura una fecha de expiración futura en la misma cadena de transacciones, por lo que el acceso se recupera solo. La API Revoke access level sí dispara un evento `access_level_updated` (`is_active=false`), pero la siguiente renovación lo sobreescribe.
Para detener el acceso realmente, cancela la suscripción desde el store. En el dispositivo de prueba, ve a **Settings > Developer > Sandbox Apple Account**, selecciona **Manage** y cancela la suscripción. Los renovaciones se detienen y el acceso termina cuando expira el período actual.
### Por qué eliminar el perfil devuelve el acceso \{#why-deleting-the-profile-brings-access-back\}
Cuando un tester reinstala la app, Adapty recibe el historial de compras de la cuenta sandbox y vincula la nueva instalación a la compra existente. La compra está asociada a la cuenta del store, no al perfil que eliminaste.
- **Perfiles anónimos**: Una reinstalación sin `customer_user_id` siempre hereda el nivel de acceso de la cuenta de la store, independientemente de tu configuración de [compartición de acceso de pago](sharing-paid-access-between-user-accounts).
- **Perfiles identificados**: Si el acceso se transfiere a un nuevo `customer_user_id` depende de tu configuración de compartición de acceso de pago.
Para entender cómo Adapty enlaza estos perfiles en una cadena, consulta [Cómo funcionan los perfiles](how-profiles-work#parent-and-inheritor-profiles).
## Probar suscripciones \{#test-subscriptions\}
Al probar la app con una cuenta de prueba de sandbox, puedes configurar la tasa de renovación de la suscripción para cada tester en sandbox. Consulta más información sobre cómo editar las tasas de renovación en la [documentación oficial de Apple](https://developer.apple.com/help/app-store-connect/test-in-app-purchases/manage-sandbox-apple-account-settings).
Por defecto, las suscripciones se renuevan hasta 12 veces antes de detenerse, según el siguiente calendario:
| Duración de la suscripción | 1 semana | 1 mes | 2 meses | 3 meses | 6 meses | 1 año |
| :---------------------------------- | :--------- | :--------- | :--------- | :--------- | :--------- | :--------- |
| Velocidad de renovación | 3 minutos | 5 minutos | 10 minutos | 15 minutos | 30 minutos | 1 hora |
| Duración del reintento de cobro | 10 minutos | 10 minutos | 10 minutos | 10 minutos | 10 minutos | 10 minutos |
| Duración del período de gracia | 3 minutos | 5 minutos | 5 minutos | 5 minutos | 5 minutos | 5 minutos |
:::note
Ten en cuenta que las transacciones de prueba pueden tardar hasta 10 minutos en aparecer en el [Event feed](validate-test-purchases).
:::
Usa el sandbox para verificar que tu app y tu backend gestionan correctamente las renovaciones, los reintentos de cobro y los períodos de gracia — no para predecir los tiempos de renovación en producción. El calendario acelerado y limitado que se muestra arriba no coincide con el de producción. Para reproducir transacciones en tu servidor con fines de prueba de backend, usa la [API Set transaction](api-adapty/operations/setTransaction).
## Probar ofertas \{#test-offers\}
Para que la elegibilidad funcione correctamente al probar ofertas, es necesario eliminar todos los recibos del usuario.
La forma más fiable de probar ofertas es usar una [cuenta de prueba Sandbox](#step-1-create-sandbox-test-account-in-app-store-connect) completamente nueva. Repetir las pruebas con la misma cuenta de prueba Sandbox puede provocar comportamientos inesperados.
:::danger
Si repites las pruebas con la misma cuenta de prueba Sandbox, asegúrate de [borrar el historial de compras](#step-5-clear-purchase-history) para evitar problemas de elegibilidad.
:::
---
# File: local-sk-files
---
---
title: "Pruebas con StoreKit en Xcode"
description: "Prueba compras en el entorno sandbox para garantizar transacciones fluidas."
---
Las pruebas con StoreKit en Xcode te permiten probar compras in-app de forma local sin necesidad de configurar una cuenta sandbox.
Para este tipo de pruebas, necesitas:
1. [Crear un producto en Adapty](quickstart-products) y asignarle un **App Store product ID**.
2. En Xcode, crea un [archivo de configuración de StoreKit](https://developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode) local y añade un producto. El ID del producto debe coincidir con el **App Store product ID** en Adapty.
3. Añade el archivo de configuración de StoreKit a tu esquema de compilación y compila la app. Ejecútala en el emulador o en tu dispositivo.
## ¿Debería usar las pruebas con StoreKit en Xcode? \{#should-i-use-storekit-testing-in-xcode\}
Esta forma de probar es la más cómoda si eres desarrollador de la app y quieres probar la compilación sobre la marcha o reproducir distintos escenarios de compra usando las herramientas de Xcode.
Sin embargo, ten en cuenta que este tipo de pruebas es local, por lo que ningún cambio aparecerá en el Adapty Dashboard. Antes de lanzar tu app en producción, te recomendamos que pruebes el [trabajo con perfiles](ios-quickstart-identify) usando el [entorno sandbox](test-purchases-in-sandbox).
**Deberías** usar las pruebas con StoreKit si quieres:
- Probar la lógica de compra
- Reproducir distintos escenarios de compra con las herramientas de Xcode (por ejemplo, pago cancelado o reembolso)
- Probar usando el emulador
**No deberías** usar las pruebas con StoreKit si quieres:
- Probar la lógica relacionada con perfiles
- Verificar que tus acciones en la app aparecen en el Adapty Dashboard
- Compartir tu app con equipos que no sean de desarrollo para pruebas
## Paso 1. Crea un archivo de configuración de StoreKit \{#step-1-create-a-storekit-configuration-file\}
Para crear un archivo de configuración de StoreKit en Xcode:
1. Haz clic en **File > New > File from template**. Luego selecciona **StoreKit Configuration File** y haz clic en **Next**.
2. Ponle un nombre. Luego, dependiendo de si ya tienes los productos en App Store Connect:
- Selecciona **Sync this file with an app in App Store Connect**: para crear un archivo de configuración que contendrá todos tus productos de App Store Connect y poder probarlos localmente.
- No selecciones **Sync this file with an app in App Store Connect**: para crear un archivo de configuración vacío donde tendrás que añadir los productos manualmente.
Haz clic en **Next**.
3. No añadas tu app como destino. Continúa. Si estás trabajando con productos sincronizados desde App Store Connect, ve al [Paso 2](#step-2-add-the-configuration-file-to-the-build-scheme).
4. Si tus productos no están sincronizados desde App Store Connect, haz clic en **+** en la parte inferior izquierda y selecciona un tipo de producto.
5. Introduce un nombre para el grupo de suscripción y haz clic en **Next**.
6. Introduce un nombre de referencia. En el campo **Product ID**, introduce el **App Store product ID** de tu producto en Adapty.
7. Configura el precio, las ofertas y otros ajustes del producto en el archivo de configuración. O añade más productos.
## Paso 2. Añade el archivo de configuración al esquema de compilación \{#step-2-add-the-configuration-file-to-the-build-scheme\}
Para compilar la app usando este archivo de configuración, necesitas añadirlo a un esquema de compilación. La buena práctica es separar los esquemas de prueba y de producción, así que te sugerimos crear un nuevo esquema para pruebas:
1. En la parte superior, haz clic en el nombre de tu app y selecciona **New scheme**.
2. Introduce un nombre para el esquema y haz clic en **OK**.
3. Haz clic de nuevo en el nombre de la app y selecciona **Edit scheme**. En **StoreKit configuration**, selecciona tu archivo de configuración local para que se use al compilar.
## Paso 3. Compila y prueba \{#step-3-build--test\}
Ahora puedes compilar la app y probar compras in-app sin conectarte al backend de App Store. Puedes realizar compras y obtener niveles de acceso de forma local. Estos cambios no se reflejarán en el Adapty Dashboard, pero aun así puedes probar el desbloqueo de funciones de pago localmente.
[Lee más](https://developer.apple.com/documentation/xcode/testing-in-app-purchases-with-storekit-transaction-manager-in-code) sobre otras funciones disponibles con las pruebas de StoreKit en Xcode.
---
# File: testing-on-android
---
---
title: "Probar compras in-app en Google Play Store"
description: "Prueba compras de suscripción en Android usando Adapty."
---
Probar las compras in-app (IAPs) en tu app Android es un paso fundamental antes de publicarla. Las pruebas en sandbox son una forma segura y eficiente de probar IAPs sin cobrar dinero real a tus usuarios. En esta guía, te explicamos el proceso de pruebas en sandbox de IAPs en Google Play Store para Android.
:::note
**Las transacciones en sandbox se excluyen de todos los gráficos de análisis.** Siguen apareciendo en las páginas de perfil individuales y en el feed de eventos.
:::
## Entorno de pruebas \{#testing-environment\}
Para garantizar el rendimiento óptimo de tu app Android, se recomienda probarla en un dispositivo real en lugar de un emulador. Aunque hemos probado con éxito en emuladores, Google recomienda usar un dispositivo real.
Si decides usar un emulador, asegúrate de que tenga Google Play instalado. Esto ayudará a garantizar que tu app funcione correctamente.
## 1. Configura una cuenta de prueba para probar la app \{#1-set-up-test-account-for-app-testing\}
Para facilitar las pruebas en fases posteriores del desarrollo, necesitarás configurar un usuario de prueba para las pruebas de compras in-app. Este usuario será la primera cuenta con la que inicies sesión en tu dispositivo Android de pruebas.
Ten en cuenta que la cuenta principal de un dispositivo Android solo puede cambiarse realizando un restablecimiento de fábrica, lo que borra todos tus datos. Por eso es importante configurar correctamente tu cuenta de usuario de prueba para evitar tener que hacer un restablecimiento.
:::important
La forma de configurar una cuenta de prueba dependerá del dispositivo que uses:
- Si tienes un dispositivo dedicado para pruebas, crea una **cuenta de prueba separada (una nueva cuenta de Gmail)**.
- Si no tienes un dispositivo dedicado para pruebas, puedes usar tu propia **cuenta personal** y activar temporalmente las **License testing** para ella.
- Si no tienes ningún dispositivo Android, puedes **crear una cuenta de prueba separada y usarla con un emulador**. Sin embargo, este enfoque no se recomienda ya que no permite detectar todos los posibles problemas de dispositivos reales.
:::
## 2. Activa License testing \{#2-enable-license-testing\}
Una vez que hayas configurado una cuenta de usuario de prueba, deberás configurar las pruebas de licencias para tu app. Para hacerlo, sigue estos pasos:
1. En la barra lateral de Google Play Console, ve a **Settings** y selecciona **License testing** en la sección **Monetization**.
2. Selecciona una lista de probadores de licencias existente o crea una nueva.
3. Añade la cuenta que usarás para las pruebas a la lista y guarda los cambios. Si los miembros de tu equipo también necesitan probar la app, puedes añadir sus correos electrónicos a la lista para que todo el grupo tenga acceso.
## 3. Crea una pista cerrada y añade la cuenta de prueba \{#3-create-closed-track-and-add-test-account-to-it\}
Para empezar a probar, necesitas publicar una versión firmada de tu app en una pista cerrada:
1. Abre tu app y selecciona **Test and release > Testing > Closed testing** en el menú. Allí, haz clic en **Create track**.
2. Introduce el nombre de la pista de pruebas cerrada y haz clic en **Create track**.
3. Añade una lista de probadores a la pista.
4. En la sección **How testers join your test**, copia el enlace y envíalo al dispositivo que ha iniciado sesión con la cuenta de prueba. Abre el enlace en tu dispositivo de pruebas para convertir al usuario en probador.
:::warning
Ten en cuenta lo siguiente para garantizar que las pruebas funcionen correctamente:
- Abrir la URL de participación marca tu cuenta de Play para pruebas. Si no completas este paso, los productos no se cargarán.
- Con frecuencia, los desarrolladores usan un ID de aplicación diferente para sus versiones de prueba. Esto puede causarte problemas, ya que Google Play Services utiliza el ID de aplicación para encontrar tus compras in-app.
- Hay casos en los que un usuario de prueba puede estar autorizado a comprar consumibles pero no suscripciones si el dispositivo de prueba no tiene PIN. Esto puede manifestarse con un críptico mensaje de "Something went wrong". Asegúrate de que el dispositivo de prueba tenga un PIN y de que esté conectado a Google Play Store.
:::
## 4. Sube un APK firmado a la pista cerrada \{#4-upload-a-signed-apk-to-the-closed-track\}
Genera un APK firmado o usa Android App Bundle para subir un APK firmado a la pista cerrada que acabas de crear. Ni siquiera necesitas lanzar el release. Solo sube el APK. Puedes encontrar más información al respecto en [este](https://support.google.com/googleplay/android-developer/answer/9859348?visit_id=638929100639477968-3849460621&rd=1) artículo de soporte.
:::important
Si tu app es nueva, es posible que tengas que hacerla disponible en tu país o región. Para ello, ve a **Testing > Closed testing**, haz clic en tu pista de pruebas y ve a **Countries/regions** para añadir los países y regiones deseados.
:::
## 5. Prueba las compras in-app \{#5-test-in-app-purchases\}
Después de subir el APK, espera unos minutos para que se procese el release. Luego, abre tu dispositivo de pruebas e inicia sesión con la cuenta de correo electrónico que añadiste a la lista de probadores. A continuación, podrás probar las compras in-app como lo harías en una app de producción.
## Más información \{#read-more\}
Consulta los siguientes recursos para saber más sobre cómo probar compras in-app en apps Android:
- [Períodos de renovación en sandbox](https://developer.android.com/google/play/billing/test#subs)
- [Probar compras únicas](https://developer.android.com/google/play/billing/test#one-time)
---
# File: validate-test-purchases
---
---
title: "Validar compras de prueba"
description: "Valida las compras de prueba en Adapty para garantizar transacciones sin problemas."
---
Antes de publicar tu app en producción, es fundamental probar las compras in-app a fondo. Consulta nuestros artículos [Probar compras in-app en Apple App Store](test-purchases-in-sandbox) y [Probar compras in-app en Google Play Store](testing-on-android) para obtener una guía detallada sobre cómo hacerlo. Una vez que empieces a probar, necesitas verificar que las compras de prueba se hayan completado correctamente.
Cada vez que realices una compra de prueba en tu dispositivo móvil, comprueba la transacción correspondiente en el [**Event Feed**](https://app.adapty.io/event-feed) del Adapty Dashboard. Si la compra no aparece en el **Event Feed**, significa que Adapty no la está registrando.
## La compra de prueba es exitosa \{#test-purchase-is-successful\}
Si la compra de prueba se realiza correctamente, el evento de transacción aparecerá en el **Event Feed**:
Si las transacciones funcionan como se espera, pasa al [Release checklist](release-checklist) y continúa con la publicación de la app.
## La compra de prueba no es exitosa \{#test-purchase-is-not-successful\}
Si no ves ningún evento de transacción en 10 minutos o encuentras un error en la app, consulta el artículo de [Solución de problemas](troubleshooting-test-purchases) y los artículos sobre manejo de errores [para iOS](ios-sdk-error-handling), [para Android](android-sdk-error-handling), [para React Native](react-native-handle-errors), [para Flutter](error-handling-on-flutter-react-native-unity), [para Unity](unity-handle-errors) y [Kotlin Multiplatform](kmp-handle-errors) para encontrar posibles soluciones.
---
# File: troubleshooting-test-purchases
---
---
title: "Solución de problemas con compras de prueba"
description: "Soluciona problemas con compras de prueba en Adapty y resuelve incidencias comunes en transacciones in-app."
---
Si encuentras problemas con las transacciones, asegúrate primero de haber completado todos los pasos del [checklist de lanzamiento](release-checklist). Si ya los completaste y sigues teniendo problemas, sigue las indicaciones a continuación para resolverlos:
## Se devuelve un error en la app móvil \{#an-error-is-returned-in-the-mobile-app\}
Consulta la lista de errores de tu plataforma: [para iOS](ios-sdk-error-handling), [para Android](android-sdk-error-handling), [para React Native](react-native-troubleshoot-purchases), [Flutter](error-handling-on-flutter-react-native-unity) y [Unity](unity-troubleshoot-purchases), y sigue nuestras recomendaciones para resolver el problema.
## La transacción no aparece en el Event Feed aunque no se devuelve ningún error en la app móvil \{#transaction-is-absent-from-the-event-feed-although-no-error-is-returned-in-the-mobile-app\}
Para resolver este problema, verifica lo siguiente:
1. **Para iOS**: Asegúrate de usar un dispositivo real y no un simulador.
2. Asegúrate de que el `Bundle ID`/`Package name` de tu app coincida con el que figura en [**App settings**](https://app.adapty.io/settings/general).
3. Asegúrate de que el `PUBLIC_SDK_KEY` de tu app coincida con la **Public SDK key** del Adapty Dashboard: [**App settings** -> pestaña **General** -> subsección **API keys**](https://app.adapty.io/settings/general).
4. Asegúrate de estar usando una cuenta sandbox y no un [archivo de configuración local de StoreKit](local-sk-files). Si antes usaste un archivo de configuración local de StoreKit para pruebas, verifica que no lo estés usando en la compilación actual.
## No hay ningún evento en mi perfil de prueba \{#no-event-is-present-in-my-testing-profile\}
Esto es un comportamiento normal. En Adapty se crea automáticamente un nuevo registro de perfil de usuario cuando:
- Un usuario ejecuta tu app por primera vez
- Un usuario cierra sesión en tu app
**Por qué ocurre:** Todas las transacciones y eventos están vinculados al perfil que generó la primera transacción. Esto mantiene todo el historial de transacciones (pruebas, compras, renovaciones) asociado al mismo perfil.
**Lo que verás:** Puede que aparezcan nuevos registros de perfil (llamados "perfiles no originales") sin eventos, pero conservarán los niveles de acceso. Es posible que veas eventos `access_level_updated`. Esto es un comportamiento esperado.
**Para pruebas:** Para evitar la creación de múltiples perfiles, crea una nueva cuenta de prueba (Sandbox Apple ID) cada vez que reinstales la app.
Para más detalles, consulta [Creación de perfiles](how-profiles-work#profile-creation).
A continuación se muestra un ejemplo de perfil no original. Observa la ausencia de eventos en **User history** y la presencia de un nivel de acceso.
## Los precios no reflejan los precios reales configurados en App Store Connect \{#prices-do-not-reflect-the-actual-prices-set-in-app-store-connect\}
Tanto en Sandbox como en TestFlight, que usa el entorno sandbox para las compras in-app, lo importante es verificar que el flujo de compra funcione correctamente, no que los precios sean exactos. Cabe destacar que la API de Apple puede proporcionar datos inexactos en ocasiones, especialmente cuando los dispositivos o cuentas tienen distintas regiones configuradas. Como los precios provienen directamente del Store y el backend de Adapty no afecta en ningún modo a los precios de compra, puedes ignorar cualquier inexactitud en los precios durante las pruebas de compras a través de Adapty.
Por tanto, prioriza la prueba del flujo de compra en sí sobre la exactitud de los precios para asegurarte de que funciona como se espera.
## La hora de la transacción en el Event Feed es incorrecta \{#the-transaction-time-in-the-event-feed-is-incorrect\}
El **Event Feed** utiliza la zona horaria configurada en **App Settings**. Para alinear la zona horaria de los eventos con tu hora local, ajusta la **Reporting timezone** en [**App settings** -> pestaña **General**](https://app.adapty.io/settings/general).
## Los paywalls y los productos tardan mucho en cargarse \{#paywalls-and-products-take-a-long-time-to-load\}
Este problema puede ocurrir si tu cuenta de prueba tiene un historial de transacciones muy largo. Te recomendamos encarecidamente crear una nueva cuenta de prueba cada vez, tal como se describe en la sección [Crear una cuenta de prueba en Sandbox (Sandbox Apple ID) en App Store Connect](test-purchases-in-sandbox#step-1-create-sandbox-test-account-in-app-store-connect).
Si no puedes crear una cuenta nueva, puedes borrar el historial de transacciones de tu cuenta actual siguiendo estos pasos en tu dispositivo iOS:
1. Abre **Configuración** y toca **App Store**.
2. Toca tu **Sandbox Apple ID**.
3. En el popup, selecciona **Manage**.
4. En la página **Account Settings**, toca **Clear Purchase History**.
Para más detalles, consulta la [documentación para desarrolladores de Apple](https://developer.apple.com/documentation/storekit/testing-in-app-purchases-with-sandbox).
---
# File: test-devices
---
---
title: "Dispositivos de prueba"
description: "Aprende a gestionar los dispositivos de prueba en Adapty para un testing eficiente."
---
Para hacer pruebas, puedes marcar tu dispositivo como dispositivo de prueba, lo que desactiva el caché y garantiza que los cambios se reflejen de inmediato.
:::note
Los dispositivos de prueba están disponibles a partir de las siguientes versiones del SDK:
- iOS: 2.11.1
- Android: 2.11.3
- React Native: 2.11.1
La compatibilidad con Flutter y Unity se añadirá más adelante.
:::
## Marca tu dispositivo como dispositivo de prueba \{#mark-your-device-as-test\}
1. Abre **[App settings](https://app.adapty.io/settings/general)** en el Adapty Dashboard.
2. Desplázate hacia abajo hasta la sección **Test devices** en la pestaña **General**.
3. Haz clic en el botón **Add test device**.
4. En la ventana **Add test device**, introduce:
| Campo | Descripción |
|:-----------------------------------------| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Test device name** | Nombre del dispositivo o dispositivos de prueba para tu referencia. |
| **ID used to identify this test device** | Elige el tipo de identificador que usarás para identificar el dispositivo o dispositivos de prueba. Consulta nuestras recomendaciones en la sección [Qué identificador deberías usar](test-devices#which-identifier-you-should-use) para elegir la mejor opción. |
| **ID value** | Introduce el valor del identificador. |
5. Recuerda hacer clic en el botón **Add test device** para guardar los cambios.
## Qué identificador deberías usar \{#which-identifier-you-should-use\}
Para identificar un dispositivo puedes usar varios identificadores. Recomendamos los siguientes:
- **Customer User ID** tanto para dispositivos iOS como Android si Un identificador único que tú asignas para identificar a tus usuarios en tu sistema. Puede ser el correo electrónico del usuario, tu ID interno o cualquier otra cadena de texto. Para usar esta opción, debes
Es la mejor opción para identificar un dispositivo de prueba, especialmente si usas varios dispositivos para la misma cuenta. Todos los dispositivos con esa cuenta se considerarán dispositivos de prueba.
| | Adapty profile ID |Un identificador único para el [perfil de usuario](profiles-crm) en Adapty.
Úsalo si no puedes usar el Customer User ID, el IDFA para iOS ni el Advertising ID para Android. Ten en cuenta que el Adapty Profile ID puede cambiar si reinstalar la app o vuelves a iniciar sesión.
| #### Cómo obtener el Customer User ID y el Adapty profile ID \{#how-to-obtain-customer-user-id-and-adapty-profile-id\} Ambos identificadores se pueden obtener en los detalles del **Profile** en el Adapty Dashboard: 1. Busca el perfil del usuario en la pestaña [**Adapty Profiles** -> **Event feed**](https://app.adapty.io/event-feed). :::note Para encontrar el perfil exacto, realiza un tipo de transacción poco frecuente. Cuando la transacción aparezca en el [**Event Feed**](https://app.adapty.io/event-feed), podrás identificarla fácilmente. ::: 2. Copia los valores de los campos **Customer user ID** y **Adapty ID** en los detalles del perfil:
### Identificadores de Apple \{#apple-identifiers\}
| Identificador | Uso |
|----------|-----|
| IDFA | El Identifier for Advertisers (IDFA) es un identificador único de dispositivo que Apple asigna al dispositivo del usuario.
Es ideal para dispositivos iOS, ya que no cambia por sí solo, aunque puedes restablecerlo manualmente.
**Nota**: Desde la introducción de iOS 14.5, los anunciantes deben solicitar el consentimiento del usuario para acceder al IDFA. Asegúrate de pedirlo en tu app y de haberlo concedido en tu dispositivo de prueba.
| | IDFV | El Identifier for Vendors (IDFV) es un identificador alfanumérico único que Apple asigna a todas las apps de un mismo dispositivo pertenecientes al mismo editor o proveedor. Puede cambiar si reinstalar o actualizas tu app. | #### Cómo obtener el IDFA \{#how-to-obtain-the-idfa\} Apple no proporciona el IDFA por defecto. Obtenlo a través de la atribución del perfil en el Adapty Dashboard: 1. Busca el perfil del usuario en la pestaña [**Adapty Profiles** -> **Event feed**](https://app.adapty.io/event-feed). :::note Para encontrar el perfil exacto, realiza un tipo de transacción poco frecuente. Cuando la transacción aparezca en el [**Event Feed**](https://app.adapty.io/event-feed), podrás identificarla fácilmente. ::: 2. Abre los detalles del perfil y copia el valor del campo **IDFA** en la sección **Attributes**:
También puedes [buscar en el App Store una app que te muestre tu IDFA](https://www.apple.com/us/search/idfa?src=globalnav).
#### Cómo obtener el Identifier for Vendors (IDFV) \{#how-to-obtain-the-identifier-for-vendors-idfv\}
Para obtener el IDFV, pide a tu desarrollador que lo solicite usando el siguiente método en tu app y que muestre el identificador recibido en los logs o en el panel de depuración.
```swift showLineNumbers title="Swift"
UIDevice.current.identifierForVendor
```
### Identificadores de Google \{#google-identifiers\}
| Identificador | Uso |
|----------|-----|
| Advertising ID | El Advertising ID es un identificador único de dispositivo que Google asigna al dispositivo del usuario.
Es ideal para dispositivos Android, ya que no cambia por sí solo, aunque puedes restablecerlo manualmente.
**Nota**: Para usarlo, desactiva la opción **Opt out of Ads Personalization** en la configuración de **Ads** si usas Android 12 o superior.
| | Android ID | El Android ID es un identificador único para cada combinación de clave de firma de la app, usuario y dispositivo. Está disponible en Android 8.0 y versiones superiores. | #### Cómo obtener el Advertising ID \{#how-to-obtain-advertising-id\} Para encontrar el Advertising ID de tu dispositivo: 1. Abre la app **Settings** en tu dispositivo Android. 2. Toca **Google**. 3. Selecciona **Ads** en **Services**. Tu Advertising ID aparecerá en la parte inferior de la pantalla. #### Cómo obtener el Android ID \{#how-to-obtain-android-id\} Para obtener el Android ID, pide a tu desarrollador que solicite el [ANDROID_ID](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID) usando el siguiente método en tu app y que muestre el identificador recibido en los logs o en el panel de depuración. ```kotlin showLineNumbers title="Kotlin/Java" android.provider.Settings.Secure.getString(contentResolver, android.provider.Settings.Secure.ANDROID_ID); ``` --- # File: release-checklist --- --- title: "Lista de verificación para el lanzamiento" description: "Sigue la lista de verificación de Adapty para garantizar un proceso de actualización de tu app sin problemas." --- ¡Nos alegra que hayas elegido Adapty! Esperamos que la implementación haya ido bien. Esta guía te llevará paso a paso para asegurarte de que tu app esté lista para publicarse en los stores y de que el flujo de monetización funcione correctamente. ## Elementos esenciales antes del lanzamiento \{#pre-flight-essentials\} Lo que necesitas antes de empezar la validación: - Un dispositivo real con una cuenta sandbox - Acceso al Adapty Dashboard - Acceso a App Store Connect / Google Play Console :::note Aunque las compras sandbox pueden ejecutarse en simuladores, necesitas dispositivos reales para probar todos los flujos, incluidos los diálogos de pago y las solicitudes biométricas. ::: ## Validaciones universales \{#universal-validations\} - [ ] **Conexión con el store**: Asegúrate de haber conectado Adapty a App Store y/o Google Play: - [ ] [App Store](initial_ios) - [ ] [Google Play](initial-android) - [ ] **Entrega de eventos de suscripción**: Confirma que las notificaciones del servidor están configuradas: - [ ] [Notificaciones del servidor de App Store](enable-app-store-server-notifications) - [ ] [Notificaciones en tiempo real para desarrolladores (RTDN)](enable-real-time-developer-notifications-rtdn) - [ ] **Identificación de perfiles**: Valida la lógica de identificación de usuarios y asegúrate de que las compras se asocien al perfil correcto: - [ ] [Comprueba que la lógica de identificación en el código de tu app coincide con tu caso de uso](ios-quickstart-identify) - [ ] [Asegúrate de entender la lógica de padre/heredero para compartir el acceso de pago entre perfiles de usuario](sharing-paid-access-between-user-accounts) - [ ] **Ofertas**: Si tienes ofertas promocionales de App Store en la app, asegúrate de haber [añadido tu clave de compra in-app](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers) tanto en el campo principal como en la sección **App Store promotional offers**. - [ ] **Recopilación de datos**: Garantiza el cumplimiento de la privacidad: - [ ] Si necesitas cumplir con normativas de privacidad como GDPR o CCPA, o tu app está destinada a niños, controla si [habilitas la recopilación y el uso compartido del IDFA e IP](sdk-installation-ios#data-policies). - [ ] Si tu app usa AppTrackingTransparency, asegúrate de [enviar el estado de autorización a Adapty](ios-deal-with-att). - [ ] **Etiquetas de privacidad**: [Más información](apple-app-privacy) sobre los datos que recopila Adapty y qué indicadores tendrás que configurar para la revisión. ## Validación de compras \{#purchase-validations\} :::tip ¿Tienes preguntas o estás teniendo algún problema? Consulta nuestro [foro de soporte](https://adapty.featurebase.app/) donde encontrarás respuestas a preguntas frecuentes o podrás plantear las tuyas. ¡Nuestro equipo y la comunidad están aquí para ayudarte! ::: Antes de publicar tu app, asegúrate de que las compras funcionan correctamente y de que tu paywall está listo para la revisión de la store. La forma de validar las compras in-app depende de cómo las hayas implementado: - Muestras un paywall creado en el Adapty Paywall Builder - Has implementado tu propio paywall y usas el método `makePurchase` dentro de él para gestionar las compras - Usas Adapty en modo observador (ya sea con el Adapty Paywall Builder o con tu paywall personalizado)
2. Selecciona **Product** > **Archive** en la barra de menú superior.
3. Espera a que finalice el proceso de archivado. La ventana **Organizer** se abre automáticamente. Selecciona tu archivo y haz clic en **Distribute App**.
4. Elige **App Store Connect** como método de distribución. Sigue los pasos para completar la subida.
:::note
La subida puede fallar si faltan recursos obligatorios, como el icono de la app o la pantalla de inicio. Consulta el registro de errores de Xcode para más detalles.
:::
### Paso 2. Comprueba el build en App Store Connect \{#step-2-check-the-build-in-app-store-connect\}
1. Ve a [App Store Connect](https://appstoreconnect.apple.com) y abre tu app.
2. Desplázate hasta la sección **Build**. Asegúrate de que el build que acabas de subir aparece ahí.
:::note
Puede tardar unos minutos en aparecer el build en App Store Connect tras la subida.
:::
## Envía tu app y productos a revisión \{#submit-your-app-and-products-for-review\}
Una vez que el build aparezca en la sección **Build**, adjunta tus suscripciones in-app y envía la app para revisión de Apple.
### Paso 1. Adjunta los productos al envío \{#step-1-attach-products-to-the-submission\}
Cada suscripción debe tener el estado **Ready to Submit** en App Store Connect antes de poder adjuntarla. Si una suscripción está en borrador o le falta información, no aparecerá en la lista.
1. En la misma página, desplázate hasta la sección **In-App Purchases and Subscriptions**.
2. Haz clic en **Select in-app purchases or subscriptions**.
3. Selecciona todos los productos que quieras incluir en este envío y haz clic en **Done**.
### Paso 2. Envía para revisión \{#step-2-submit-for-review\}
1. Completa todos los campos obligatorios de la página (descripción, capturas de pantalla, palabras clave, etc.).
2. En la sección **App Store Version Release**, selecciona si quieres publicar tu app automáticamente, manualmente o de forma programada tras su aprobación.
3. Haz clic en **Add for Review** y luego en **Submit to App Review**.
Apple revisa las apps en un plazo de 1 a 2 días, aunque los tiempos pueden variar.
## Verifica tu app en producción \{#verify-your-app-in-production\}
Tras la aprobación de Apple:
1. Realiza una compra real (o espera a que tu primer usuario compre).
2. Abre el [**Event Feed**](https://app.adapty.io/event-feed) en el Adapty Dashboard y confirma que aparecen los eventos de transacciones en producción.
3. Comprueba que los eventos de suscripción (renovaciones, cancelaciones) llegan correctamente; esto depende de que las [notificaciones del servidor de App Store](enable-app-store-server-notifications) estén configuradas.
Si los eventos de producción no aparecen, verifica la [configuración de tu conexión con App Store](app-store-connection-configuration).
## Próximos pasos \{#next-steps\}
Tu app ya está en producción. Empieza a hacer crecer tus ingresos por suscripción:
- **[Pruebas A/B](ab-tests)**: Experimenta con distintos paywalls para encontrar el que mejor convierte.
- **[Analíticas](charts)**: Monitoriza métricas de suscripción como MRR, churn y conversión.
- **Integraciones**: Envía eventos de suscripción a plataformas de [analíticas](analytics-integration) y de [atribución](attribution-integration).
---
# File: general
---
---
title: "Configuración de la app"
description: "Explora la configuración general de Adapty para un uso sin complicaciones."
---
Puedes navegar a la pestaña General de la página App Settings para gestionar el comportamiento, la apariencia y el reparto de ingresos de tu app. Aquí puedes personalizar el nombre e icono de tu app, gestionar las claves del SDK y la API de Adapty, configurar tu estado en el Small Business Program y elegir la zona horaria para los análisis y gráficos de tu app.
## 1. Detalles de la app \{#1-app-details\}
Elige un nombre e icono únicos que representen tu app en la interfaz de Adapty. Ten en cuenta que el nombre y el icono de la app no afectarán al nombre ni al icono en el App Store o Google Play. Además, asegúrate de seleccionar una categoría de app adecuada que refleje con precisión el propósito y el contenido de tu app. Esto ayudará a los usuarios a descubrirla y garantizará que aparezca en las categorías correctas de la store.
## 2\. Miembro del Small Business Program y tarifa de servicio reducida \{#2-member-of-small-business-program-and-reduced-service-fee\}
Si tu organización está inscrita en el [Small Business Program](app-store-small-business-program) de Apple o en el programa de [tarifa de servicio reducida](google-reduced-service-fee) de Google, tus apps están sujetas a una comisión reducida de la store.
Notifica a Adapty si tu app está inscrita en un programa de comisión reducida. Para garantizar cálculos correctos, especifica el estado de estos programas en la sección "Reduced Store Fee".
La configuración de tarifa reducida solo se aplica a las transacciones futuras. Cambia tu estado **antes** de que entre en vigor y Adapty ajustará la tasa de comisión.
:::warning
* Si extiendes tu participación en un programa de tarifa reducida, **añade un período de elegibilidad adicional**.
* Si pierdes la membresía en el programa, **cambia la fecha de vencimiento** de tu período de elegibilidad actual.
:::
Los siguientes artículos profundizan en este tema:
* [App Store Small Business Program](app-store-small-business-program)
* [Google Reduced Service Fee](google-reduced-service-fee)
## 3\. Zona horaria de informes \{#3-reporting-timezone\}
Elige la zona horaria que corresponda a tu ubicación o a la zona donde los análisis y gráficos de tu app sean más relevantes. Recomendamos usar la misma zona horaria que tu cuenta de App Store Connect o Google Play Console para mantener la coherencia. Ten en cuenta que esta configuración de zona horaria no afecta a las integraciones de terceros en el sistema de Adapty, que utilizan la zona horaria UTC.
Puedes acceder a la configuración de zona horaria en la sección "Reported timezone" de la pestaña General en la página App Settings. También puedes aplicar la misma zona horaria a todas las apps de tu cuenta de Adapty marcando la casilla correspondiente.
## 4\. Definición de instalaciones para análisis \{#4-installs-definition-for-analytics\}
Elige qué se considera un nuevo evento de instalación en los análisis:
| Base | Descripción |
|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Nuevos device_ids | (Recomendado) Cada instalación de la app desde la store en un dispositivo se cuenta como una nueva instalación. Esto incluye tanto las instalaciones por primera vez como las reinstalaciones.
Las instalaciones se cuentan por ID de dispositivo y no se ven afectadas por la autenticación del usuario. Crear un perfil (al activar el SDK o al cerrar sesión), iniciar sesión o actualizar la app no genera eventos de instalación adicionales.
Por ejemplo, si la misma app está instalada en 5 dispositivos diferentes, verás 5 instalaciones en los análisis.
| | Nuevos customer_user_ids |Esta opción está pensada para apps que
Para los usuarios con sesión iniciada, solo la primera instalación asociada a un customer user ID se cuenta como instalación. Las instalaciones en dispositivos adicionales no se contabilizan como nuevas instalaciones.
Los usuarios anónimos (usuarios que no han iniciado sesión) no se contabilizan en los análisis.
Reinstalar la app o volver a iniciar sesión no crea instalaciones adicionales.
Las stores y las plataformas de atribución (como App Store Connect, Google Play Console y AppsFlyer) utilizan un enfoque basado en dispositivos para contar instalaciones. Si cuentas instalaciones por customer user IDs en Adapty, los números pueden diferir de los de estos servicios externos.
⚠️ Si no identificas usuarios en Adapty, no se contabilizará ninguna instalación con esta opción activada.
| | Nuevos perfiles en Adapty | (Heredado) Cada instalación, reinstalación de la app y los perfiles anónimos creados durante los cierres de sesión se cuentan como nuevas instalaciones. | Ten en cuenta que esta opción solo afecta a la página [**Analytics**](https://app.adapty.io/analytics) y no tiene impacto en la página [**Overview**](https://app.adapty.io/overview), donde puedes configurar la vista por separado. ## 5. Lógica de aumento de precio en el App Store \{#5-app-store-price-increase-logic\} Para mantener datos precisos y evitar discrepancias entre los análisis de Adapty y los resultados de App Store Connect, es importante seleccionar la opción adecuada al ajustar las configuraciones relacionadas con los aumentos de precio en App Store Connect. Así puedes elegir la lógica que se aplicará a los aumentos de precio de las suscripciones en Adapty:
- **El precio de la suscripción para los usuarios existentes se mantiene:** Al seleccionar esta opción, el precio actual se conservará para tus suscriptores existentes, aunque realices cambios en el precio en App Store Connect. Esto significa que los suscriptores existentes seguirán siendo facturados al precio original de su suscripción.
- **Cuando el precio de la suscripción cambia en App Store Connect, también cambia para los suscriptores existentes:** Si eliges esta opción, cualquier cambio de precio realizado en App Store Connect se aplicará también a tus suscriptores existentes. Esto significa que los suscriptores existentes serán cobrados al nuevo precio que refleja la actualización establecida en App Store Connect.
:::warning
Es importante tener en cuenta que la opción seleccionada no solo afecta a los análisis en Adapty, sino que también impacta en las integraciones y en el comportamiento general del procesamiento de transacciones.
:::
Asegúrate de seleccionar la opción adecuada que se alinee con tu enfoque deseado para gestionar los precios de las suscripciones para los suscriptores existentes. Esto ayudará a mantener datos precisos y la sincronización entre los análisis de Adapty y los resultados obtenidos de App Store Connect.
## 6. Compartir el acceso de pago entre cuentas de usuario \{#6-sharing-paid-access-between-user-accounts\}
:::link
Artículo principal: [Compartir el acceso de pago entre cuentas de usuario](sharing-paid-access-between-user-accounts)
:::
La configuración **Sharing paid access between user accounts** determina qué hace Adapty cuando más de un [perfil de usuario](identifying-users) intenta acceder a la misma compra. Puedes especificar una configuración de compartición de acceso independiente para el [entorno sandbox](test-purchases-in-sandbox).
**Activado (predeterminado)**
Los usuarios identificados (aquellos con un [Customer User ID](identifying-users#set-customer-user-id-on-configuration)) pueden compartir el mismo [nivel de acceso](access-level) proporcionado por Adapty si su dispositivo está conectado al mismo Apple/Google ID. Esto es útil cuando un usuario reinstala la app e inicia sesión con un correo diferente: seguirá teniendo acceso a su compra anterior. Con esta opción, varios usuarios identificados pueden compartir el mismo nivel de acceso.
Aunque el nivel de acceso se comparte, todas las transacciones pasadas y futuras se registran como eventos en el Customer User ID original para mantener una analítica coherente y conservar un historial completo de transacciones — incluidos períodos de prueba, compras de suscripciones, renovaciones y más, vinculadas al mismo perfil.
**Transferir acceso al nuevo usuario**
Los usuarios identificados pueden seguir accediendo al [nivel de acceso](access-level) proporcionado por Adapty, incluso si inician sesión con un [Customer User ID](identifying-users#set-customer-user-id-on-configuration) diferente o reinstalan la app, siempre que el dispositivo esté conectado al mismo Apple/Google ID.
A diferencia de la opción anterior, Adapty transfiere la compra entre usuarios identificados. Esto garantiza que el contenido adquirido esté disponible, pero solo un usuario puede tener acceso a la vez. Por ejemplo, si UserA compra una suscripción y UserB inicia sesión en el mismo dispositivo y restaura las transacciones, UserB obtendrá acceso a la suscripción y se le revocará a UserA.
Si uno de los usuarios (ya sea el nuevo o el antiguo) no está identificado, el nivel de acceso seguirá compartiéndose entre esos perfiles en Adapty.
Aunque el nivel de acceso se transfiere, todas las transacciones pasadas y futuras se registran como eventos en el Customer User ID original para mantener una analítica coherente y conservar un historial completo de transacciones — incluidos períodos de prueba, compras de suscripciones, renovaciones y más, vinculadas al mismo perfil.
Tras activar **Transferir acceso al nuevo usuario**, los niveles de acceso no se transferirán entre perfiles de forma inmediata. El proceso de transferencia para cada nivel de acceso específico solo se activa cuando Adapty recibe un evento del store, como una renovación de suscripción, una restauración o al validar una transacción.
**Desactivado**
El primer perfil de usuario identificado que obtenga un nivel de acceso lo conservará de forma permanente. Esta es la mejor opción si tu lógica de negocio requiere que las compras estén vinculadas a un único Customer User ID.
Ten en cuenta que los niveles de acceso siguen compartiéndose entre usuarios anónimos.
Puedes "desvincular" una compra [eliminando el perfil del usuario propietario](https://adapty.io/docs/es/api-adapty/operations/deleteProfile). Tras la eliminación, el nivel de acceso queda disponible para el primer perfil de usuario que lo reclame, ya sea anónimo o identificado.
Desactivar el uso compartido solo afecta a los nuevos usuarios. Las suscripciones que ya se comparten entre usuarios seguirán compartiéndose aunque se desactive esta opción.
:::warning
Apple y Google exigen que las compras in-app se compartan o transfieran entre usuarios porque se basan en el Apple/Google ID para asociar la compra. Sin el uso compartido, restaurar las compras podría no funcionar en reinstalaciones posteriores.
Desactivar el uso compartido puede impedir que los usuarios recuperen el acceso después de iniciar sesión.
Recomendamos desactivar el uso compartido solo si tus usuarios **están obligados a iniciar sesión** antes de realizar una compra. De lo contrario, un usuario identificado podría comprar una suscripción, iniciar sesión en otra cuenta y perder el acceso de forma permanente.
:::
### ¿Qué opción debo elegir? \{#which-setting-should-i-choose\}
| Mi app... | Opción a elegir |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| No tiene sistema de inicio de sesión y solo utiliza los IDs de perfil anónimos de Adapty. | Usa la opción predeterminada, ya que los niveles de acceso siempre se comparten entre IDs de perfil anónimos en las tres opciones. |
| Tiene un sistema de inicio de sesión opcional y permite a los clientes realizar compras antes de crear una cuenta. | Elige **Transferir acceso al nuevo usuario** para garantizar que los clientes que compren sin cuenta puedan restaurar sus transacciones más adelante. |
| Requiere que los clientes creen una cuenta antes de comprar, pero permite que las compras estén vinculadas a varios Customer User IDs. | Elige **Transferir acceso al nuevo usuario** para garantizar que solo un Customer User ID tenga acceso a la vez, permitiendo además que los usuarios inicien sesión con un Customer User ID diferente sin perder su acceso de pago. |
| Requiere que los clientes creen una cuenta antes de comprar, con reglas estrictas que vinculan las compras a un único Customer User ID. | Elige **Desactivado** para garantizar que las transacciones nunca se transfieran entre cuentas. |
## 7. Claves del SDK y la API \{#7-sdk-and-api-keys\}
Usa una clave SDK pública para integrar los SDK de Adapty en tu app, y una clave secreta para acceder a la API del servidor de Adapty. Puedes generar nuevas claves o revocar las existentes según sea necesario. Para crear tokens para el Developer CLI, ve a **Settings → Developer API**. Consulta [Authentication](developer-cli-authentication).
## 8. Dispositivos de prueba \{#8-test-devices\}
Especifica los dispositivos que se usarán para pruebas para asegurarte de que reciben actualizaciones instantáneas de los cambios en paywalls o placements, sin demoras de caché. Para más información, consulta [Testing devices](test-devices).
## 9. Persistencia de variante entre placements \{#9-cross-placement-variation-stickiness\}
Define cuánto tiempo después de finalizar una prueba un usuario sigue viendo las variantes de esa prueba. Esto afecta a la precisión de los análisis y a la experiencia del usuario, ya que mostrarle una oferta diferente a la que vio anteriormente puede influir en su decisión de compra.
El período máximo y predeterminado de persistencia es de 90 días.
:::warning
Ten en cuenta lo siguiente:
- Cambiar esta configuración afectará a todos los usuarios que previamente recibieron una variante. Inmediatamente podrán ver un nuevo paywall cuando accedan a un placement, lo que puede distorsionar los resultados de tus pruebas A/B en curso.
- Si el período de persistencia ha expirado para un usuario, puede recibir un nuevo paywall o prueba A/B. Sin embargo, incluso en ese caso, no podrá formar parte de ninguna otra prueba entre placements en ningún momento futuro.
:::
## 10. Eliminar la app \{#10-delete-the-app\}
Si ya no necesitas una app, puedes eliminarla de Adapty.
:::warning
Ten en cuenta que esta acción es irreversible y no podrás restaurar la app ni sus datos.
:::
---
# File: ios-settings
---
---
title: "Credenciales de Apple App Store"
description: "Configura los ajustes de iOS en Adapty para una gestión fluida de suscripciones."
---
Para configurar las credenciales del App Store y garantizar el funcionamiento óptimo del SDK de Adapty para iOS, ve a la pestaña [iOS SDK](https://app.adapty.io/settings/ios-sdk) dentro de la página App Settings del Adapty Dashboard. A continuación, configura los siguientes parámetros:
| Campo | Descripción |
|----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Bundle ID** | El [bundle ID de tu app](app-store-connection-configuration#step-1-provide-bundle-id-and-apple-app-id). |
| **In-app purchase API (StoreKit 2)** | [Claves](app-store-connection-configuration#step-2-provide-issuer-id-and-key-id) para habilitar la autenticación segura y la validación del historial de transacciones de compras in-app. |
| **App Store Server Notifications** | URL que se utiliza para habilitar las [notificaciones server-to-server](enable-app-store-server-notifications) del App Store para monitorizar y responder a los cambios de estado de las suscripciones de los usuarios. |
| **App Store Promotional Offers** | Claves de suscripción para crear [ofertas promocionales](generate-in-app-purchase-key) en Adapty para productos específicos. |
| **Apple app ID** | El ID de tu app en el App Store. Para encontrarlo, abre la página de tu app en App Store Connect, abre la página **App Information** desde el menú izquierdo y copia el **Apple ID**. |
| **App Store Connect shared secret (LEGACY)** | **Clave heredada para el SDK de Adapty anterior a v2.9.0**
[Una clave](app-store-connection-configuration#step-5-enter-app-store-shared-secret) para la validación de recibos y la prevención de fraude en tu app.
| --- # File: google-play-store-connection-configuration --- --- title: "Configurar la integración con Google Play Store" description: "Configura la conexión con Google Play Store en Adapty para gestionar las compras in-app sin problemas." --- Esta sección describe el proceso de integración de tu aplicación móvil distribuida a través de Google Play con Adapty. Tendrás que introducir los datos de configuración de tu app desde la Play Store en el Adapty Dashboard. Este paso es fundamental para validar las compras y recibir actualizaciones de suscripciones desde la Play Store dentro de Adapty. Puedes completar este proceso durante el onboarding inicial o realizar cambios posteriormente en los **App Settings** del Adapty Dashboard. :::danger Los cambios de configuración solo son válidos antes de publicar tu aplicación móvil con los paywalls de Adapty integrados. Modificar la configuración tras el lanzamiento romperá la integración y los paywalls dejarán de mostrarse en tu aplicación. ::: ## Paso 1. Proporciona el Package name \{#step-1-provide-package-name\} El Package name es el identificador único de tu app en Google Play Store. Es necesario para el funcionamiento básico de Adapty, como el procesamiento de suscripciones. 1. Abre la [Google Play Developer Console](https://play.google.com/console/u/0/developers). 2. Selecciona la app cuyo ID necesitas. Se abrirá la ventana **Dashboard**.
3. Busca el ID del producto bajo el nombre de la aplicación y cópialo.
4. Abre los [**App settings**](https://app.adapty.io/settings/android-sdk) desde el menú superior de Adapty.
5. En la pestaña **Android SDK** de la ventana **App settings**, pega el **Package name** copiado.
## Paso 2. Sube el archivo de clave de cuenta \{#step-2-upload-the-account-key-file\}
1. Sube el archivo de clave privada de cuenta de servicio en formato JSON que creaste en el paso [Crear archivo de clave de cuenta de servicio](create-service-account) en el área **Service account key file**.
No olvides hacer clic en el botón **Save** para confirmar los cambios.
**Próximos pasos**
- [Activar las notificaciones en tiempo real para desarrolladores (RTDN) en la Google Play Console](enable-real-time-developer-notifications-rtdn)
---
# File: enable-real-time-developer-notifications-rtdn
---
---
title: "Habilitar notificaciones en tiempo real para desarrolladores (RTDN) en Google Play Console"
description: "Mantente informado sobre eventos críticos y garantiza la exactitud de los datos habilitando las Notificaciones en Tiempo Real para Desarrolladores (RTDN) en Google Play Console para Adapty. Aprende a configurar RTDN para recibir actualizaciones instantáneas sobre reembolsos y otros eventos importantes de la Play Store"
---
Configurar las notificaciones en tiempo real para desarrolladores (RTDN) es fundamental para garantizar la exactitud de los datos, ya que te permite recibir actualizaciones al instante desde la Play Store, incluyendo información sobre reembolsos y otros eventos.
## Habilitar notificaciones \{#enable-notifications\}
1. Asegúrate de tener **Google Cloud Pub/Sub** habilitado. Abre [este enlace](https://console.cloud.google.com/flows/enableapi?apiid=pubsub) y selecciona el proyecto de tu app. Si todavía no has habilitado **Google Cloud Pub/Sub**, debes hacerlo aquí.
2. Ve a [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) desde el menú superior de Adapty y copia el contenido del campo **Enable Pub/Sub API** que aparece junto al título **Google Play RTDN topic name**.
:::note Si el contenido del campo **Enable Pub/Sub API** tiene un formato incorrecto (el formato correcto empieza por `projects/...`), consulta la sección [Corregir el formato incorrecto en el campo Enable Pub/Sub API](enable-real-time-developer-notifications-rtdn#fixing-incorrect-format-in-enable-pubsub-api-field) para obtener ayuda. ::: 3. Abre la [Google Play Console](https://play.google.com/console/), elige tu app y ve a **Monetize with Play** -> **Monetization setup**. En la sección **Google Play Billing**, marca la casilla **Enable real-time notifications**. 4. Pega el contenido del campo **Enable Pub/Sub API** que copiaste en los **App Settings** de Adapty en el campo **Topic name**. 5. Haz clic en **Save changes** en la Google Play Console.
## Probar las notificaciones \{#test-notifications\}
Para comprobar si te has suscrito correctamente a las notificaciones en tiempo real para desarrolladores:
1. Guarda los cambios en la configuración de Google Play Console.
2. Debajo del campo **Topic name** en Google Play Console, haz clic en **Send test notification**.
3. Ve a [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) en Adapty. Si se ha enviado una notificación de prueba, verás su estado encima del nombre del topic.
## Corregir el formato incorrecto en el campo Enable Pub/Sub API \{#fixing-incorrect-format-in-enable-pubsub-api-field\}
Si el contenido del campo **Enable Pub/Sub API** tiene un formato incorrecto (el formato correcto empieza por `projects/...`), sigue estos pasos para solucionar el problema:
### 1. Verificar la habilitación de la API y los permisos \{#1-verify-api-enablement-and-permissions\}
Comprueba detenidamente que todas las APIs necesarias estén habilitadas y que los permisos estén correctamente concedidos a la cuenta de servicio. Aunque ya hayas completado estos pasos, es importante revisarlos de nuevo para asegurarte de que no se omitió ninguno. Repite los pasos de las siguientes secciones:
1. [Habilitar las APIs de desarrollador en Google Play Console](enabling-of-devepoler-api)
2. [Crear una cuenta de servicio en Google Cloud Console](create-service-account)
3. [Conceder permisos a la cuenta de servicio en Google Play Console](grant-permissions-to-service-account)
4. [Generar el archivo de clave de la cuenta de servicio en Google Play Console](create-service-account-key-file)
5. [Configurar la integración con Google Play Store](google-play-store-connection-configuration)
### 2. Ajustar las políticas de dominio \{#2-adjust-domain-policies\}
Cambia las políticas **Domain restricted contacts** y **Domain restricted sharing**:
1. Abre la [Google Cloud Console](https://console.cloud.google.com/) y selecciona el proyecto donde creaste la cuenta de servicio para gestionar tu app.
2. En la sección **Quick Access**, elige **IAM & Admin**.
3. En el panel izquierdo, elige **Organization Policies**.
4. Busca la política **Domain restricted contacts**.
5. Haz clic en el botón de puntos suspensivos en la columna **Actions** y elige **Edit policy**.
6. En la ventana de edición de la política:
1. En **Policy source**, selecciona el botón de opción **Override parent's policy**.
2. En **Policy enforcement**, selecciona el botón de opción **Replace**.
3. En **Rules**, haz clic en el botón **ADD A RULE**.
4. En **New rule** -> **Policy values**, elige **Allow All**.
5. Haz clic en **SET POLICY**.
7. Repite los pasos 4-6 para la política **Domain restricted sharing**.
Por último, vuelve a generar el contenido del campo **Enable Pub/Sub API** situado junto al título **Google Play RTDN topic name**. El campo tendrá ahora el formato correcto.
Asegúrate de cambiar **Policy source** de vuelta a **Inherit parent's policy** para las políticas actualizadas una vez que hayas habilitado correctamente las Notificaciones en Tiempo Real para Desarrolladores (RTDN).
## Reenvío de eventos sin procesar \{#raw-events-forwarding\}
En algunos casos, puede que quieras seguir recibiendo eventos S2S sin procesar de Google. Para continuar recibiéndolos mientras usas Adapty, simplemente añade tu endpoint en el campo **URL for forwarding raw Google events** y enviaremos los eventos tal cual los recibimos de Google.
---
**Próximos pasos**
Configura el SDK de Adapty para:
- [Android](sdk-installation-android)
- [React Native](sdk-installation-reactnative)
- [Flutter](sdk-installation-flutter)
- [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)
- [Unity](sdk-installation-unity)
---
# File: apple-search-ads
---
---
title: "Apple Ads"
description: "Integra Apple Ads con Adapty para optimizar las conversiones de suscripciones."
---
:::important
La integración de Apple Ads en **App settings** se utiliza únicamente para análisis básico y para las integraciones con SplitMetrics Acquire y Asapty.
[Adapty Ads Manager](adapty-ads-manager) utiliza una conexión independiente. Conecta tu cuenta de Apple Ads en [Adapty Ads Manager](adapty-ads-manager-get-started).
:::
Adapty puede ayudarte a obtener datos de atribución de Apple Ads y analizar tus métricas con segmentación por campaña y palabra clave. Adapty recopila los datos de atribución de Apple Ads automáticamente a través de su SDK y el AdServices Framework.
Una vez que hayas configurado la integración con Apple Ads, Adapty comenzará a recibir datos de atribución de Apple Ads. Puedes acceder a estos datos y consultarlos fácilmente en la página de perfiles.
## Configurar la integración \{#set-up-integration\}
### Conectar Adapty con el framework AdServices \{#connect-adapty-to-the-adservices-framework\}
Apple Ads a través de [AdServices](https://developer.apple.com/documentation/adservices) requiere cierta configuración en el Adapty Dashboard, y también necesitarás habilitarlo en el lado de la app. Para configurar Apple Ads usando el framework AdServices a través de Adapty, sigue estos pasos:
#### Paso 1: Obtener la clave pública \{#step-1-obtain-public-key\}
En el Adapty Dashboard, ve a [Settings -> Apple Ads.](https://app.adapty.io/settings/apple-search-ads)
Localiza la clave pública pregenerada (Adapty te proporciona un par de claves) y cópiala.
:::note
Si utilizas un servicio alternativo o tu propia solución para la atribución de Apple Ads, puedes subir tu propia clave privada.
:::
#### Paso 2: Configura la gestión de usuarios en Apple Ads \{#step-2-configure-user-management-on-apple-ads\}
En tu [cuenta de Apple Ads](https://ads.apple.com/app-store), ve a la página **Settings > User Management**. Para que Adapty pueda obtener datos de atribución, necesitas invitar otra cuenta de Apple ID y concederle acceso como API Account Manager. Puedes usar cualquier cuenta a la que tengas acceso o crear una nueva exclusivamente para este fin. Lo importante es que debas poder iniciar sesión en Apple Ads con ese Apple ID.
#### Paso 3: Generar credenciales de API \{#step-3-generate-api-credentials\}
Como siguiente paso, inicia sesión en la cuenta recién añadida en Apple Ads. Ve a Settings -> API en la interfaz de Apple Ads. Pega la clave pública copiada anteriormente en el campo correspondiente. Genera nuevas credenciales de API.
#### Paso 4: Configurar Adapty con las credenciales de Apple Ads \{#step-4-configure-adapty-with-apple-ads-credentials\}
Copia los campos Client ID, Team ID y Key ID de la configuración de Apple Ads. En el Adapty Dashboard, pega estas credenciales en los campos correspondientes.
### Conectar tu app a la red AdServices \{#connect-your-app-to-the-adservices-network\}
Una vez que completes [la configuración del framework AdServices](#connect-the-adservices-framework), Adapty empieza a recopilar automáticamente los datos de atribución de Apple Search Ads. No necesitas añadir ningún código al SDK.
En aplicaciones iOS, estos datos de atribución **siempre** tendrán prioridad sobre los datos de otras fuentes. Si este comportamiento no es el deseado, *desactiva* la atribución de ASA siguiendo las instrucciones a continuación.
## Desactivar la integración \{#disable-integration\}
Para desactivar la atribución de Apple Search Ads, abre la pestaña [**App Settings** -> **Apple Search Ads**](https://app.adapty.io/settings/apple-search-ads) y desactiva el interruptor **Receive Apple Search Ads attribution**.
:::warning
Ten en cuenta que desactivar esto detendrá por completo la recepción de datos de análisis de ASA. Como resultado, ASA dejará de utilizarse en el análisis y no se enviará a las integraciones. Además, SplitMetrics Acquire y Asapty dejarán de funcionar, ya que dependen de la atribución de ASA para operar correctamente.
La atribución recibida antes de este cambio no se verá afectada.
:::
## Subir tus propias claves \{#uploading-your-own-keys\}
:::note
Opcional
Estos pasos no son necesarios para la atribución de Apple Ads, solo para trabajar con otros servicios como Asapty o tu propia solución.
:::
Puedes usar tu propio par de claves pública-privada si estás utilizando otros servicios o una solución propia para la atribución de ASA.
### Paso 1 \{#step-1\}
Genera la clave privada en el Terminal
```text showLineNumbers title="Text"
openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem
```
Súbela en Adapty Settings -> Apple Ads (botón Upload private key)
### Paso 2 \{#step-2\}
Genera la clave pública en el Terminal
```text showLineNumbers title="Text"
openssl ec -in private-key.pem -pubout -out public-key.pem
```
Puedes usar esta clave pública en los ajustes de Apple Ads de la cuenta con el rol API Account Manager. Así podrás usar los valores generados de Client ID, Team ID y Key ID tanto en Adapty como en otros servicios.
---
# File: account
---
---
title: "Detalles de la cuenta y facturación"
description: "Gestiona tu cuenta de Adapty y optimiza la configuración para un mejor seguimiento de suscripciones."
---
La página **Account** te permite gestionar tu perfil, los miembros del equipo y la facturación.
La página tiene tres pestañas:
- [General](#general-settings)
- [Subscription & Billing](#billing-info)
- [Members](#members)
Para acceder a la configuración de tu cuenta, haz clic en **Account** en la parte superior derecha o ve a [app.adapty.io/account](https://app.adapty.io/account).
## Configuración general \{#general-settings\}
La pestaña General contiene tu perfil, la configuración de la cuenta, las preferencias de visualización y la configuración de informes.
- **Profile**: Introduce tu nombre, apellidos y nombre de empresa. El nombre de empresa puede tener hasta 256 caracteres.
- **Account settings**: Consulta tu dirección de correo electrónico registrada y cambia tu contraseña.
- **Date & Time formats**: Elige cómo se muestran las fechas y horas en Adapty:
- **American format**: January 31, 2022 y hora en formato de 12 horas (AM/PM)
- **European format**: 31 January, 2022 y hora en formato de 24 horas (16:00)
- **Email reports**: Configura informes diarios, semanales o mensuales para una o todas tus apps. Recibe informes resumidos de todas las apps a la vez, o un informe detallado de cada app seleccionada.
## Suscripción y facturación \{#billing-info\}
La pestaña **Subscription & Billing** te permite gestionar tu información de pago y el acceso a funciones:
- Añadir o actualizar los datos de pago
- Revisar la información de facturación
- Adquirir funciones adicionales de pago
Más información sobre [funciones y precios](https://adapty.io/pricing).
## Miembros \{#members\}
Puedes gestionar los miembros de tu equipo desde la configuración de la cuenta. Para añadir miembros, invítalos por su correo electrónico y asígnales un rol.
Lee más sobre cómo gestionar los miembros del equipo y sus permisos de acceso [aquí](members-settings).
---
# File: members-settings
---
---
title: "Members"
description: "Gestiona la configuración y los permisos de los miembros en el dashboard de Adapty."
---
:::note
Esta página trata sobre los miembros del Adapty Dashboard
Si quieres otorgar distintos niveles de acceso a los usuarios de tu app, consulta [Nivel de acceso](access-level).
:::
El sistema de miembros del Adapty Dashboard te permite conceder diferentes niveles de acceso a Adapty y especificar las aplicaciones para cada miembro.
## Roles \{#roles\}
Los siguientes roles están disponibles para los miembros del Adapty Dashboard:
| Rol | Acceso a Facturación | Añadir nuevos miembros | Cambiar cualquier cosa | Acceso a todas las secciones |
|-------------|----------------------|------------------------|------------------------|------------------------------|
| Owner | ✅ | ✅ | ✅ | ✅ |
| Admin | ❌ | ✅ | ✅ | ✅ |
| Developer | ❌ | ❌ | ✅ | ❌ |
| Viewer | ❌ | ❌ | ❌ | ✅ |
| Support | ❌ | ❌ | ❌ | ❌ |
| ASA manager | ❌ | ❌ | ❌ | ❌ |
- **Owner:** El Owner es el creador original de la cuenta de Adapty y tiene el mayor nivel de acceso y control. Los Owners tienen acceso completo a la facturación de Adapty, lo que les permite gestionar la información de pago y los planes de suscripción. Además, solo los Owners y Admins pueden especificar el acceso a las aplicaciones para los nuevos miembros. Solo puede haber un Owner por cuenta de Adapty.
- **Admin:** Los miembros con el rol Admin tienen acceso completo a las aplicaciones seleccionadas. Pueden realizar diversas tareas de gestión, como crear y modificar paywalls, realizar pruebas A/B, analizar métricas y gestionar miembros dentro de esas aplicaciones.
- **Developer**: Los miembros con el rol Developer tienen acceso completo a todas las entidades, excepto a las analíticas y los miembros de la cuenta. No pueden acceder a ninguna configuración de facturación. Este rol está pensado para quienes configuran paywalls, pruebas A/B y otras entidades e integran Adapty en tu app, pero no deben ver datos financieros.
- **Viewer:** Los miembros con el rol Viewer tienen acceso de solo lectura a las aplicaciones seleccionadas. Pueden ver la información, pero no pueden crear ni modificar paywalls, pruebas A/B ni otras funciones, invitar a nuevos usuarios, crear nuevas apps ni cambiar la configuración de la app.
- **Support:** Los miembros con el rol Support solo tienen acceso a los perfiles de usuario en las aplicaciones seleccionadas. Sin embargo, no pueden realizar acciones como añadir nuevos miembros ni acceder a ninguna otra sección de Adapty. Este rol es especialmente adecuado para equipos de soporte o personas que necesitan ayudar a los clientes con consultas o problemas relacionados con suscripciones.
- **ASA manager**: Los miembros con el rol ASA manager solo tienen acceso al dashboard de [Adapty Ads Manager](adapty-ads-manager).
## Añadir un miembro \{#add-a-member\}
En Adapty, puedes invitar hasta 256 miembros al equipo. Añadir nuevos miembros es gratuito.
:::note
Solo puedes invitar direcciones de correo que aún no estén registradas en Adapty. Si tu compañero o compañera tiene una cuenta independiente, invita a otra dirección de correo o contacta con el soporte de Adapty para eliminar su cuenta existente.
:::
Para añadir un miembro al equipo:
1. Haz clic en **Account** en la parte superior derecha y abre la pestaña **Members**.
2. Haz clic en **Invite member**.
3. Introduce la dirección de correo electrónico del miembro.
4. Selecciona un [rol](#roles) de la lista.
5. Selecciona las apps a las que quieres dar acceso.
6. (Opcional) Activa **Always allow access to new apps** para conceder acceso automáticamente a futuras apps.
7. Haz clic en **Save**.
## Transferir la propiedad de la cuenta \{#transfer-account-ownership\}
Si necesitas transferir la **propiedad completa de la cuenta**, contacta con nuestro equipo de soporte en [support@adapty.io](mailto:support@adapty.io).
Si necesitas transferir la **propiedad de la app**, consulta la [guía específica](transfer-apps) para más información.
---
# File: set-up-app-store-connect
---
---
title: "Configurar App Store Connect"
description: "Guía para desarrolladores primerizos sobre cómo inscribirse en el Apple Developer Program y configurar App Store Connect para las compras in-app."
---
Si estás **creando tu primera app para iOS**, debes configurar tu cuenta de Apple Developer y App Store Connect antes de integrar Adapty.
:::note
Si ya tienes una cuenta de Apple Developer y una app registrada en App Store Connect, puedes saltarte esta guía e ir directamente a [Integración inicial con el App Store](initial_ios).
:::
## Paso 1. Inscríbete en el Apple Developer Program \{#step-1-enroll-in-apple-developer-program\}
Para distribuir apps en el App Store y vender compras in-app, debes unirte al [Apple Developer Program](https://developer.apple.com/programs/).
### Elige el tipo de inscripción \{#choose-enrollment-type\}
Apple ofrece dos tipos de inscripción:
| | Individual | Organización |
|----------------------------------------|------------------------|------------------------------------|
| **Para quién es** | Desarrolladores solos | Empresas, equipos, organizaciones sin ánimo de lucro |
| **Requiere número D-U-N-S** | No | Sí |
| **Apps publicadas bajo** | Tu nombre personal | El nombre de tu organización |
| **Gestión de equipo** | No disponible | Disponible |
:::tip
Si te inscribes como organización, necesitas un **número D-U-N-S** — un identificador único de nueve dígitos emitido por Dun & Bradstreet. Puedes [comprobar si tu organización ya tiene uno](https://developer.apple.com/enroll/duns-lookup/) o solicitar uno nuevo — el enlace está al final de la página de búsqueda. Un número D-U-N-S puede tardar hasta 5 días hábiles en llegar.
:::
### Inscríbete \{#enroll\}
1. Ve a la [página de inscripción del Apple Developer Program](https://developer.apple.com/programs/enroll/).
2. Inicia sesión con tu Apple ID. Si no tienes uno, créalo primero.
3. Sigue los pasos según tu tipo de inscripción (individual u organización).
4. Paga la cuota anual.
Una vez que Apple procese tu inscripción, tendrás acceso a [App Store Connect](https://appstoreconnect.apple.com). La inscripción suele tardar hasta 48 horas. Para las organizaciones, puede tardar más si se requiere verificación del D-U-N-S.
## Paso 2. Configura tu app en App Store Connect \{#step-2-set-up-your-app-in-app-store-connect\}
Antes de poder vender compras in-app, completa la configuración inicial en App Store Connect. Esto incluye firmar acuerdos, añadir datos de pago y registrar tu app.
### Firma el Paid Applications Agreement \{#sign-the-paid-applications-agreement\}
Apple requiere que firmes el Paid Applications Agreement antes de poder vender en el App Store. Esto aplica tanto a apps de pago como a compras in-app en apps gratuitas.
1. Ve a la página **Business** en [App Store Connect](https://appstoreconnect.apple.com/business).
2. Encuentra el acuerdo **Paid Apps** y haz clic en **Review and Agree**.
3. Completa la información requerida:
- **Banking information**: Añade una cuenta bancaria donde Apple enviará tus ingresos.
- **Tax information**: Rellena los formularios fiscales de los países donde quieres vender.
- **Contact information**: Proporciona tus datos de contacto.
:::important
Debes completar las tres secciones (banking, tax, contact) para que el acuerdo entre en vigor. Hasta que el acuerdo esté activo, no podrás vender compras in-app.
:::
### Crea un Bundle ID \{#create-a-bundle-id\}
Un Bundle ID identifica tu app de forma única en todo el ecosistema de Apple. Lo necesitas para registrar tu app en App Store Connect y para configurar la integración con Adapty.
1. Abre el [portal de Apple Developer](https://developer.apple.com/account).
2. Ve a **Certificates, Identifiers & Profiles** → **Identifiers**.
3. Haz clic en **+** para registrar un nuevo identificador.
4. Selecciona **App IDs** y haz clic en **Continue**.
5. Selecciona **App** como tipo y haz clic en **Continue**.
6. Rellena los campos:
- **Description**: Un nombre para identificar este Bundle ID (p. ej., "My Subscription App").
- **Bundle ID**: Elige **Explicit** e introduce un identificador único en formato de dominio invertido (p. ej., `com.yourcompany.yourapp`).
7. En la sección **Capabilities**, desplázate hacia abajo y marca **In-App Purchase**.
8. Haz clic en **Continue** y luego en **Register**.
### Registra tu app en App Store Connect \{#register-your-app-in-app-store-connect\}
1. Ve a la página **Apps** en [App Store Connect](https://appstoreconnect.apple.com/apps).
2. Haz clic en **+** → **New App**.
3. Rellena los campos obligatorios:
- **Platforms**: Selecciona **iOS**.
- **Name**: El nombre de tu app tal como aparecerá en el App Store.
- **Primary language**: El idioma predeterminado para los metadatos de tu app.
- **Bundle ID**: Selecciona el Bundle ID que creaste en el paso anterior.
- **SKU**: Un identificador único para tu app (no visible para los usuarios). Por ejemplo, `my_subscription_app_2025`.
4. Haz clic en **Create**.
Tu app ya está registrada en App Store Connect y lista para la integración con Adapty.
## Qué hacer a continuación \{#whats-next\}
- [Integración inicial con el App Store](initial_ios): Conecta tu app del App Store a Adapty
- [Integración del SDK](quickstart-sdk): Integra el SDK de Adapty en el código de tu app
- [Pruebas en sandbox](test-purchases-in-sandbox): Prueba tus compras in-app antes del lanzamiento
- [Envía tu app iOS al App Store](submit-app-to-app-store): Sube tu build y envíala para revisión de Apple
- [App Store Small Business Program](app-store-small-business-program): Reduce tu comisión del App Store del 30% al 15%
---
# File: app-store-products
---
---
title: "Producto en App Store"
description: "Gestiona los productos de App Store de forma eficiente con las herramientas de suscripción de Adapty."
---
Esta página explica cómo crear un producto en App Store Connect. Aunque esta información no está directamente relacionada con la funcionalidad de Adapty, puede servirte de ayuda si tienes problemas al crear productos en tu cuenta de App Store Connect.
Para crear un producto que se vinculará a Adapty:
1. Abre **App Store Connect**. Ve a la sección [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) en el menú lateral izquierdo.
2. Si aún no has creado un grupo de suscripciones, haz clic en el botón **Create** bajo el título **Subscription Groups** para iniciar el proceso. Los [Subscription Groups](https://developer.apple.com/help/app-store-connect/manage-subscriptions/offer-auto-renewable-subscriptions) en App Store Connect organizan y gestionan tus productos, lo que permite a los usuarios cambiar entre diferentes ofertas sin problemas. Ten en cuenta que no es posible crear una suscripción fuera de un grupo.
3. En la ventana **Create Subscription Group** que se abre, introduce un nombre para el nuevo grupo de suscripciones en el campo **Reference Name**. El nombre de referencia es una etiqueta o identificador que tú defines para distinguir y gestionar los distintos grupos de suscripciones dentro de tu app.
El nombre de referencia no es visible para los usuarios; es exclusivamente para tu uso interno y organización. Te permite identificar y referirte fácilmente a grupos de suscripciones específicos al gestionarlos en la interfaz de App Store Connect. Esto resulta especialmente útil si tienes varias ofertas de suscripción o quieres categorizarlas de una forma que tenga sentido para la estructura de tu app.
4. Haz clic en el botón **Create** para confirmar la creación del grupo de suscripciones.
5. El grupo de suscripciones se crea y se abre. Ahora puedes crear suscripciones dentro del grupo. Haz clic en el botón **Create** bajo el título **Subscriptions**. Si añades una nueva suscripción a un grupo existente, haz clic en el botón **Plus** junto al título **Subscriptions**.
6. En la ventana **Create Subscription** que se abre, introduce el nombre en el campo **Reference Name** y el código único de la suscripción en el campo **Product ID**.
El Reference Name actúa como identificador exclusivo dentro de App Store Connect para tu suscripción in-app. No es visible para los usuarios en el App Store. Recomendamos usar una descripción clara y legible que represente con precisión la suscripción que quieres crear. Ten en cuenta que este nombre no puede superar los 64 caracteres.
El Product ID es un identificador alfanumérico único imprescindible para acceder a tu producto durante la fase de desarrollo y para sincronizarlo con Adapty. En el Product ID solo se permiten caracteres alfanuméricos, puntos y guiones bajos.
7. Haz clic en el botón **Create** para confirmar la creación de la suscripción.
8. La suscripción se crea y se abre. Ahora selecciona la duración de la suscripción en la lista **Subscription Duration**. Aunque la duración ya esté indicada en el nombre de la suscripción, recuerda completar el campo **Subscription Duration**.
9. Ahora toca configurar el precio de la suscripción. Para ello, haz clic en el botón **Add Subscription Price** bajo el título Subscription Prices. Es posible que tengas que desplazarte hacia abajo para encontrarlo.
10. En la ventana **Subscription Price** que se abre, selecciona el país base en la lista **Country or Region** y la moneda base en la lista **Price**. Más adelante, Apple calculará automáticamente los precios para los 175 países o regiones basándose en este precio base y los tipos de cambio más recientes.
11. Haz clic en el botón **Next**. En la ventana **Price by Country or Region** que se abre, verás los precios recalculados automáticamente para todos los países. Puedes modificarlos si lo deseas.
12. Tras actualizar los precios regionales, continúa haciendo clic en el botón **Next** en la parte inferior de la ventana.
13. En la ventana **Confirm Subscription Price?** que se abre, revisa detenidamente los precios finales. Si necesitas corregirlos, puedes hacer clic en el botón **Back** para volver a la ventana **Price by Country or Region** y actualizarlos. Cuando estés conforme con los precios, haz clic en el botón **Confirm**.
14. Después de cerrar la ventana **Confirm Subscription Price?**, recuerda hacer clic en el botón **Save** en la ventana de tu suscripción. Sin este paso, la suscripción no se creará y todos los datos introducidos se perderán.
Ten en cuenta que los pasos descritos hasta ahora se centran en configurar una suscripción de renovación automática. Sin embargo, si quieres configurar otros tipos de compras in-app, puedes hacer clic en la pestaña **In-App Purchases** en la barra lateral, en lugar de "Subscriptions". Esto te llevará a la sección donde puedes gestionar y crear distintos tipos de compras in-app.
### Añadir productos a Adapty \{#add-products-to-adapty\}
Una vez que hayas terminado de añadir tus compras in-app, suscripciones y ofertas en App Store Connect, el siguiente paso es [añadir estos productos a Adapty](create-product).
---
# File: apple-app-privacy
---
---
title: "Privacidad de aplicaciones de Apple"
description: "Entiende las políticas de privacidad de aplicaciones de Apple y su impacto en tu app de suscripciones."
---
Apple exige una declaración de privacidad para todas las apps nuevas y actualizaciones tanto en la sección **App Privacy** de App Store Connect como en el archivo de manifiesto de la app. Adapty es una dependencia de terceros en tu app, por lo que debes declarar cómo usas Adapty en relación con los datos de usuario.
## Manifiesto de privacidad de aplicaciones de Apple \{#apple-app-privacy-manifest\}
El [archivo de manifiesto de privacidad](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests), llamado `PrivacyInfo.xcprivacy`, describe qué datos privados utiliza tu app y por qué. Como propietario de la app, debes crear un archivo de manifiesto para ella. Además, si integras SDKs adicionales, asegúrate de que los archivos de manifiesto de aquellos incluidos en la lista de [SDKs que requieren manifiesto de privacidad y firma](https://developer.apple.com/support/third-party-SDK-requirements/) estén incluidos. Al compilar la app, Xcode tomará todos estos archivos de manifiesto y los fusionará en uno solo.
Aunque Adapty no figura en la lista de [SDKs que requieren manifiesto de privacidad y firma](https://developer.apple.com/support/third-party-SDK-requirements/), las versiones 2.10.2 y superiores del SDK de Adapty lo incluyen para tu comodidad. Asegúrate de actualizar el SDK para obtener el manifiesto.
Si bien Adapty no requiere que se incluya ningún dato en el archivo de manifiesto (también llamado informe de privacidad de la app), si usas el `customerUserId` de Adapty para el seguimiento, es necesario especificarlo en tu archivo de manifiesto de la siguiente manera:
1. Añade un diccionario al array `NSPrivacyCollectedDataTypes` en tu archivo de información de privacidad.
2. Añade las claves `NSPrivacyCollectedDataType`, `NSPrivacyCollectedDataTypeLinked` y `NSPrivacyCollectedDataTypeTracking` al diccionario.
3. Añade la cadena `NSPrivacyCollectedDataTypeUserID` (identificador del tipo de dato `UserID` en la [lista de categorías y tipos de datos que se deben declarar en el archivo de manifiesto](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests#Describe-the-data-your-app-or-third-party-SDK-collects)) para la clave `NSPrivacyCollectedDataType` en tu diccionario `NSPrivacyCollectedDataTypes`.
4. Añade `true` para las claves `NSPrivacyCollectedDataTypeTracking` y `NSPrivacyCollectedDataTypeLinked` en tu diccionario `NSPrivacyCollectedDataTypes`.
5. Usa la cadena `NSPrivacyCollectedDataTypePurposeProductPersonalization` como valor para la clave `NSPrivacyCollectedDataTypePurposes` en tu diccionario `NSPrivacyCollectedDataTypes`.
Si segmentas tus paywalls a audiencias con atributos personalizados, considera detenidamente qué atributos personalizados usas y si coinciden con las [categorías y tipos de datos que se deben declarar en el archivo de manifiesto](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests). En ese caso, repite los pasos anteriores para cada tipo de dato.
Una vez que hayas declarado todos los tipos y categorías de datos que recopilas, crea el informe de privacidad de tu app tal como se describe en la [documentación de Apple](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests#Create-your-apps-privacy-report).
## Declaración de privacidad de aplicaciones de Apple en App Store Connect \{#apple-app-privacy-disclosure-in-app-store-connect\}
1. En [App Store Connect](https://appstoreconnect.apple.com/), abre tu app y ve a **App Privacy**. Haz clic en **Get Started**.
2. Selecciona **Yes, we collect data from this app** y haz clic en **Next**.
### Tipos de datos \{#data-types\}
La tabla siguiente lista los tipos de datos que Apple exige declarar e indica cuáles necesita Adapty. **Esto solo cubre Adapty.** Si tu app recopila datos adicionales a través de otros SDKs o tu propio código, selecciona también esos tipos de datos.
✅ = Requerido por Adapty
👀 = Puede ser requerido \(consulta los detalles a continuación\)
❌ = No requerido por Adapty — selecciona si tu app recopila estos datos por otros medios
| Tipo de dato | Requerido | Nota |
|-----------------------------------------------------------------------|-----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Identifiers | ✅ | Si identificas usuarios con un customerUserId, selecciona 'User ID'.
Adapty recopila IDFA, por lo que debes seleccionar 'Device ID'.
| | Purchases | ✅ | Adapty recopila el historial de compras de los usuarios. | | Contact Info, incluyendo nombre, número de teléfono o dirección email | 👀 | Requerido si pasas datos personales como nombre, número de teléfono o dirección de email usando el método **`updateProfile`**. | | Usage Data | 👀 | Si usas SDKs de analítica como Amplitude, Mixpanel, AppMetrica o Firebase, puede ser necesario. | | Location | ❌ | Adapty no recopila datos de ubicación precisa. Selecciona si tu app los recopila. | | Health & Fitness | ❌ | Adapty no recopila datos de salud ni actividad física. Selecciona si tu app los recopila. | | Sensitive Info | ❌ | Adapty no recopila información sensible. Selecciona si tu app la recopila. | | User Content | ❌ | Adapty no recopila contenido de usuario. Selecciona si tu app lo recopila. | | Diagnostics | ❌ | Adapty no recopila datos de diagnóstico. Selecciona si tu app los recopila. | | Browsing History | ❌ | Adapty no recopila el historial de navegación. Selecciona si tu app lo recopila. | | Search History | ❌ | Adapty no recopila el historial de búsqueda. Selecciona si tu app lo recopila. | | Contacts | ❌ | Adapty no recopila listas de contactos. Selecciona si tu app las recopila. | | Financial Info | ❌ | Adapty no recopila información financiera. Selecciona si tu app la recopila. | ### Tipos de datos requeridos \{#required-data-types\} #### Purchases \{#purchases\} Al usar Adapty, debes declarar que tu app recopila **Purchase History**.
#### Identifiers \{#identifiers\}
Al usar Adapty, debes declarar los siguientes identificadores:
- **Device ID** — Adapty recopila IDFA.
- **User ID** — requerido si identificas usuarios con **`customerUserId`**.
### Uso de datos \{#data-usage\}
Después de guardar los **Data types**, deberás indicar cómo se usan los datos:
1. Haz clic en **Set up purchase history** dentro del bloque **Purchases**.
2. Cuando Apple pregunte cómo se usan los datos del historial de compras, selecciona lo siguiente para Adapty:
- **Analytics** — Adapty usa el historial de compras para analíticas de ingresos, cohortes y métricas.
- **Product Personalization** — Adapty usa los datos de compras para la segmentación de audiencias y la segmentación de paywalls.
- **App Functionality** — Adapty valida las compras, gestiona los niveles de acceso y hace seguimiento del estado de la suscripción.
Selecciona propósitos adicionales si tu app usa los datos de compras de otras formas (por ejemplo, si envías eventos de compra a plataformas publicitarias mediante integraciones de Adapty).
3. Haz clic en **Next**.
4. Para **Device ID** y **User ID** (si se usa):
1. Haz clic en **Set up user/device ID** dentro del bloque **User/Device ID**.
2. Cuando Apple pregunte cómo se usan los datos de identificadores, selecciona lo siguiente para Adapty:
- **App Functionality** — Adapty usa los identificadores para gestionar perfiles de usuario, vincular compras y hacer seguimiento de los niveles de acceso.
Si envías datos de atribución a plataformas de terceros mediante integraciones de Adapty (como AppsFlyer o Adjust), selecciona también **Third-Party Advertising**. Selecciona propósitos adicionales si tu app usa los identificadores de otras formas.
5. Haz clic en **Next**.
---
# File: apple-family-sharing
---
---
title: "Apple Family Sharing"
description: "Habilita Apple Family Sharing en Adapty para admitir suscripciones compartidas."
---
La función de Family Sharing de Apple permite distribuir compras in-app entre los miembros de una familia, lo que ofrece a los usuarios de apps orientadas a grupos —como servicios de streaming de vídeo o apps para niños— una forma cómoda de compartir suscripciones sin tener que compartir su Apple ID. Al permitir que hasta cinco miembros de la familia usen una suscripción, [Family Sharing](https://developer.apple.com/documentation/storekit/supporting-family-sharing-in-your-app) puede mejorar la fidelización y el engagement de los usuarios en tu app.
En esta guía, explicamos cómo activar el uso compartido familiar para suscripciones y cómo Adapty gestiona las compras compartidas dentro de una familia.
Para empezar a habilitar Family Sharing para un producto concreto, ve a [App Store Connect](https://appstoreconnect.apple.com/). Family Sharing está desactivado por defecto tanto para las compras in-app nuevas como para las existentes, por lo que es necesario habilitarlo individualmente para cada compra in-app. Puedes hacerlo fácilmente accediendo a la **página de tu app**, navegando a la página de la compra in-app correspondiente y seleccionando la opción **Turn On** en la sección Family Sharing.
Ten en cuenta que una vez que actives Family Sharing para un producto, **no podrás desactivarlo**, ya que esto interrumpiría la experiencia de los usuarios que ya han compartido la suscripción con sus familiares.
Además, ten en cuenta que solo los productos no consumibles y las suscripciones pueden compartirse.
En el modal que aparece, haz clic en el botón **Confirm** para finalizar el proceso. Tras hacerlo, la sección Family Sharing debería actualizarse y mostrar el mensaje "This subscription can be shared by everyone in a family group." Esto confirma que la suscripción ya está habilitada para Family Sharing y puede compartirse con hasta cinco miembros de la familia.
Adapty facilita la compatibilidad con Family Sharing sin ningún esfuerzo adicional. Solo tienes que [configurar tus productos](app-store-products) desde App Store y, una vez que lo **actives** desde App Store Connect, **Family Sharing** estará disponible automáticamente en **Adapty** y se recibirá como un evento en el webhook.
:::note
Ten en cuenta que Family Sharing no es compatible con el entorno sandbox.
:::
Ten en cuenta que cuando un usuario adquiere una suscripción y la comparte con sus familiares, puede haber un **retraso de hasta una hora** antes de que esté disponible para ellos. Apple diseñó este retraso para dar al usuario tiempo de cambiar de opinión y retirar el acceso si lo desea. Sin embargo, si la suscripción se renueva, los familiares reciben acceso sin ningún retraso.
Cuando un usuario compra un producto in-app de Family Sharing, la transacción aparecerá en su recibo como de costumbre, pero con un nuevo campo llamado `in_app_ownership_type` con el valor `PURCHASED.` Además, se creará una nueva transacción para todos los miembros de la familia, que tendrá un `web_order_line_item_id` y un `original_transaction_id` diferentes a los de la compra original, así como un campo `in_app_ownership_type` con el valor `FAMILY_SHARED.`
Para garantizar un cálculo de ingresos preciso, solo se contabilizan en los análisis de Adapty las transacciones con un `in_app_ownership_type` de `PURCHASED`. Las transacciones `FAMILY_SHARED` quedan excluidas de las métricas de ingresos y conversión.
**Eventos enviados para transacciones de Family Sharing.**
Las transacciones `FAMILY_SHARED` solo activan el evento **Access level updated**. Los eventos de suscripción por producto no se activan para los miembros de la familia.
| Evento | `FAMILY_SHARED` | `PURCHASED` |
| --- | --- | --- |
| **Nivel de acceso actualizado** | Sí | Sí |
| **Suscripción iniciada** | No | Sí |
| **Prueba iniciada** | No | Sí |
| **Suscripción renovada** | No | Sí |
| **Suscripción expirada** | No | Sí |
| **Suscripción reembolsada** | No | Sí |
| **Problema de facturación detectado** | No | Sí |
Si tu analítica downstream se basa en **Suscripción iniciada**, los miembros familiares no aparecerán ahí. Usa **Nivel de acceso actualizado** para detectar miembros familiares activos.
Para identificar a los demás miembros de la familia en Adapty, puedes encontrarlos en los detalles del evento. Primero, localiza la transacción de compra familiar original. Luego, examina los detalles del evento para esa transacción, buscando específicamente el mismo producto, fecha de compra y fecha de vencimiento. Analizando los detalles del evento, puedes identificar otras transacciones de membresía familiar asociadas a la compra original.
---
# File: app-store-small-business-program
---
---
title: "App Store Small Business Program"
description: "Comprende el Small Business Program de Apple, su impacto en tus ingresos y los análisis de Adapty"
---
:::link
Para el programa equivalente en Play Store, consulta [Google Reduced Service Fee](google-reduced-service-fee).
:::
Las organizaciones que reciben hasta 1 millón de USD en ingresos anuales del App Store pueden participar en el [programa Small Business](https://developer.apple.com/app-store/small-business-program/) de Apple. Si te inscribes, la comisión estándar del 30% se reduce al **15%**.
Los miembros del programa deben **cambiar su configuración en Adapty** para garantizar cálculos de ingresos correctos y el manejo adecuado de los eventos de integración.
Este artículo describe:
* [Cómo configurar Adapty](#configure-adapty) si tu app está inscrita en el Small Business Program
* [Cómo inscribirte en el programa](#apply-for-the-program) si quieres reducir tu comisión del store
## Configurar Adapty \{#configure-adapty\}
Adapty puede aplicar la comisión reducida a tus [análisis](analytics) y [eventos de integración](analytics-integration). Para activarlo, especifica tu estado en el Small Business Program por app.
:::warning
Configura tu estado en el SBP en Adapty **en cuanto recibas la aprobación**. Los cambios tardíos no pueden reescribir los eventos de webhook ya entregados ([detalles](#retroactive-setting-changes)).
:::
1. Abre [**App Settings** → **General**](https://app.adapty.io/account)
2. Busca la sección **Small Business Program**.
3. Haz clic en **Add period**.
4. Selecciona la fecha de inicio de la membresía.
5. Selecciona una fecha de fin, o activa la casilla **At the current moment** para extender este estado indefinidamente. Si en el futuro [pierdes la elegibilidad](#losing-eligibility), puedes modificar la fecha de fin.
6. Haz clic en **Apply**.
Si tu organización sigue siendo elegible para el programa, la membresía se renueva automáticamente al siguiente año natural. Sin embargo, el estado de membresía solo se aplica **al rango de fechas que especifiques**.
* Haz clic en **Add period** para añadir un nuevo período de membresía.
* Para extender este estado indefinidamente, activa la casilla **At the current moment**.
Para verificar tu configuración, abre el [gráfico de Revenue](revenue) y selecciona **Proceeds after store commission**. Confirma que los ingresos mostrados reflejan la comisión reducida.
## Inscribirse en el programa \{#apply-for-the-program\}
### Requisitos de elegibilidad \{#eligibility-requirements\}
Apple determina la elegibilidad para el SBP en función de tus **ingresos anuales** — las ventas del año natural anterior **después** de la comisión del store e impuestos.
Para ser elegible, los ingresos anuales de tu organización y sus
2. Haz clic en el botón **Create subscription**.
3. En la ventana **Create subscription** que se abre, introduce el ID de la suscripción en el campo **Product ID** y el nombre de la suscripción en el campo **Name**.
El ID del producto debe ser único, comenzar con un número o letra minúscula, y puede contener guiones bajos (\_) y puntos (.). Se utiliza para acceder a tu producto durante el desarrollo y sincronizarlo con Adapty. Una vez que se asigna un Product ID a un producto en Google Play Console, no puede reutilizarse en ninguna otra app, incluso si el producto se elimina.
Al elegir el ID del producto, es recomendable seguir un formato estandarizado. Te recomendamos usar un enfoque más conciso y nombrar el producto `
3. Una vez que se abran los detalles de la suscripción, haz clic en el botón **Add base plan** que aparece bajo el título **Base plans and offers**. Es posible que tengas que desplazarte hacia abajo para encontrarlo.
4. En la ventana **Add base plan** que se abre, introduce un identificador único para el plan base en el campo **Plan ID**. Debe comenzar con un número o letra minúscula, y puede contener números (0-9), letras minúsculas (a-z) y guiones (-). Completa también los campos obligatorios.
5. Especifica los precios por región.
6. Haz clic en el botón **Save** para finalizar la configuración.
7. Haz clic en el botón **Activate** para activar el plan base.
Ten en cuenta que los productos de suscripción solo pueden tener un único plan base con duración y tipo de renovación consistentes en Adapty.
### Productos de respaldo \{#fallback-products\}
:::warning
Compatibilidad con planes base no retrocompatibles
Las versiones antiguas de los SDK de Adapty no son compatibles con las funciones de Google Billing Library v5+, concretamente con múltiples planes base por producto de suscripción y ofertas. Solo los planes base marcados como **[backwards compatible](https://support.google.com/googleplay/android-developer/answer/12124625?hl=en#backwards_compatible)** en Google Play Console son accesibles con estas versiones del SDK. Ten en cuenta que solo un plan base por suscripción puede marcarse como retrocompatible.
:::
Para aprovechar al máximo las configuraciones y funciones mejoradas de suscripciones de Google en Adapty, ofrecemos la posibilidad de configurar un producto de respaldo retrocompatible. Este producto de respaldo se utiliza exclusivamente para apps que usan versiones antiguas del SDK de Adapty. Al crear productos de Google Play, ahora tienes la opción de indicar si el producto debe marcarse como retrocompatible en Play Console. Adapty utiliza esta información para determinar si el producto puede ser comprado por versiones antiguas del SDK (versiones 2.5 e inferiores).
Supongamos que tienes una suscripción llamada `subscription.premium` que ofrece dos planes base: semanal (retrocompatible) y mensual. Si añades el producto `subscription.premium:weekly` a Adapty, no necesitas indicar un producto retrocompatible. Sin embargo, en el caso del producto `subscription.premium:monthly`, deberás especificar un producto retrocompatible. No hacerlo podría provocar una compra no deseada del producto `subscription.premium:weekly` en la biblioteca de facturación 4 de Google. Para resolver este escenario, debes crear un producto separado donde el plan base también sea mensual y esté marcado como retrocompatible. Esto garantiza que los usuarios que seleccionen la opción `subscription.premium:monthly` sean facturados correctamente con la frecuencia prevista.
## Añadir productos a Adapty \{#add-products-to-adapty\}
Una vez que hayas completado la incorporación de tus compras in-app, suscripciones y ofertas en App Store Connect, el siguiente paso es [añadir estos productos a Adapty](create-product).
---
# File: google-play-data-safety
---
---
title: "Seguridad de datos de Google Play"
description: "Garantiza el cumplimiento de las políticas de seguridad de datos de Google Play en Adapty."
---
La sección de seguridad de datos disponible en Google Play ofrece a los desarrolladores un método sencillo para informar a los usuarios sobre los datos que su app recopila o comparte, así como destacar las medidas críticas de privacidad y seguridad. Esta información permite a los usuarios tomar decisiones más informadas al elegir qué apps descargar y usar.
Aquí tienes una guía breve sobre los datos que Adapty recopila para ayudarte a proporcionar la información requerida a Google Play.
## Recopilación y seguridad de datos \{#data-collection-and-security\}
**¿Tu app recopila o comparte alguno de los tipos de datos de usuario requeridos?**
Selecciona 'Sí', ya que Adapty recopila el historial de compras del cliente.
**¿Todos los datos de usuario recopilados por tu app están cifrados en tránsito?**
Selecciona 'Sí', ya que Adapty cifra los datos en tránsito.
**¿Ofreces a los usuarios una forma de solicitar la eliminación de sus datos?**
Si seleccionas 'Sí', asegúrate de que tus clientes tengan una forma de contactar con tu equipo de soporte para solicitar la eliminación de sus datos. Podrás eliminar al cliente directamente desde el Adapty Dashboard o mediante la API REST.
## Tipos de datos \{#data-types\}
A continuación encontrarás la lista de tipos de datos que Google requiere para el reporte, junto con la especificación de si Adapty recopila cada tipo de dato en particular.
| Tipo de dato | Detalles |
| :----------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Ubicación | Adapty no lo recopila |
| Salud y fitness | Adapty no lo recopila |
| Fotos y vídeos | Adapty no lo recopila |
| Archivos y documentos | Adapty no lo recopila |
| Calendario | Adapty no lo recopila |
| Contactos | Adapty no lo recopila |
| Contenido del usuario | Adapty no lo recopila |
| Historial de navegación | Adapty no lo recopila |
| Historial de búsqueda | Adapty no lo recopila |
| Información y rendimiento de la app | Adapty no lo recopila |
| Navegación web | Adapty no lo recopila |
| Información de contacto | Adapty no lo recopila |
| Información financiera | Adapty recopila el historial de compras de los usuarios |
| Información personal e identificadores | Adapty recopila el ID de usuario y otra información de contacto identificable, como nombre, dirección de correo electrónico, número de teléfono, etc., si los pasas explícitamente al SDK de Adapty. |
| Identificadores de dispositivo y otros | Adapty recopila datos sobre el ID del dispositivo. |
## Uso y tratamiento de datos \{#data-usage-and-handling\}
### IDs de usuario \{#user-ids\}
**1. ¿Estos datos se recopilan, se comparten o ambas cosas?**
Adapty recopila estos datos. Si usas integraciones entre Adapty y terceros que no se consideran proveedores de servicios, puede que también tengas que indicar "Compartido" aquí.
**2. ¿Estos datos se procesan de forma efímera?**
Selecciona 'No'.
**3. ¿Estos datos son obligatorios para tu app o los usuarios pueden elegir si se recopilan?**
La recopilación de estos datos es obligatoria y no se puede desactivar.
**4. ¿Por qué se recopilan estos datos de usuario? / ¿Por qué se comparten estos datos de usuario?**
Marca las casillas 'Funcionalidad de la app' y 'Análisis'.
### Información financiera \{#financial-info\}
Si usas Adapty, debes declarar que tu app recopila información sobre el 'Historial de compras' en la sección de tipos de datos de Google Play Console.
### Identificadores de dispositivo u otros \{#device-or-other-ids\}
## Pasos siguientes \{#next-steps\}
Una vez que hayas completado las selecciones de seguridad de datos, Google mostrará una vista previa de la sección de privacidad de tu app. Si has seleccionado "Información financiera" e "Identificadores de dispositivo u otros" como se mencionó anteriormente, la información de privacidad debería aparecer de forma similar al siguiente ejemplo.
Si estás listo para enviar tu app a revisión, consulta nuestro documento [Lista de verificación para el lanzamiento](release-checklist) para obtener más orientación sobre cómo preparar tu app para el envío.
---
# File: google-reduced-service-fee
---
---
title: "Tarifa de Servicio Reducida de Google"
description: "Comprende la Tarifa de Servicio Reducida de Google, su impacto en tus ingresos y los análisis de Adapty"
---
:::link
Para el programa equivalente en App Store, consulta el [Programa para Pequeñas Empresas de App Store](app-store-small-business-program).
:::
El [programa de Tarifa de Servicio Reducida](https://support.google.com/googleplay/android-developer/answer/112622?hl=en) de Google Play reduce la comisión sobre tu primer millón de USD en ganancias anuales del 30% al **15%**. Las ganancias que superen el millón de USD en el mismo año calendario se cobran a la tarifa estándar del 30%.
:::note
Desde el 1 de enero de 2022, Google cobra el 15% en todas las suscripciones de renovación automática independientemente de este programa. La Tarifa de Servicio Reducida beneficia principalmente a las compras in-app que no son suscripciones y a las apps de pago.
:::
Los miembros del programa deben **cambiar su configuración en Adapty** para garantizar cálculos de ingresos correctos y el manejo adecuado de los eventos de integración.
Este artículo describe:
* [Cómo configurar Adapty](#configure-adapty) si tu app está inscrita en el programa de Tarifa de Servicio Reducida
* [Cómo inscribirse en el programa](#enroll-in-the-program) si quieres reducir tu comisión del store
## Configurar Adapty \{#configure-adapty\}
Adapty puede aplicar la tarifa de comisión reducida a tus [análisis](analytics) y [eventos de integración](analytics-integration). Para habilitarlo, especifica tu estado en la Tarifa de Servicio Reducida para cada app por separado.
:::warning
Configura tu estado de Tarifa de Servicio Reducida en Adapty **en cuanto te inscribas**. Los cambios posteriores no pueden reescribir los eventos de webhook ya entregados ([detalles](#retroactive-setting-changes)).
:::
1. Abre [**App Settings** → **General**](https://app.adapty.io/account).
2. Busca la sección **Reduced Service Fee**.
3. Haz clic en **Add period**.
4. Selecciona la fecha de inicio de la membresía.
5. Selecciona una fecha de fin, o activa la casilla **At the current moment** para extender este estado indefinidamente. Si tus [ganancias anuales superan el millón de USD](#exceeding-the-threshold), puedes modificar la fecha de fin.
6. Haz clic en **Apply**.
El estado de membresía solo se aplica **al rango de fechas que especifiques**. El programa se reinicia cada año calendario.
* Haz clic en **Add period** para añadir un nuevo período de membresía.
* Para extender este estado indefinidamente, activa la casilla **At the current moment**.
Para verificar tu configuración, abre el [gráfico de Ingresos](revenue) y selecciona **Proceeds after store commission**. Confirma que los ingresos mostrados reflejan la tarifa de comisión reducida.
## Inscribirse en el programa \{#enroll-in-the-program\}
### Requisitos de elegibilidad \{#eligibility-requirements\}
Google determina la elegibilidad en función de tus **ganancias anuales** en todas las cuentas de tu | Opción | Descripción | | ------- | ------------------------------------------------------------ | | Opt-out | (predeterminado) Si Adapty no conoce el estado de consentimiento del usuario, asume que el consentimiento **fue otorgado** y Refund Saver **compartirá** los datos relacionados con reembolsos con Apple. | | Opt-in | Si Adapty no conoce el estado de consentimiento del usuario, asume que el consentimiento **no fue otorgado** y Refund Saver **no compartirá** ningún dato con Apple. Este es el enfoque recomendado por Apple. | ## Actualizar el consentimiento del usuario en el SDK \{#update-user-consent-in-the-sdk\} Para indicarle a Adapty si un usuario específico ha dado su consentimiento, usa el método `updateCollectingRefundDataConsent`. El valor persiste en el servidor por perfil, por lo que solo necesitas llamarlo cuando el consentimiento cambie.
:::note Para registrar eventos de suscripción, usa la integración [Webhook](webhook) en Adapty o intégrala directamente con tu servicio existente. ::: ## Caso 1: Sincronizar suscriptores entre web y móvil \{#case-1-sync-subscribers-between-web-and-mobile\} Si utilizas proveedores de pago web como Stripe, ChargeBee u otros, puedes sincronizar a tus suscriptores fácilmente. Así es como funciona: 1.
2. Crea un nombre descriptivo para tu onboarding y haz clic en **Proceed to build onboarding**.
3. Serás redirigido al constructor de onboarding.
Contiene una plantilla de demostración predeterminada que puedes estudiar para entender cómo los onboardings recopilan datos y cómo puedes personalizarlos usando variables y cuestionarios. Siéntete libre de eliminar las pantallas que no necesites y [diseña tu propia experiencia de onboarding](design-onboarding) allí.
4. Cuando estés listo, haz clic en el botón **Preview** en la parte superior derecha. Completa tu onboarding flow tú mismo para asegurarte de que todo funciona correctamente.
5. Si todo funciona bien, haz clic en **Publish** en la parte superior derecha. Espera a que se publique antes de volver a Adapty. De lo contrario, perderás tu progreso.
:::danger
Si no haces clic en **Publish**, el SDK no podrá obtener el onboarding que has creado.
:::
Una vez publicado el onboarding, haz clic en **Back to Adapty**. Tu onboarding está creado y puedes añadirlo a un placement para empezar a usarlo.
## Paso 2. Crea un placement para tu onboarding \{#step-2-create-a-placement-for-your-onboarding\}
1. Ve a **Placements** desde el menú principal y cambia a la pestaña **Onboardings**. Haz clic en **Create placement**.
2. Introduce el nombre y el ID del placement. Luego, haz clic en **Run onboarding** y selecciona el onboarding que verán todos los usuarios.
3. Si tienes un onboarding preparado para un grupo específico de usuarios, [añade más audiencias](audience) y selecciona un onboarding diferente para ellas.
## Paso 3. Integra el onboarding en tu app \{#step-3-integrate-the-onboarding-into-your-app\}
:::important
Los onboardings están disponibles para apps que usen el SDK de Adapty v3.8.0+ (iOS, Android, React Native, Flutter), v3.14.0+ (Unity) o v3.15.0+ (Kotlin Multiplatform, Capacitor).
:::
Para empezar a mostrar onboardings en tu app, intégralos mediante el SDK de Adapty:
- [iOS](ios-onboardings)
- [Android](android-onboardings)
- [React Native](react-native-onboardings)
- [Flutter](flutter-onboardings)
- [Unity](unity-onboardings)
- [Kotlin Multiplatform](kmp-onboardings)
- [Capacitor](capacitor-onboardings)
Para entender qué onboarding funciona mejor, también puedes ejecutar [pruebas A/B](ab-tests).
---
# File: design-onboarding
---
---
title: "Diseñar onboardings"
description: "Crea onboardings significativos."
---
El onboarding builder sin código para aplicaciones móviles es una herramienta potente y personalizable que te ayudará a ofrecer a tus usuarios la mejor experiencia de onboarding. No necesitas ser desarrollador ni diseñador para obtener un gran resultado.
## Pantallas del onboarding \{#onboarding-screens\}
El flow de onboarding consta de varias pantallas que añades y diseñas.
Los usuarios navegarán entre ellas tocando el botón.
:::tip
Si algunos de tus usuarios necesitan un flow ligeramente diferente (por ejemplo, en una app de fitness podrías querer mostrar distintas imágenes de 'objetivo' según el género del usuario), no hace falta que crees onboardings separados.
En su lugar, puedes ocultar algunas pantallas por defecto y mostrarlas solo en determinados escenarios.
:::
## Elementos del onboarding \{#onboarding-elements\}
Los elementos del onboarding se muestran a la izquierda en el orden en que aparecen. Haz clic en **Add** arriba a la derecha para añadir un nuevo elemento.
Estos son los grupos de elementos disponibles:
- **Containers**: Los contenedores permiten configurar un diseño flexible. Por ejemplo, si quieres añadir texto en dos columnas, añade **Columns** y arrastra dos bloques de texto dentro de **Columns** en el panel izquierdo. O, si añades un carrusel, tendrás que agregar imágenes a los elementos **Media** que contiene.
- **Typography**: Añade bloques de texto preformateados y configura su apariencia según tus necesidades.
- **Media & Display**: Además de imágenes y vídeos, puedes añadir gráficos animados que muestren el valor de tu app y animen a los usuarios.
Los **formatos de vídeo compatibles** son MP4 y WebM. El **tamaño máximo de archivo multimedia** es de 15 MB.
Si quieres añadir un elemento animado no compatible (como Lottie), puedes convertirlo a vídeo (por ejemplo, con [esta herramienta](https://www.lottielab.com/lottie/lottie-to-video)) e insertarlo como vídeo.
- **Quiz**: Crea cuestionarios breves con opciones de texto e imagen para personalizar la experiencia de onboarding y conocer mejor a tus usuarios.
- **Inputs**: Recoge datos de tus usuarios.
- **Buttons**: Los botones permiten a los usuarios navegar entre pantallas, cerrar el onboarding o ir al paywall. También puedes añadir botones brillantes o animados para captar la atención del usuario y convertir su instalación en una compra.
- **Loaders**: Los loaders animados mantienen a los usuarios entretenidos durante el proceso.
- **User engagement**: Añade testimonios, listas de correos de usuarios y cuenta atrás.
:::note
Como parte del grupo **Media & Display**, también puedes añadir código HTML personalizado si las opciones de personalización disponibles no son suficientes.
Sin embargo, los elementos HTML personalizados no se precargan ni se cachean, por lo que se recomienda usar **Raw HTML** solo para elementos pequeños y ligeros.
:::
### ID de elemento e ID de acción \{#element-id-and-action-id\}
Si quieres usar un botón para acciones personalizadas, asígnale un **action ID** y úsalo en tu código fuente. Los action ID permiten gestionar de la misma manera distintos botones que comparten el mismo ID.
Si quieres procesar la entrada del usuario en un campo concreto (por ejemplo, guardar su edad o correo electrónico), asígnale un **element ID** y úsalo en tu código fuente para asociar preguntas con respuestas. Los element ID solo pueden usarse una vez en tu onboarding.
## Opciones de personalización \{#customization-options\}
El builder ofrece las siguientes opciones de personalización:
- Pestaña **Styles**: Ajusta la apariencia del elemento.
- Pestaña **Element**: Configura los atributos del elemento, como la visibilidad, las acciones al pulsar botones u otras propiedades no relacionadas con su apariencia.
- Pestaña **Screen**: Configura los ajustes generales de la pantalla, como una cabecera o la visualización de un contador de pantallas.
## Copiar pantallas y elementos \{#copy-screens-and-elements\}
Si has creado un onboarding y quieres reutilizar partes del mismo, o si deseas hacer pequeños cambios y ejecutar pruebas A/B, puedes copiar una o más pantallas de un onboarding a otro.
Para copiar pantallas, abre el onboarding builder y realiza una de estas acciones:
- Haz clic derecho en una pantalla y selecciona **Copy**
- Selecciona la pantalla que quieres y pulsa `Ctrl+C` (Windows) o `⌘+C` (Mac)
También puedes copiar elementos individuales o bloques de texto, ya sea dentro del mismo onboarding o entre onboardings distintos.
## Copiar pantallas desde funnels web-to-app \{#copy-screens-from-web-to-app-funnels\}
Si usas funnels web-to-app creados en [FunnelFox](https://funnelfox.com/) y quieres utilizar pantallas de esos funnels en onboardings, puedes hacerlo fácilmente copiando las pantallas en el funnel builder y pegándolas en el onboarding builder:
1. En el funnel builder de FunnelFox, haz clic derecho en una pantalla y selecciona **Copy**, o selecciónala y pulsa `Ctrl+C`/`⌘+C`.
2. Abre el onboarding builder.
3. Haz clic derecho en la pantalla donde quieres insertar la pantalla copiada y selecciona **Paste**, o selecciónala y pulsa `Ctrl+V`/`⌘+V`. La pantalla copiada se insertará debajo de la pantalla seleccionada.
---
# File: adapty-paywall-builder
---
---
title: "Adapty Paywall Builder (Legacy)"
description: "Crea paywalls y flows de onboarding con el constructor visual sin código."
---
:::warning
El Paywall Builder es completamente funcional, pero Adapty ya no añade nuevas funciones ni publica actualizaciones para él. Para nuevos proyectos, considera el [Adapty Flow Builder](adapty-flow-builder) — un editor visual sin código para paywalls de una sola pantalla y flows de onboarding multipantalla que se renderizan de forma nativa en el dispositivo:
- **Cualquier tipo de flow**: Crea paywalls de una sola pantalla, onboardings de varios pasos que incluyen un paywall, y cualquier cosa intermedia.
- **Renderizado nativo**: Los flows se renderizan a través del SDK de Adapty, sin web views.
- **Actualiza sin redesplegar**: Cambia textos, diseño o lógica en cualquier momento, y los cambios llegan a los usuarios sin necesidad de publicar una nueva versión de la app.
:::
El **Paywall Builder** de Adapty es una herramienta visual sin código para diseñar paywalls personalizados. Puedes empezar desde una plantilla, personalizar el diseño y añadir elementos como carruseles, tarjetas, listas de productos y pies de página. El builder también admite fuentes personalizadas, etiquetas de productos y localización.
El Paywall Builder requiere el SDK de Adapty v3.0 o posterior. Una vez que hayas diseñado un paywall, [añádelo a un placement](add-audience-paywall-ab-test) y muéstralo en tu app:
- [iOS](ios-quickstart-paywalls)
- [Android](android-quickstart-paywalls)
- [React Native](react-native-quickstart-paywalls)
- [Flutter](flutter-quickstart-paywalls)
- [Unity](unity-quickstart-paywalls)
- [Capacitor](capacitor-quickstart-paywalls)
- [Kotlin Multiplatform](kmp-quickstart-paywalls)
---
# File: flutterflow
---
---
title: "Plugin de Adapty para FlutterFlow"
description: "Integra FlutterFlow con Adapty para una gestión de suscripciones mejorada."
---
Adapty es una plataforma versátil diseñada para ayudar a las apps móviles a crecer. Tanto si estás empezando como si ya tienes miles de usuarios, Adapty te permite ahorrar meses en la integración de compras in-app y duplicar los ingresos por suscripciones con la gestión de paywalls.
El plugin de Adapty para FlutterFlow te permite aprovechar todas las funciones de Adapty sin escribir ni una línea de código. Puedes diseñar páginas de paywall en FlutterFlow, habilitar las compras en ellas y luego controlar de forma remota qué productos se muestran, incluyendo la segmentación por grupos de usuarios o las pruebas A/B. Y una vez que publiques tu app, tendrás acceso inmediato a analíticas detalladas de las compras de tus clientes directamente en nuestro dashboard.
¿Quieres actualizar los productos disponibles en tu paywall? ¡Es muy sencillo! Haz los cambios en unos pocos clics dentro del Adapty Dashboard y tus clientes verán los nuevos productos de inmediato, sin necesidad de publicar una nueva versión de la app.
Qué más te ofrece Adapty:
- **Suscripciones y compras in-app**: Adapty se encarga de la validación de recibos en el servidor y sincroniza a tus clientes en todas las plataformas, incluida la web.
- **Pruebas A/B para paywalls**: Prueba diferentes precios, duraciones, períodos de prueba y elementos visuales para optimizar tus ofertas de suscripción y de compra única.
- **Analíticas potentes**: Accede a métricas detalladas para entender mejor la monetización de tu app y mejorarla.
- **Integraciones**: Adapty se conecta sin problemas con herramientas de analítica de terceros como Amplitude, AppsFlyer, Adjust, Branch, Mixpanel, Facebook Ads, AppMetrica, Webhooks personalizados y mucho más.
---
# File: ff-getting-started
---
---
title: "Primeros pasos"
description: "Empieza con los Feature Flags de Adapty para personalizar los flujos de suscripción."
---
Con Adapty puedes crear y ejecutar paywalls y pruebas A/B en distintos momentos del recorrido del usuario en tu app móvil, como en el onboarding, en los ajustes, etc. Estos puntos se llaman [Placements](placements). Un placement en tu app puede gestionar varios paywalls o [pruebas A/B](ab-tests) a la vez, cada uno diseñado para un grupo concreto de usuarios, lo que denominamos [Audiencias](audience). Además, puedes experimentar con los paywalls, sustituyendo uno por otro a lo largo del tiempo sin publicar una nueva versión de la app. Lo único que tienes que escribir directamente en el código de la app es el ID del placement.
La biblioteca de Adapty mantiene tu paywall actualizado con los últimos productos de tu Adapty Dashboard. [Obtiene los datos de los productos](ff-action-flow) y [los muestra en tu paywall](ff-add-variables-to-paywalls), [gestiona las compras](ff-make-purchase) y [comprueba el nivel de acceso del usuario](ff-check-subscription-status) para determinar si debe recibir contenido de pago.
Para empezar, solo tienes que [añadir la biblioteca de Adapty](ff-getting-started#add-the-adapty-library-as-a-dependency) a tu proyecto de FlutterFlow e [inicializarla](ff-getting-started#initiate-adapty-plugin) como se muestra a continuación.
:::warning
Antes de comenzar, ten en cuenta las siguientes limitaciones:
- La biblioteca de Adapty para FlutterFlow no es compatible con aplicaciones web. Evita compilar aplicaciones web con ella.
- La biblioteca de Adapty para FlutterFlow no es compatible con paywalls creados con el Paywall Builder de Adapty. Tienes que diseñar tu propio paywall en FlutterFlow antes de habilitar las compras con Adapty.
:::
## Añadir la biblioteca de Adapty como dependencia \{#add-the-adapty-library-as-a-dependency\}
1. En el [FlutterFlow Dashboard](https://app.flutterflow.io/dashboard), abre tu proyecto y haz clic en **Settings and Integrations** en el menú de la izquierda. En la sección **Project setup** a la izquierda, selecciona **Project dependencies**.
2. En la sección **FlutterFlow Libraries**, haz clic en **Add Library** e introduce `adapty-xtuel0`. Haz clic en **Add**.
3. Ahora debes asociar tu clave SDK con la biblioteca. Haz clic en **View details** junto a la biblioteca.
4. Copia la **Public SDK key** desde la pestaña [**App Settings** -> **General**](https://app.adapty.io/settings/general) en el Adapty Dashboard.
5. Pega la clave en **AdaptyApiKey** en FlutterFlow.
La biblioteca de Adapty FF se añadirá como dependencia a tu proyecto. En la ventana de la biblioteca **Adapty** FF encontrarás todos los recursos de Adapty que se han importado a tu proyecto.
## Llamar a la nueva acción de activación al iniciar la aplicación \{#call-the-new-activation-action-at-application-launch\}
1. Ve a la sección **Custom Code** en el menú de la izquierda y abre `main.dart`.
2. Haz clic en **+** y selecciona `activate (Adapty)`.
3. Haz clic en **Save**.
## Inicializar el plugin de Adapty \{#initiate-adapty-plugin\}
Para que el Adapty Dashboard reconozca tu app, deberás proporcionar una clave especial en FlutterFlow.
1. En tu proyecto de FlutterFlow, ve a **Settings and Integrations > Permissions** en el menú de la izquierda.
2. En la ventana **Permissions** que se abre, haz clic en el botón **Add Permission**.
3. En los campos **iOS Permission Key** y **Android Permission Key**, pega `AdaptyPublicSdkKey`.
4. Para el campo **Permission Message**, copia la **Public SDK key** desde la pestaña [**App Settings** -> **General**](https://app.adapty.io/settings/general) en el Adapty Dashboard. Cada app tiene su propia clave SDK, así que si tienes varias apps, asegúrate de coger la correcta.
Tras completar estos pasos, podrás mostrar tu paywall en tu app de FlutterFlow y habilitar las compras a través de él.
## ¿Qué sigue? \{#whats-next\}
1. [Crea un flujo de acción](ff-action-flow) para gestionar los productos del paywall de Adapty y sus datos en FlutterFlow.
2. [Mapea los datos recibidos en el paywall](ff-add-variables-to-paywalls) que diseñaste en FlutterFlow.
3. [Configura el botón de compra](ff-make-purchase) en tu paywall para procesar las transacciones a través de Adapty cuando se pulse.
4. Por último, [añade comprobaciones del estado de la suscripción](ff-check-subscription-status) para determinar si mostrar contenido de pago al usuario.
---
# File: ff-action-flow
---
---
title: "Paso 1. Crear el flujo para mostrar los datos del paywall"
description: "Configura los flujos de acción de feature flags en Adapty para personalizar los journeys de suscripción de los usuarios."
---
:::important
Al usar el plugin de FlutterFlow, no puedes usar paywalls creados en el Paywall Builder de Adapty. Debes implementar tu propia página de paywall en FlutterFlow y conectarla a Adapty.
:::
Después de añadir la librería de Adapty como dependencia a tu proyecto de FlutterFlow, es momento de construir el flujo que **recupera los datos del paywall y los productos de Adapty, y los muestra en el paywall que has diseñado en FlutterFlow**.
Primero necesitamos recibir los datos del paywall desde Adapty. Empezaremos solicitando el paywall de Adapty, luego sus productos asociados, y finalmente comprobaremos si los datos se recibieron correctamente. Si es así, mostraremos el título y el precio del producto en la página del paywall. En caso contrario, mostraremos un mensaje de error.
Antes de continuar, asegúrate de haber hecho lo siguiente:
1. [Crear al menos un paywall y añadir al menos un producto](create-paywall) en el Adapty Dashboard.
2. [Crear al menos un placement](create-placement) y [añadir tu paywall](add-audience-paywall-ab-test) en el Adapty Dashboard.
¡Empecemos!
## Paso 1.1. Solicitar el paywall de Adapty \{#step-11-request-adapty-paywall\}
Como se mencionó, para mostrar datos en tu paywall de FlutterFlow, primero necesitamos recuperarlos desde Adapty. El primer paso es obtener el paywall de Adapty. Así se hace:
1. Abre tu pantalla de paywall y cambia a la sección **Actions** en el panel derecho. Ahí, abre el **Action Flow Editor**.
2. En la ventana **Select Action Trigger**, selecciona **On Page Load**.
3. Haz clic en **Add Action**. Luego, busca la acción personalizada `getPaywall` y selecciónala.
4. En la sección **Set Actions Arguments**, introduce el ID real del [placement que has creado](create-placement) en el Adapty Dashboard que incluye el paywall. En este ejemplo es `monthly`. ¡Asegúrate de usar tu ID de placement real!
5. Si has [localizado](localizations-and-locale-codes) tu paywall en el dashboard de Adapty, también puedes configurar el argumento **locale**.
6. En **Action Output Variable Name**, crea una nueva variable y nómbrala `getPaywallResult`. La usaremos en el siguiente paso para referenciar el paywall de Adapty y solicitar sus productos.
## Paso 1.2. Solicitar los productos del paywall de Adapty \{#step-12-request-adapty-paywall-products\}
¡Genial! Ya hemos recuperado el paywall de Adapty. Ahora, obtengamos los productos asociados a este paywall:
1. Haz clic en **+** bajo la acción creada y selecciona **Add Action**. Esta acción recibirá los productos del paywall de Adapty. Para ello, busca y selecciona `getPaywallProducts`.
2. En la sección **Set Actions Arguments**, selecciona la variable `getPaywallResult` creada anteriormente.
3. Rellena los demás campos de la siguiente manera:
- **Available Options**: Data Structured Field
- **Select Field**: value
- **Available Options**: No further changes
4. Haz clic en **Confirm**.
5. En **Action Output Variable Name**, crea una nueva variable y nómbrala `getPaywallProductsResult`. La usaremos para vincular el paywall que diseñaste en FlutterFlow con los datos del paywall de Adapty.
## Paso 1.3. Añadir comprobación de si el paywall se cargó correctamente \{#step-13-add-check-if-the-paywall-uploaded-successfully\}
Antes de continuar, verifiquemos que el paywall de Adapty se recibió correctamente. Si es así, podemos actualizar el paywall con los datos de los productos. Si no, gestionaremos el error. Así se añade la comprobación:
1. Haz clic en **+** y luego en **Add Conditional**.
2. En la sección **Action Output**, selecciona la variable de salida de acción creada anteriormente (`getPaywallResult` en nuestro ejemplo).
3. Para verificar que el paywall de Adapty se recibió, comprueba la presencia de un campo con valor. Rellena los campos de la siguiente manera:
- **Available Options**: Has Field
- **Field (AdaptyGetPaywallResult)**: value
4. Haz clic en **Confirm** para finalizar la condición.
## Paso 1.4. Registrar la visualización del paywall \{#step-14-log-the-paywall-review\}
Para asegurarte de que los análisis de Adapty registran la visualización del paywall, necesitamos registrar este evento. Sin este paso, la visualización no se contabilizará en los análisis. Así se hace:
1. Haz clic en **+** bajo la etiqueta **TRUE** y haz clic en **Add Action**.
2. En el campo **Select Action**, busca y elige **logShowPaywall**.
3. Haz clic en **Value** en el área **Set Action Arguments** y elige la variable `getPaywallResult` que hemos creado. Esta variable contiene los datos del paywall.
4. Rellena los campos de la siguiente manera:
- **Available Options**: Data Structured Field
- **Select Field**: value
5. Haz clic en **Confirm**.
## Paso 1.5. Mostrar error si el paywall no se recibe \{#step-15-show-error-if-paywall-not-received\}
Si el paywall de Adapty no se recibe, necesitas [gestionar el error](error-handling-on-flutter-react-native-unity#system-storekit-codes). En este ejemplo, simplemente mostraremos un mensaje de alerta.
1. Añade una acción **Informational Dialog** a la etiqueta **FALSE**.
2. En el campo **Title**, añade el texto que quieras ver como título del diálogo. En este ejemplo, es **Error**.
3. Haz clic en **Value** en el cuadro **Message**.
4. Rellena los campos de la siguiente manera:
- **Set Variable**: variable `getPaywallProductResult` que hemos creado
- **Available Options**: Data Structure Field
- **Select Field**: error
- **Available Options**: Data Structure Field
- **Select Field**: errorMessage
5. Haz clic en **Confirm**.
6. Añade una acción **Terminate action** al flujo **FALSE**.
7. Haz clic en **Close** en la esquina superior derecha.
¡Felicidades! Has recibido correctamente los datos del producto. Ahora, [vincúlalos al paywall que has diseñado en FlutterFlow](ff-add-variables-to-paywalls).
---
# File: ff-add-variables-to-paywalls
---
---
title: "Paso 2. Añadir datos a la página del paywall"
description: "Añade variables de Feature Flag a los paywalls en Adapty."
---
Una vez que hayas [recibido todos los datos de producto necesarios](ff-action-flow), es hora de mapearlos al bonito paywall que diseñaste en FlutterFlow. En este ejemplo, mapearemos el título del producto y su precio.
## Paso 2.1. Añadir el título del producto a la página del paywall \{#step-21-add-product-title-to-paywall-page\}
1. Haz doble clic en el texto del producto en tu página del paywall. En la ventana **Set from Variable**, busca la variable `getPaywallProductResult` y selecciónala.
2. Rellena los campos de la siguiente manera:
- **Available Options**: Data Structured Field
- **Select Field**: value
- **Available Options**: Item at Index
- **List Index Options**: First
- **Available Options**: Data Structured Field
- **Select Field**: localizedTitle
- **Default Variable Value**: null
- **UI Builder Display Value**: Cualquier valor; en el ejemplo es `product.title`
3. Haz clic en **Confirm** para guardar los cambios.
## Paso 2.2. Añadir el texto del precio a la página del paywall \{#step-22-add-price-text-to-paywall-page\}
Repite los pasos del Paso 2.1 para el texto del precio como se muestra a continuación:
1. Haz doble clic en el texto del precio en tu página del paywall. En la ventana **Set from Variable**, busca la variable `getPaywallProductResult` y selecciónala.
2. Rellena los campos de la siguiente manera:
- **Available Options**: Data Structured Field
- **Select Field**: value
- **Available Options**: Item at Index
- **List Index Options**: First
- **Available Options**: Data Structured Field
- **Select Field**: price
- **Default Variable Value**: null
- **UI Builder Display Value**: Cualquier valor; en el ejemplo es `product.price`
3. Haz clic en el botón **Confirm** para guardar los cambios.
### Añadir el precio en moneda local a la página del paywall \{#add-price-in-local-currency-to-paywall-page\}
1. Haz doble clic en el precio en tu página del paywall. En la ventana **Set from Variable**, busca la variable `getPaywallProductResult` y selecciónala.
2. Rellena los campos de la siguiente manera:
- **Available Options**: Data Structured Field
- **Select Field**: value
- **Available Options**: Item at Index
- **List Index Options**: First
- **Available Options**: Data Structured Field
- **Select Field**: price
- **Available Options**: Data Structured Field
- **Select Field**: amount
- **Available Options**: Decimal
- **Decimal Type**: Automatic
- **Default Variable Value**: null
- **UI Builder Display Value**: Cualquier valor; en el ejemplo es `price.amount`
3. Haz clic en **Confirm** para guardar los cambios.
¡Y voilà! Ahora, al lanzar tu app, mostrará los datos del producto del paywall de Adapty directamente en tu página del paywall.
Es hora de [permitir que tus usuarios compren este producto](ff-make-purchase).
---
# File: ff-make-purchase
---
---
title: "Paso 3. Habilitar la compra"
description: "Aprende a realizar compras usando el sistema de Feature Flags de Adapty."
---
¡Enhorabuena! Ya has [configurado tu paywall para mostrar datos de productos de Adapty](ff-add-variables-to-paywalls), incluyendo el título y el precio del producto.
Ahora vamos al paso final: permitir que los usuarios realicen una compra a través del paywall.
## Paso 3.1. Permitir que los usuarios realicen compras \{#step-31-enable-users-to-make-purchases\}
1. Haz doble clic en el botón de compra de tu página del paywall. En el panel derecho, abre la sección **Actions** si no está ya abierta.
2. Abre el **Action Flow Editor**.
3. En la ventana **Select Action Trigger**, elige **On Tap**.
4. En la ventana **No Actions Created**, haz clic en **Add Action**. Busca la acción `makePurchase` y selecciónala.
5. En la sección **Set Actions Arguments**, selecciona la variable `getPaywallProductsResult` creada anteriormente.
6. Rellena los campos de la siguiente manera:
- **Available Options**: Data Structure Field
- **Select Field**: value
- **Available Options**: Item at Index
- **List Index Options**: First
7. Haz clic en `subscriptionUpdateParameters`, busca `AdaptySubscriptionUpdateParameters` y selecciónalo. Haz clic en **Confirm**.
:::info
Por defecto, puedes dejar todos los campos del objeto vacíos. Necesitarás rellenarlos para reemplazar una suscripción por otra en apps de Android. Lee más [aquí](https://android.adapty.io/adapty/com.adapty.models/-adapty-subscription-update-parameters/).
:::
8. Haz clic en **Confirm**.
9. En **Action Output Variable Name**, crea una nueva variable y nómbrala `makePurchaseResult`; se usará más adelante para confirmar que la compra fue exitosa.
## Paso 3.2. Comprobar si la compra fue exitosa \{#step-32-check-if-the-purchase-was-successful\}
Ahora configuremos una comprobación para ver si la compra se realizó correctamente.
1. Haz clic en **+** y luego en **Add Conditional**.
2. En **Set Condition for Action**, selecciona la variable `makePurchaseResult`.
3. En la ventana **Set Variable**, rellena los campos de la siguiente manera:
- **Available Options**: Has Field
- **Select Field**: profile
4. Haz clic en **Confirm**.
## Paso 3.3. Abrir el contenido de pago \{#step-33-open-paid-content\}
Si la compra es exitosa, puedes desbloquear el contenido de pago. Aquí te explicamos cómo configurarlo:
1. Haz clic en **+** bajo la etiqueta **TRUE** y haz clic en **Add Action**.
2. En el campo **Define Action**, busca y selecciona la página que quieres abrir en la lista **Navigate To**. En este ejemplo, la página es **Questions**.
## Paso 3.4. Mostrar un mensaje de error si la compra falla \{#step-34-show-error-message-if-purchase-failed\}
Si la compra falla, vamos a mostrar una alerta al usuario.
1. Añade una acción **Informational Dialog** a la etiqueta **FALSE**.
2. En el campo **Title**, introduce el texto que quieras para el título del diálogo, como **Purchase Failed**.
3. Haz clic en **Value** en el cuadro **Message**. En la ventana **Set from Variable**, busca `makePurchaseResult` y selecciónalo. Rellena los campos de la siguiente manera:
- **Available Options**: Data Structure Field
- **Select Field**: error
- **Available Options**: Data Structure Field
- **Select Field**: errorMessage
4. Haz clic en **Confirm**.
5. Añade una acción **Terminate** al flujo **FALSE**.
6. Por último, haz clic en **Close** en la esquina superior derecha.
¡Enhorabuena! Tus usuarios ya pueden comprar tus productos. Como paso adicional, vamos a [configurar una comprobación del acceso del usuario al contenido de pago](ff-check-subscription-status) en otros puntos de la app para decidir si mostrarles el contenido de pago o el paywall.
---
# File: ff-check-subscription-status
---
---
title: "Paso 4. Verificar el acceso al contenido de pago"
description: "Aprende a verificar el estado de la suscripción usando los feature flags de Adapty para una mejor segmentación de usuarios."
---
Para determinar si un usuario tiene acceso a contenido de pago específico, debes verificar su nivel de acceso. Esto implica comprobar si el usuario tiene al menos un nivel de acceso y si ese nivel es el requerido.
Puedes hacerlo consultando el perfil del usuario, que contiene todos los niveles de acceso disponibles.
Ahora, vamos a permitir que los usuarios compren tu producto:
1. Haz doble clic en el botón que debe mostrar el contenido de pago y abre la sección **Actions** en el panel derecho si no está ya abierta.
2. Abre el **Action Flow Editor**.
3. En la ventana **Select Action Trigger**, elige **On Tap**.
4. En la ventana **No Actions Created**, haz clic en el botón **Add Conditional Action**.
5. Haz clic en **UNSET** para establecer los argumentos de la acción y elige la variable `currentProfile`. Esta es la variable de Adapty que almacena los datos del perfil del usuario actual.
6. Rellena los campos de la siguiente manera:
- **Available Options**: Data Structure Field
- **Select Field**: accessLevels
- **Available Options**: Filter List Items
- **Filter Conditions**:
1. Selecciona **Conditions -> Single Condition** y haz clic en **UNSET**.
2. En el campo **First value**, selecciona **Item in list** como **Source** y rellena los campos así:
- **Available Options**: Data Structure Field
- **Select Field**: accessLevelIdentifier
3. Establece el operador de filtro en **Equal to**.
4. Haz clic en **UNSET** junto a **Second value** y en el campo **Value**, introduce el ID de tu nivel de acceso; en nuestro ejemplo usamos `premium`.
5. Haz clic en **Confirm** y continúa rellenando los demás campos.
- **Available Options**: Item at Index
- **List Index Options**: First
- **Available Options**: Data Structure Field
- **Select Field**: accessLevel
- **Available Options**: Data Structure Field
- **Select Field**: isActive
7. Haz clic en **Confirm**.
Ahora, añade las acciones para lo que ocurre a continuación: si el usuario tiene la suscripción correcta o no. Llévalo a la página disponible para suscriptores premium o abre la página del paywall para que pueda comprar el acceso.
---
# File: ff-resources
---
---
title: "Acciones y tipos de datos del plugin FlutterFlow de Adapty"
description: "Accede a los recursos de indicadores de funciones de Adapty para agilizar las funciones basadas en suscripciones."
---
## Acciones personalizadas \{#custom-actions\}
A continuación se muestran los métodos de Adapty disponibles en FlutterFlow con el plugin de Adapty. Pueden usarse como acciones personalizadas en FlutterFlow.
| Custom Action | Description | Action Arguments | Adapty Data Types - Action Output Variable |
|---|----|--------|----|
| activate | Inicializa el SDK de Adapty | None ||
| getPaywall
| Obtiene un paywall. No devuelve los productos del paywall. Usa la acción `getPaywallProducts` para obtener los productos reales |getPaywallProducts
| Devuelve una lista de los productos reales del paywall | [AdaptyPaywall](ff-resources#adaptypaywall) | [AdaptyGetProductsResult](ff-resources#adaptygetproductsresult) | |getProductsIntroductoryOfferEligibility
| Comprueba si el usuario cumple los requisitos para una oferta introductoria de suscripción iOS | [AdaptyPaywallProduct](product) | [AdaptyGetIntroEligibilitiesResult](ff-resources#adaptygetintroeligibilitiesresult) | |makePurchase
| Completa una compra y desbloquea el contenido. Si el paywall tiene una oferta promocional, Adapty la aplica automáticamente en el proceso de pago |getProfile
|Obtiene el perfil del usuario actual de la app. Esto te permite configurar niveles de acceso y otros parámetros
Si falla (por ejemplo, por falta de conexión), se devolverán los datos en caché. Adapty actualiza regularmente la caché del perfil para mantener la información lo más actualizada posible
| None| [AdaptyGetProfileResult](ff-resources#adaptygetprofileresult) | | updateProfile | Modifica atributos opcionales del perfil del usuario actual, como correo electrónico, número de teléfono, etc. Posteriormente puedes usar estos atributos para crear [segmentos](segments) de usuarios o simplemente consultarlos en el CRM | El ID y cualquier parámetro que deba actualizarse en el [AdaptyProfile](ff-resources#adaptyprofile) | [AdaptyError](ff-resources#adaptyerror) (Optional) | | restorePurchases | Restaura todas las compras realizadas por el usuario | None | [AdaptyGetProfileResult](ff-resources#adaptygetprofileresult) | | logShowPaywall | Registra cuándo se muestra un paywall concreto al usuario | [AdaptyPaywall](ff-resources#adaptypaywall) | [AdaptyError](ff-resources#adaptyerror) (Optional) | | identify | Identifica al usuario mediante el `customerUserId` de tu sistema | customerUserId | [AdaptyError](ff-resources#adaptyerror) (Optional) | | logout | Cierra la sesión del usuario actual en tu app | None | [AdaptyError](ff-resources#adaptyerror) (Optional)| | presentCodeRedemptionSheet | Muestra una hoja que permite a los usuarios canjear códigos (solo iOS) | None | None | ## Tipos de datos \{#data-types\} Tipos de datos de Adapty (colecciones de valores de datos) entregados a FlutterFlow con el plugin de Adapty. ### AdaptyAccessLevel Información sobre el [nivel de acceso](access-level) del usuario. | Nombre del campo | Tipo | Descripción | |--------------------------|----------|-------------| | activatedAt | DateTime | La hora en que este nivel de acceso fue activado | | activeIntroductoryOfferType | String | El tipo de oferta introductoria activa. Si está definido, significa que se aplicó una oferta durante este período de suscripción | | activePromotionalOfferId | String | El ID de una oferta promocional activa (comprada desde iOS) | | activePromotionalOfferType | String | El tipo de oferta promocional activa (comprada desde iOS). Si está definido, significa que se aplicó una oferta durante este período de suscripción | | billingIssueDetectedAt | DateTime | La hora en que se detectó un problema de facturación. La suscripción puede seguir activa. Se establece en null si el pago se procesa correctamente | | cancellationReason | String | El motivo por el que se canceló la suscripción | | expiresAt | DateTime | La hora de expiración del nivel de acceso (puede ser en el pasado o no estar definida para el acceso de por vida) | | id | String | El identificador del nivel de acceso | | isActive | Boolean | True si este nivel de acceso está activo. En general, puedes consultar esta propiedad para determinar si un usuario tiene acceso a las funciones premium | | isInGracePeriod | Boolean | True si esta suscripción de renovación automática está en el [período de gracia](https://developer.apple.com/help/app-store-connect/manage-subscriptions/enable-billing-grace-period-for-auto-renewable-subscriptions) | | isLifetime | Boolean | True si este nivel de acceso está activo de por vida (sin fecha de expiración) | | isRefund | Boolean | True si esta compra fue reembolsada | | offerId | String | El ID de una oferta promocional activa (comprada desde Android) | | renewedAt | DateTime | La hora en que el nivel de acceso fue renovado por última vez | | startsAt | DateTime | La hora de inicio de este nivel de acceso (puede ser en el futuro) | | store | String | El store donde se realizó la compra | | unsubscribedAt | DateTime | La hora en que se desactivó la renovación automática de la suscripción. La suscripción puede seguir activa. Si no está definido, el usuario reactivó la suscripción | | vendorProductId | String | El ID del producto en el store que desbloqueó este nivel de acceso | | willRenew | Boolean | True si esta suscripción de renovación automática está configurada para renovarse | ### AdaptyAccessLevelIdentifiers Esta estructura está diseñada para reemplazar el par clave-valor de `Map
Adapty usa el espacio de nombres `AdaptySDK`. Al principio de los archivos de script que usen el SDK de Adapty, puedes añadir:
```csharp showLineNumbers title="C#"
using AdaptySDK;
```
Suscríbete a los eventos de Adapty:
```csharp showLineNumbers title="C#"
using UnityEngine;
using AdaptySDK;
public class AdaptyListener : MonoBehaviour, AdaptyEventListener {
public void OnLoadLatestProfile(AdaptyProfile profile) {
// handle updated profile data
}
public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { }
public void OnInstallationDetailsFail(AdaptyError error) { }
}
```
Recomendamos ajustar el orden de ejecución de scripts (Script Execution Order) para colocar el AdaptyListener antes del tiempo predeterminado (Default Time). Esto garantiza que Adapty se inicialice lo antes posible.
Ahora configura los paywalls en tu app:
- Si usas el [Paywall Builder de Adapty](adapty-paywall-builder), primero [activa el módulo AdaptyUI](#activate-adaptyui-module-of-adapty-sdk) a continuación y luego sigue la [guía de inicio rápido del Paywall Builder](unity-quickstart-paywalls).
- Si construyes tu propia interfaz de paywall, consulta la [guía de inicio rápido para paywalls personalizados](unity-quickstart-manual).
## Activar el módulo AdaptyUI del SDK \{#activate-adaptyui-module-of-adapty-sdk\}
Si planeas usar [Paywall Builder](adapty-paywall-builder) y has instalado el módulo AdaptyUI, necesitas que AdaptyUI esté activo. Puedes activarlo durante la configuración:
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetActivateUI(true);
```
## Configuración opcional \{#optional-setup\}
### Registro
#### Configura el sistema de registro \{#set-up-the-logging-system\}
Adapty registra errores y otra información importante para ayudarte a entender qué está pasando. Están disponibles los siguientes niveles:
| Level | Description |
| ---------- | ------------------------------------------------------------ |
| `error` | Solo se registrarán errores |
| `warn` | Se registrarán errores y mensajes del SDK que no causan errores críticos, pero que merecen atención |
| `info` | Se registrarán errores, advertencias y varios mensajes informativos |
| `verbose` | Se registrará cualquier información adicional que pueda ser útil durante la depuración, como llamadas a funciones, consultas a la API, etc. |
Puedes establecer el nivel de log en tu app durante la configuración de Adapty:
```csharp showLineNumbers title="C#"
// 'verbose' is recommended for development and the first production release
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY");
builder.LogLevel = AdaptyLogLevel.Verbose;
```
También puedes cambiar el nivel de log en tiempo de ejecución:
```csharp showLineNumbers title="C#"
Adapty.SetLogLevel(AdaptyLogLevel.Verbose, (error) => {
// handle result
});
```
### Políticas de datos \{#data-policies\}
Adapty no almacena datos personales de tus usuarios a menos que los envíes explícitamente, pero puedes implementar políticas de seguridad de datos adicionales para cumplir con las directrices del store o del país.
#### Deshabilitar la recopilación y el uso compartido de direcciones IP \{#disable-ip-address-collection-and-sharing\}
Al activar el módulo de Adapty, establece `SetIPAddressCollectionDisabled` en `true` para deshabilitar la recopilación y el uso compartido de la dirección IP del usuario. El valor predeterminado es `false`.
Usa este parámetro para mejorar la privacidad del usuario, cumplir con normativas regionales de protección de datos (como GDPR o CCPA) o reducir la recopilación de datos innecesaria cuando las funciones basadas en IP no son necesarias para tu app.
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetIPAddressCollectionDisabled(true);
```
#### Desactivar la recopilación y el uso compartido del ID publicitario \{#disable-advertising-id-collection-and-sharing\}
Al activar el módulo de Adapty, establece `SetAppleIDFACollectionDisabled` y/o `SetGoogleAdvertisingIdCollectionDisabled` en `true` para desactivar la recopilación de identificadores publicitarios. El valor predeterminado es `false`.
Usa este parámetro para cumplir con las políticas de App Store/Google Play, evitar que aparezca el aviso de App Tracking Transparency, o si tu aplicación no necesita atribución publicitaria ni análisis basado en IDs publicitarios.
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetAppleIDFACollectionDisabled(true)
.SetGoogleAdvertisingIdCollectionDisabled(true);
```
#### Configurar la caché de medios para AdaptyUI \{#set-up-media-cache-configuration-for-adaptyui\}
De forma predeterminada, AdaptyUI almacena en caché los medios (como imágenes y vídeos) para mejorar el rendimiento y reducir el uso de red. Puedes personalizar la configuración de la caché proporcionando una configuración personalizada.
Usa `SetAdaptyUIMediaCache` para sobreescribir la configuración de caché predeterminada:
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetAdaptyUIMediaCache(
100 * 1024 * 1024, // MemoryStorageTotalCostLimit 100MB
null, // MemoryStorageCountLimit
100 * 1024 * 1024 // DiskStorageSizeLimit 100MB
);
```
Parámetros:
| Parámetro | Obligatorio | Descripción |
|-----------------------------|-------------|--------------------------------------------------------------------------------------------------|
| memoryStorageTotalCostLimit | opcional | Tamaño total de la caché en memoria en bytes. Por defecto, usa el valor específico de la plataforma. |
| memoryStorageCountLimit | opcional | Límite del número de elementos en el almacenamiento en memoria. Por defecto, usa el valor específico de la plataforma. |
| diskStorageSizeLimit | opcional | Límite del tamaño de archivo en disco en bytes. Por defecto, usa el valor específico de la plataforma. |
### Habilitar niveles de acceso locales (Android) \{#enable-local-access-levels-android\}
Por defecto, los [niveles de acceso locales](local-access-levels) están habilitados en iOS y deshabilitados en Android. Para habilitarlos también en Android, establece `SetGoogleLocalAccessLevelAllowed` en `true`:
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetGoogleLocalAccessLevelAllowed(true);
```
### Borrar datos al restaurar desde copia de seguridad \{#clear-data-on-backup-restore\}
Cuando `SetAppleClearDataOnBackup` está configurado en `true`, el SDK detecta cuándo la app se restaura desde una copia de seguridad de iCloud y elimina todos los datos almacenados localmente por el SDK, incluida la información de perfil en caché, los detalles de productos y los paywalls. El SDK se inicializa entonces con un estado limpio. El valor predeterminado es `false`.
:::note
Solo se elimina la caché local del SDK. El historial de transacciones con Apple y los datos de usuario en los servidores de Adapty permanecen sin cambios.
:::
```csharp showLineNumbers title="C#"
var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY")
.SetAppleClearDataOnBackup(true);
```
## Solución de problemas \{#troubleshooting\}
#### Reglas de copia de seguridad de Android (configuración de Auto Backup) \{#android-backup-rules-auto-backup-configuration\}
Algunos SDKs (incluido Adapty) incluyen su propia configuración de Android Auto Backup. Si utilizas varios SDKs que definen reglas de copia de seguridad, el fusionador de manifiestos de Android puede fallar con un error relacionado con `android:fullBackupContent`, `android:dataExtractionRules` o `android:allowBackup`.
Síntomas típicos del error: `Manifest merger failed: Attribute application@dataExtractionRules value=(@xml/your_data_extraction_rules)
is also present at [com.other.sdk:library:1.0.0] value=(@xml/other_sdk_data_extraction_rules)`
:::note
Estos cambios deben realizarse en el directorio de la plataforma Android (normalmente en la carpeta `android/` de tu proyecto).
:::
Para resolverlo, necesitas:
- Indicar al fusionador de manifiestos que use los valores de tu app para los atributos relacionados con la copia de seguridad.
- Crear archivos de reglas de copia de seguridad que combinen las reglas de Adapty con las de otros SDKs.
#### 1. Añade el namespace `tools` a tu manifiesto \{#1-add-the-tools-namespace-to-your-manifest\}
En tu archivo `AndroidManifest.xml`, asegúrate de que la etiqueta raíz `
2. Añade la siguiente línea a `/Assets/Plugins/Android/launcherTemplate.gradle`:
```groovy showLineNumbers
apply plugin: 'com.android.application'
// highlight-next-line
apply plugin: 'kotlin-android'
apply from: 'setupSymbols.gradle'
apply from: '../shared/keepUnitySymbols.gradle'
```
3. Añade la siguiente línea a `/Assets/Plugins/Android/baseProjectTemplate.gradle`:
```groovy showLineNumbers
plugins {
// If you are changing the Android Gradle Plugin version, make sure it is compatible with the Gradle version preinstalled with Unity
// See which Gradle version is preinstalled with Unity here https://docs.unity3d.com/Manual/android-gradle-overview.html
// See official Gradle and Android Gradle Plugin compatibility table here https://developer.android.com/studio/releases/gradle-plugin#updating-gradle
// To specify a custom Gradle version in Unity, go do "Preferences > External Tools", uncheck "Gradle Installed with Unity (recommended)" and specify a path to a custom Gradle version
id 'com.android.application' version '8.3.0' apply false
id 'com.android.library' version '8.3.0' apply false
// highlight-next-line
id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
**BUILD_SCRIPT_DEPS**
}
```
---
# File: unity-quickstart-paywalls
---
---
title: "Habilitar compras usando paywalls en Unity SDK"
description: "Aprende cómo presentar paywalls en tu aplicación Unity con el SDK de Adapty."
---
Para habilitar las compras in-app, necesitas entender tres conceptos clave:
- [**Productos**](product) – cualquier cosa que los usuarios pueden comprar (suscripciones, consumibles, acceso de por vida)
- Los [**paywalls**](paywalls) son configuraciones que definen qué productos ofrecer. En Adapty, los paywalls son la única forma de recuperar productos, pero este diseño te permite modificar ofertas, precios y combinaciones de productos sin tocar el código de tu app.
- Los [**placements**](placements) – dónde y cuándo muestras los paywalls en tu app (como `main`, `onboarding`, `settings`). Configuras los paywalls para los placements en el dashboard y luego los solicitas por ID de placement en tu código. Esto facilita la ejecución de pruebas A/B y mostrar diferentes paywalls a distintos usuarios.
Adapty te ofrece tres formas de habilitar compras en tu app. Selecciona una según los requisitos de tu aplicación:
| Implementación | Complejidad | Cuándo usarla |
|---------------------------|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Adapty Paywall Builder | ✅ Fácil | [Creas un paywall completo y listo para compras en el editor sin código](quickstart-paywalls). Adapty lo renderiza automáticamente y gestiona todo el flujo de compra, la validación de recibos y la gestión de suscripciones entre bastidores. |
| Paywalls creados manualmente | 🟡 Medio | Implementas la UI de tu paywall en el código de tu app, pero igualmente obtienes el objeto paywall de Adapty para mantener flexibilidad en las ofertas de productos. Consulta la [guía](unity-quickstart-manual). |
| Modo observador | 🔴 Difícil | Ya tienes tu propia infraestructura de gestión de compras y quieres seguir usándola. Ten en cuenta que el modo observador tiene sus limitaciones en Adapty. Consulta el [artículo](observer-vs-full-mode). |
:::important
**Los pasos a continuación muestran cómo implementar un paywall creado en el Adapty Paywall Builder.**
Si no quieres usar el Paywall Builder, consulta la [guía para gestionar compras en paywalls creados manualmente](unity-making-purchases).
:::
Para mostrar un paywall creado en el Adapty Paywall Builder, en el código de tu app solo necesitas:
1. **Obtener el paywall**: Obtener el paywall de Adapty.
2. **Mostrar el paywall y Adapty gestionará las compras por ti**: Muestra el contenedor del paywall que obtuviste en tu app.
3. **Gestionar las acciones de los botones**: Asocia las interacciones del usuario con el paywall con la respuesta de tu app a ellas. Por ejemplo, abrir enlaces o cerrar el paywall cuando los usuarios pulsan botones.
## Antes de empezar \{#before-you-start\}
Antes de empezar, completa estos pasos:
1. Conecta tu app al [App Store](initial_ios) y/o [Google Play](initial-android) en el Adapty Dashboard.
2. [Crea tus productos](create-product) en Adapty.
3. [Crea un paywall y añade productos](create-paywall).
4. [Crea un placement y añade tu paywall](create-placement).
5. [Instala y activa el SDK de Adapty](sdk-installation-unity) en el código de tu app.
:::tip
La forma más rápida de completar estos pasos es seguir la [guía de inicio rápido](quickstart) o crear paywalls y placements usando el [CLI para desarrolladores](developer-cli-quickstart).
:::
## 1. Obtener el paywall \{#1-get-the-paywall\}
Tus paywalls están asociados a placements configurados en el dashboard. Los placements te permiten ejecutar distintos paywalls para diferentes audiencias o realizar [pruebas A/B](ab-tests).
Para obtener un paywall creado en el Adapty Paywall Builder, necesitas:
1. Obtener el objeto `paywall` por el ID del [placement](placements) usando el método `GetPaywall` y comprobar si fue creado en el builder mediante la propiedad `HasViewConfiguration`.
2. Crear la vista del paywall usando el método `CreatePaywallView`. La vista contiene los elementos de UI y el estilo necesarios para mostrar el paywall.
:::important
Para obtener la configuración de la vista, debes activar el toggle **Show on device** en el Paywall Builder. De lo contrario, obtendrás una configuración de vista vacía y el paywall no se mostrará.
:::
```csharp showLineNumbers
Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => {
if(error != null) {
// handle the error
return;
}
// Create paywall view parameters
var parameters = new AdaptyUICreatePaywallViewParameters();
// Create the paywall view
AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => {
if(error != null) {
// handle the error
return;
}
// view - the paywall view ready to be presented
});
});
```
:::info
Este inicio rápido proporciona la configuración mínima necesaria para mostrar un paywall. Para detalles de configuración avanzada, consulta nuestra [guía sobre cómo obtener paywalls](unity-get-pb-paywalls).
:::
## 2. Mostrar el paywall \{#2-display-the-paywall\}
Ahora que tienes la configuración del paywall, basta con añadir unas pocas líneas para mostrarlo.
Para mostrar el paywall, usa el método `view.Present()` en el `view` creado por el método `CreatePaywallView`. Cada `view` solo puede usarse una vez. Si necesitas mostrar el paywall de nuevo, llama a `CreatePaywallView` otra vez para crear una nueva instancia de `view`.
```csharp showLineNumbers title="Unity"
view.Present((error) => {
// handle the error
});
```
:::info
Para más detalles sobre cómo mostrar un paywall, consulta nuestra [guía](unity-present-paywalls).
:::
## 3. Gestionar las acciones de los botones \{#3-handle-button-actions\}
Cuando los usuarios pulsan botones en el paywall, el SDK de Unity gestiona automáticamente las compras y la restauración. Sin embargo, otros botones tienen IDs personalizados o predefinidos y requieren gestionar las acciones en tu código.
Por ejemplo, tu paywall probablemente tenga un botón de cerrar y URLs que abrir (p. ej., términos de uso y política de privacidad). Para gestionar estas acciones, tu clase debe implementar la interfaz `AdaptyPaywallsEventsListener` y registrarse como listener.
:::tip
Lee nuestras guías sobre cómo gestionar [acciones](unity-handle-paywall-actions) y [eventos](unity-handling-events) de botones.
:::
```csharp showLineNumbers title="Unity"
public class YourClass : MonoBehaviour, AdaptyPaywallsEventsListener
{
void Start()
{
// Register this class as the paywall events listener
Adapty.SetPaywallsEventsListener(this);
}
// AdaptyPaywallsEventsListener method - handles button actions
public void PaywallViewDidPerformAction(
AdaptyUIPaywallView view,
AdaptyUIUserAction action
) {
switch (action.Type) {
case AdaptyUIUserActionType.Close:
view.Dismiss(null);
break;
case AdaptyUIUserActionType.OpenUrl:
Application.OpenURL(action.Value);
break;
default:
break;
}
}
}
```
## Próximos pasos \{#next-steps\}
:::tip
¿Tienes preguntas o estás teniendo algún problema? Consulta nuestro [foro de soporte](https://adapty.featurebase.app/) donde encontrarás respuestas a preguntas frecuentes o podrás plantear las tuyas. ¡Nuestro equipo y la comunidad están aquí para ayudarte!
:::
Tu paywall está listo para mostrarse en la app. Prueba tus compras en el [sandbox del App Store](test-purchases-in-sandbox) o en [Google Play Store](testing-on-android) para asegurarte de que puedes completar una compra de prueba desde el paywall.
Ahora necesitas [comprobar el nivel de acceso de los usuarios](unity-check-subscription-status) para asegurarte de que muestras un paywall o das acceso a las funciones de pago a los usuarios correctos.
## Ejemplo completo \{#full-example\}
Así es como todos esos pasos pueden integrarse juntos en tu app.
```csharp showLineNumbers
using System;
using UnityEngine;
using AdaptySDK;
public class PaywallManager : MonoBehaviour, AdaptyPaywallsEventsListener
{
[SerializeField] private string placementId = "YOUR_PLACEMENT_ID";
private AdaptyUIPaywallView currentPaywallView;
void Start()
{
// Register for paywall events
Adapty.SetPaywallsEventsListener(this);
GetAndDisplayPaywall();
}
private void GetAndDisplayPaywall()
{
Adapty.GetPaywall(placementId, (paywall, error) => {
if (error != null) {
Debug.LogError("Error getting paywall: " + error.Message);
return;
}
if (paywall.HasViewConfiguration) {
CreateAndPresentPaywallView(paywall);
} else {
Debug.LogWarning("Paywall was not created using the builder");
}
});
}
private void CreateAndPresentPaywallView(AdaptyPaywall paywall)
{
var parameters = new AdaptyUICreatePaywallViewParameters();
AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => {
if (error != null) {
Debug.LogError("Error creating paywall view: " + error.Message);
return;
}
currentPaywallView = view;
view.Present((presentError) => {
if (presentError != null) {
Debug.LogError("Error presenting paywall: " + presentError.Message);
return;
}
Debug.Log("Paywall presented successfully");
});
});
}
// AdaptyPaywallsEventsListener implementation
public void PaywallViewDidPerformAction(
AdaptyUIPaywallView view,
AdaptyUIUserAction action
) {
switch (action.Type) {
case AdaptyUIUserActionType.Close:
Debug.Log("Close button pressed");
view.Dismiss(null);
break;
case AdaptyUIUserActionType.OpenUrl:
Application.OpenURL(action.Value);
break;
default:
break;
}
}
// Required interface methods (implement as needed)
public void PaywallViewDidAppear(AdaptyUIPaywallView view) { }
public void PaywallViewDidDisappear(AdaptyUIPaywallView view) { }
public void PaywallViewDidSelectProduct(AdaptyUIPaywallView view, string productId) { }
public void PaywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) { }
public void PaywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult) { }
public void PaywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { }
public void PaywallViewDidStartRestore(AdaptyUIPaywallView view) { }
public void PaywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) { }
public void PaywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) { }
public void PaywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) { }
public void PaywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) { }
public void PaywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { }
public void ShowPaywall()
{
GetAndDisplayPaywall();
}
void OnDestroy()
{
if (currentPaywallView != null) {
currentPaywallView.Dismiss(null);
}
}
}
```
---
# File: unity-check-subscription-status
---
---
title: "Comprobar el estado de la suscripción en el SDK de Unity"
description: "Aprende cómo comprobar el estado de la suscripción en tu app de Unity con Adapty."
---
Para decidir si los usuarios pueden acceder al contenido de pago o ver un paywall, necesitas comprobar su [nivel de acceso](access-level) en el perfil.
Este artículo te muestra cómo acceder al estado del perfil para decidir qué necesitan ver los usuarios: si mostrarles un paywall o darles acceso a las funciones de pago.
## Obtener el estado de la suscripción \{#get-subscription-status\}
Cuando decides si mostrar un paywall o contenido de pago a un usuario, compruebas su [nivel de acceso](access-level) en su perfil. Tienes dos opciones:
- Llama a `GetProfile` si necesitas los datos más recientes del perfil de inmediato (como al iniciar la app) o quieres forzar una actualización.
- Configura **actualizaciones automáticas del perfil** para mantener una copia local que se actualiza automáticamente cada vez que cambia el estado de la suscripción.
### Obtener el perfil \{#get-profile\}
La forma más sencilla de obtener el estado de la suscripción es usar el método `GetProfile` para acceder al perfil:
```csharp showLineNumbers
Adapty.GetProfile((profile, error) => {
if (error != null) {
// handle the error
return;
}
// check the access
});
```
### Escuchar actualizaciones de la suscripción \{#listen-to-subscription-updates\}
Para recibir actualizaciones del perfil automáticamente en tu app:
1. Extiende `AdaptyEventListener` e implementa el método `OnLoadLatestProfile`: Adapty llamará a este método automáticamente cada vez que cambie el estado de la suscripción del usuario.
2. Almacena los datos del perfil actualizado cuando se llame a este método, para poder usarlos en toda la app sin realizar peticiones de red adicionales.
```csharp
public class SubscriptionManager : MonoBehaviour, AdaptyEventListener {
private AdaptyProfile currentProfile;
void Start() {
// Register this object as an Adapty event listener
Adapty.SetEventListener(this);
}
// Store the profile when it updates
public void OnLoadLatestProfile(AdaptyProfile profile) {
currentProfile = profile;
// Update UI, unlock content, etc.
}
public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { }
public void OnInstallationDetailsFail(AdaptyError error) { }
// Use stored profile instead of calling getProfile()
public bool HasAccess() {
if (currentProfile?.AccessLevels != null &&
currentProfile.AccessLevels.ContainsKey("premium")) {
return currentProfile.AccessLevels["premium"].IsActive;
}
return false;
}
}
```
:::note
Adapty llama automáticamente a `OnLoadLatestProfile` cuando se inicia tu app, proporcionando datos de suscripción en caché incluso si el dispositivo está sin conexión.
:::
## Conectar el perfil con la lógica del paywall \{#connect-profile-with-paywall-logic\}
Cuando necesitas tomar decisiones inmediatas sobre mostrar paywalls o dar acceso a funciones de pago, puedes comprobar el perfil del usuario directamente. Este enfoque es útil en situaciones como el inicio de la app, al entrar en secciones premium o antes de mostrar contenido específico.
```csharp
private void CheckAccessLevel()
{
Adapty.GetProfile((profile, error) => {
if (error != null) {
Debug.LogError("Error checking access level: " + error.Message);
// Show paywall if access check fails
return;
}
var accessLevel = profile.AccessLevels["YOUR_ACCESS_LEVEL"];
if (accessLevel == null || !accessLevel.IsActive) {
// Show paywall if no access
}
});
}
private void InitializePaywall()
{
LoadPaywall();
CheckAccessLevel();
}
```
## Próximos pasos \{#next-steps\}
Ahora que sabes cómo rastrear el estado de la suscripción, aprende a [trabajar con perfiles de usuario](unity-quickstart-identify) para asegurarte de que pueden acceder a lo que han pagado.
---
# File: unity-quickstart-identify
---
---
title: "Identificar usuarios en el SDK de Unity"
description: "Guía de inicio rápido para configurar Adapty en la gestión de suscripciones in-app en Unity."
---
:::important
Esta guía es para ti si tienes tu propio sistema de autenticación. Aquí aprenderás a trabajar con perfiles de usuario en Adapty para que se integre con tu sistema de autenticación existente.
:::
La forma en que gestionas las compras de los usuarios depende del modelo de autenticación de tu app:
- Si tu app no utiliza autenticación de backend y no almacena datos de usuario, consulta la [sección sobre usuarios anónimos](#anonymous-users).
- Si tu app tiene (o tendrá) autenticación de backend, consulta la [sección sobre usuarios identificados](#identified-users).
**Conceptos clave**:
- Los **perfiles** son las entidades necesarias para que funcione el SDK. Adapty los crea automáticamente.
- Pueden ser anónimos **(sin customer user ID)** o identificados **(con customer user ID)**.
- Proporcionas el **customer user ID** para cruzar los perfiles de Adapty con tu sistema de autenticación interno.
Estas son las diferencias entre usuarios anónimos e identificados:
| | Usuarios anónimos | Usuarios identificados |
|-------------------------------|----------------------------------------------------------|-------------------------------------------------------------------------------------|
| **Gestión de compras** | Restauración de compras a nivel de store | Mantienen el historial de compras en todos los dispositivos mediante su customer user ID |
| **Gestión de perfiles** | Nuevos perfiles en cada reinstalación | El mismo perfil en todas las sesiones y dispositivos |
| **Persistencia de datos** | Los datos de usuarios anónimos están vinculados a la instalación de la app | Los datos de usuarios identificados persisten entre instalaciones |
## Usuarios anónimos \{#anonymous-users\}
Si no tienes autenticación de backend, **no necesitas gestionar la autenticación en el código de la app**:
1. Cuando el SDK se activa en el primer arranque de la app, Adapty **crea un nuevo perfil para el usuario**.
2. Cuando el usuario realiza una compra en la app, esta compra queda **asociada a su perfil de Adapty y a su cuenta del store**.
3. Cuando el usuario **reinstala** la app o la instala en un **nuevo dispositivo**, Adapty **crea un nuevo perfil anónimo en la activación**.
4. Si el usuario ya había realizado compras en tu app, por defecto, sus compras se sincronizan automáticamente desde el App Store al activar el SDK.
Con usuarios anónimos se crearán nuevos perfiles en cada instalación, pero eso no es un problema porque, en las analíticas de Adapty, puedes [configurar qué se considerará una nueva instalación](general#4-installs-definition-for-analytics).
Para los usuarios anónimos, debes contar las instalaciones por **IDs de dispositivo**. En este caso, cada instalación de la app en un dispositivo se cuenta como una instalación, incluidas las reinstalaciones.
## Usuarios identificados \{#identified-users\}
Tienes dos opciones para identificar a los usuarios en la app:
- [**Durante el inicio de sesión/registro:**](#during-loginsignup) Si los usuarios inician sesión después de que arranca tu app, llama a `identify()` con un customer user ID cuando se autentiquen.
- [**Durante la activación del SDK:**](#during-the-sdk-activation) Si ya tienes un customer user ID almacenado cuando arranca la app, envíalo al llamar a `activate()`.
:::important
Por defecto, cuando Adapty recibe una compra de un Customer User ID que actualmente está asociado a otro Customer User ID, el nivel de acceso se comparte, de modo que ambos perfiles tienen acceso de pago. Puedes configurar este ajuste para transferir el acceso de pago de un perfil a otro o deshabilitar el uso compartido por completo. Consulta el [artículo](general#6-sharing-paid-access-between-user-accounts) para más detalles.
:::
### Durante el inicio de sesión/registro \{#during-loginsignup\}
Si identificas a los usuarios después del arranque de la app (por ejemplo, después de que inicien sesión o se registren), usa el método `identify` para establecer su customer user ID.
- Si **no has usado este customer user ID antes**, Adapty lo vinculará automáticamente al perfil actual.
- Si **ya has usado este customer user ID para identificar al usuario**, Adapty cambiará al perfil asociado a ese customer user ID.
:::important
Los customer user IDs deben ser únicos para cada usuario. Si hardcodeas el valor del parámetro, todos los usuarios se considerarán como uno solo.
:::
Espera el callback de finalización de `Identify` antes de llamar a otros métodos del SDK. Las llamadas concurrentes producen `#3006 profileWasChanged` o aterrizan en el perfil anónimo. Consulta [Orden de llamadas en el SDK de Unity](unity-sdk-call-order).
```csharp showLineNumbers
Adapty.Identify("YOUR_USER_ID", (error) => { // Único para cada usuario
if(error == null) {
// identificación correcta
}
});
```
### Durante la activación del SDK \{#during-the-sdk-activation\}
Si ya conoces un customer user ID cuando activas el SDK, puedes enviarlo en el método `activate` en lugar de llamar a `identify` por separado.
Si conoces un customer user ID pero lo estableces solo después de la activación, eso significará que, al activarse, Adapty creará un nuevo perfil anónimo y cambiará al existente solo después de que llames a `identify`.
Puedes pasar un customer user ID existente (uno que hayas usado antes) o uno nuevo. Si pasas uno nuevo, el nuevo perfil creado al activarse se vinculará automáticamente al customer user ID.
:::note
Por defecto, la creación de perfiles anónimos no afecta a los dashboards de analíticas, ya que las instalaciones se cuentan por IDs de dispositivo.
Un ID de dispositivo representa una única instalación de la app desde el store en un dispositivo y solo se regenera tras reinstalar la app.
No depende de si es una primera instalación o una reinstalación, ni de si se usa un customer user ID existente.
Crear un perfil (al activar el SDK o al cerrar sesión), iniciar sesión o actualizar la app sin reinstalarla no genera eventos de instalación adicionales.
Si quieres contar las instalaciones por usuarios únicos en lugar de dispositivos, ve a **App settings** y configura [**Installs definition for analytics**](general#4-installs-definition-for-analytics).
:::
```csharp showLineNumbers
using UnityEngine;
using AdaptySDK;
var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY")
.SetCustomerUserId("YOUR_USER_ID"); // Los customer user IDs deben ser únicos para cada usuario. Si hardcodeas el valor del parámetro, todos los usuarios se considerarán como uno solo.
Adapty.Activate(builder.Build(), (error) => {
if (error != null) {
// handle the error
return;
}
});
```
### Cerrar sesión de usuarios \{#log-users-out\}
Si tienes un botón para cerrar la sesión de los usuarios, usa el método `logout`.
:::important
Cerrar la sesión de los usuarios crea un nuevo perfil anónimo para el usuario.
:::
```csharp showLineNumbers
Adapty.Logout((error) => {
if(error == null) {
// cierre de sesión correcto
}
});
```
:::info
Para volver a iniciar sesión en la app, usa el método `identify`.
:::
### Permitir compras sin inicio de sesión \{#allow-purchases-without-login\}
Si tus usuarios pueden realizar compras tanto antes como después de iniciar sesión en tu app, debes asegurarte de que mantengan el acceso tras iniciar sesión:
1. Cuando un usuario sin sesión iniciada realiza una compra, Adapty la vincula a su ID de perfil anónimo.
2. Cuando el usuario inicia sesión en su cuenta, Adapty cambia al perfil identificado.
- Si es un nuevo customer user ID (por ejemplo, la compra se realizó antes del registro), Adapty asigna el customer user ID al perfil actual, por lo que se mantiene todo el historial de compras.
- Si es un customer user ID existente (el customer user ID ya está vinculado a un perfil), necesitas obtener el nivel de acceso actual tras el cambio de perfil. Puedes llamar a [`getProfile`](unity-check-subscription-status) justo después de la identificación, o [escuchar las actualizaciones del perfil](unity-check-subscription-status) para que los datos se sincronicen automáticamente.
## Próximos pasos \{#next-steps\}
¡Enhorabuena! Has implementado la lógica de pago in-app en tu app. ¡Te deseamos todo el éxito con la monetización de tu app!
Para sacar aún más partido a Adapty, puedes explorar estos temas:
- [**Pruebas**](troubleshooting-test-purchases): Asegúrate de que todo funciona como se espera
- [**Onboardings**](onboardings): Engancha a los usuarios con onboardings e impulsa la retención
- [**Integraciones**](configuration): Intégrate con servicios de atribución de marketing y analíticas con solo una línea de código
- [**Establecer atributos de perfil personalizados**](unity-setting-user-attributes): Añade atributos personalizados a los perfiles de usuario y crea segmentos para lanzar pruebas A/B o mostrar diferentes paywalls a distintos usuarios
---
# File: adapty-sdk-integration-skill-unity
---
---
title: "Integra Adapty en tu app de Unity con la habilidad de integración del SDK"
description: "Usa la habilidad adapty-sdk-integration para integrar el SDK de Adapty en tu app de Unity de principio a fin con tu herramienta de codificación con IA."
---
La [skill adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatiza la integración de Adapty de extremo a extremo: configuración del dashboard, instalación del SDK, paywall y verificación por etapas. Detecta tu plataforma automáticamente y obtiene la documentación de Adapty relevante en cada etapa.
**Herramientas compatibles**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Para instalarla, elige el formulario para tu herramienta. La lista completa está en el [README de la skill](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex u otra herramienta** — usa la [CLI de skills](https://skills.sh) (ten en cuenta que las skills instaladas de esta forma no se actualizan automáticamente):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
También puedes clonar el repositorio y copiar `skills/adapty-sdk-integration/` en el directorio de skills de tu herramienta.
Tras la instalación, ejecuta la skill en tu proyecto:
```
/adapty-sdk-integration
```
La skill hace algunas preguntas de configuración y luego te guía por la configuración del dashboard, la instalación del SDK, el paywall y la verificación.
:::important
La habilidad está en beta. Si se detiene o se comporta de forma inesperada, sigue la [guía de integración paso a paso](adapty-cursor-unity) — te lleva a través de cada etapa con la documentación adecuada.
:::
La [skill adapty-sdk-integration](https://github.com/adaptyteam/adapty-sdk-integration-skill) automatiza la integración de Adapty de extremo a extremo: configuración del dashboard, instalación del SDK, paywall y verificación por etapas. Detecta tu plataforma automáticamente y obtiene la documentación de Adapty relevante en cada etapa.
**Herramientas compatibles**: Claude Code, GitHub Copilot CLI, OpenAI Codex, Gemini CLI.
Para instalarla, elige el formulario para tu herramienta. La lista completa está en el [README de la skill](https://github.com/adaptyteam/adapty-sdk-integration-skill).
**Claude Code**
```
claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill
claude plugin install adapty-sdk-integration@adapty
```
**GitHub Copilot CLI**
```
gh skill install adaptyteam/adapty-sdk-integration-skill
```
**Gemini CLI**
```
gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill
```
**OpenAI Codex u otra herramienta** — usa la [CLI de skills](https://skills.sh) (ten en cuenta que las skills instaladas de esta forma no se actualizan automáticamente):
```
npx skills add adaptyteam/adapty-sdk-integration-skill
```
También puedes clonar el repositorio y copiar `skills/adapty-sdk-integration/` en el directorio de skills de tu herramienta.
Tras la instalación, ejecuta la skill en tu proyecto:
```
/adapty-sdk-integration
```
La skill hace algunas preguntas de configuración y luego te guía por la configuración del dashboard, la instalación del SDK, el paywall y la verificación.
---
# File: adapty-cursor-unity
---
---
title: "Integra Adapty en tu app de Unity con ayuda de IA"
description: "Una guía paso a paso para integrar Adapty en tu app de Unity usando Cursor, Context7, ChatGPT, Claude u otras herramientas de IA."
---
Esta guía te lleva paso a paso por la integración de Adapty en tu app de Unity con una herramienta de IA — solo tienes que darle los documentos correctos de Adapty en el orden correcto.
For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command.
## Antes de empezar: configuración en el dashboard \{#before-you-start-dashboard-setup\}
Adapty requiere cierta configuración en el dashboard antes de escribir código con el SDK. Puedes hacerlo con una skill interactiva de LLM o manualmente desde el Dashboard.
### Enfoque mediante skill (recomendado) \{#skill-approach-recommended\}
El skill de Adapty CLI permite que tu LLM configure tu app, productos, niveles de acceso, paywalls y placements directamente, sin necesidad de abrir el Dashboard en cada paso. Solo tienes que [conectar tus stores](integrate-payments) en el Dashboard.
```
npx skills add adaptyteam/adapty-cli --skill adapty-cli
```
Una vez añadido el skill, ejecuta `/adapty-cli` en tu agente. Te guiará paso a paso, incluyendo el momento en que debas abrir el Dashboard para conectar tus stores.
### Enfoque desde el dashboard
Si prefieres configurarlo todo manualmente, esto es lo que necesitas antes de escribir cualquier código. Tu LLM no puede consultar los valores del dashboard por ti, tendrás que proporcionarlos.
1. **Conecta tus stores**: En el Adapty Dashboard, ve a **App settings → General**. Conecta tanto App Store como Google Play si tu app de Unity apunta a ambas plataformas. Esto es necesario para que las compras funcionen.
[Conecta los stores](integrate-payments)
2. **Copia tu clave SDK pública**: En el Adapty Dashboard, ve a **App settings → General** y localiza la sección **API keys**. En el código, es la cadena que pasas al builder de configuración de Adapty.
3. **Crea al menos un producto**: En el Adapty Dashboard, ve a la página **Products**. No referenciarás los productos directamente en el código — Adapty los entrega a través de paywalls.
[Añadir productos](quickstart-products)
4. **Crea un paywall y un placement**: En el Adapty Dashboard, crea un paywall en la página **Paywalls** y asígnalo a un placement en la página **Placements**. En el código, el ID del placement es la cadena que pasas a `Adapty.GetPaywall("YOUR_PLACEMENT_ID")`.
[Crear paywall](quickstart-paywalls)
5. **Configura los niveles de acceso**: En el Adapty Dashboard, configúralos por producto en la página **Products**. En el código, la cadena que se comprueba es `profile.AccessLevels["premium"]?.IsActive`. El nivel de acceso `premium` predeterminado funciona para la mayoría de las aplicaciones. Si los usuarios de pago tienen acceso a distintas funcionalidades según el producto (por ejemplo, un plan `basic` frente a un plan `pro`), [crea niveles de acceso adicionales](assigning-access-level-to-a-product) antes de empezar a programar.
:::tip
Una vez que tengas los cinco, estás listo para escribir código. Dile a tu LLM: "Mi clave SDK pública es X, mi ID de placement es Y" para que pueda generar el código de inicialización y obtención de paywalls correcto.
:::
### Configura cuando estés listo \{#set-up-when-ready\}
No son necesarias para empezar a programar, pero las querrás a medida que tu integración madure:
- **Pruebas A/B**: Configúralas en la página **Placements**. No se requieren cambios de código.
[Pruebas A/B](ab-tests)
- **Paywalls y placements adicionales**: Añade más llamadas `GetPaywall` con diferentes IDs de placement.
- **Integraciones de analítica**: Configúralas en la página **Integrations**. La configuración varía según la integración. Consulta [integraciones de analítica](analytics-integration) y [integraciones de atribución](attribution-integration).
## Proporciona documentación de Adapty a tu LLM \{#feed-adapty-docs-to-your-llm\}
### Usa Context7 (recomendado)
[Context7](https://context7.com) es un servidor MCP que da a tu LLM acceso directo a la documentación actualizada de Adapty. Tu LLM obtiene automáticamente la documentación adecuada según lo que preguntes, sin necesidad de pegar URLs manualmente.
Context7 funciona con **Cursor**, **Claude Code**, **Windsurf** y otras herramientas compatibles con MCP. Para configurarlo, ejecuta:
```
npx ctx7 setup
```
Esto detecta tu editor y configura el servidor Context7. Para la configuración manual, consulta el [repositorio de Context7 en GitHub](https://github.com/upstash/context7).
Una vez configurado, referencia la librería de Adapty en tus prompts:
```
Use the adaptyteam/adapty-docs library to look up how to install the Unity SDK
```
:::warning
Aunque Context7 elimina la necesidad de pegar enlaces a la documentación manualmente, el orden de implementación es importante. Sigue el [recorrido de implementación](#implementation-walkthrough) paso a paso para asegurarte de que todo funciona.
:::
### Usar documentación en texto plano
Puedes acceder a cualquier artículo de Adapty en formato Markdown. Añade `.md` al final de su URL o haz clic en **Copy for LLM** bajo el título del artículo. Por ejemplo: [adapty-cursor-unity.md](https://adapty.io/docs/es/adapty-cursor-unity.md).
Cada paso del [resumen de implementación](#implementation-walkthrough) incluye un bloque "Envía esto a tu LLM" con enlaces `.md` para copiar.
Para acceder a más documentación de una vez, consulta los [archivos de índice y subconjuntos por plataforma](#plain-text-doc-index-files) más abajo.
## Guía de implementación paso a paso \{#implementation-walkthrough\}
El resto de esta guía recorre la integración de Adapty en el orden de implementación. Cada etapa incluye la documentación que debes enviar a tu LLM, qué deberías ver al terminar y los problemas más comunes.
### Planifica tu integración \{#plan-your-integration\}
Antes de escribir código, pídele a tu LLM que analice tu proyecto y cree un plan de implementación. Si tu herramienta de IA admite un modo de planificación (como el modo plan de Cursor o Claude Code), úsalo para que el LLM pueda leer tanto la estructura de tu proyecto como la documentación de Adapty antes de escribir cualquier código.
Indícale a tu LLM qué enfoque usas para las compras, ya que esto afecta a las guías que debe seguir:
- [**Adapty Paywall Builder**](adapty-paywall-builder): Creas los paywalls en el editor no-code de Adapty y el SDK los renderiza automáticamente.
- [**Paywalls creados manualmente**](unity-making-purchases): Construyes tu propia interfaz de paywall en código, pero sigues usando Adapty para obtener productos y gestionar compras.
- [**Modo Observer**](observer-vs-full-mode): Mantienes tu infraestructura de compras existente y usas Adapty solo para analíticas e integraciones.
¿No sabes cuál elegir? Consulta la [tabla comparativa en la guía de inicio rápido](unity-quickstart-paywalls).
### Instalar y configurar el SDK
Añade el paquete del SDK de Adapty a través de Unity Package Manager y actívalo con tu clave pública del SDK. Esta es la base: sin esto, nada más funcionará.
**Guía:** [Instalar y configurar el SDK de Adapty](sdk-installation-unity)
Envía esto a tu LLM:
```
Read these Adapty docs before writing code:
- https://adapty.io/docs/es/sdk-installation-unity.md
```
:::tip[Checkpoint]
- **Esperado:** El proyecto compila y se ejecuta. La consola de Unity muestra el log de activación de Adapty.
- **Problema frecuente:** "Public API key is missing" → verifica que hayas reemplazado el marcador con tu clave real de **App settings**.
:::
### Mostrar paywalls y gestionar compras \{#show-paywalls-and-handle-purchases\}
Obtén un paywall por ID de placement, muéstralo y gestiona los eventos de compra. Las guías que necesitas dependen de cómo gestionas las compras.
Prueba cada compra en el sandbox a medida que avances — no esperes hasta el final. Consulta [Probar compras en sandbox](test-purchases-in-sandbox) para las instrucciones de configuración.
opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-paywall-locale-in-adapty-paywall-builder). Se espera que este parámetro sea un código de idioma compuesto de uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta es para el idioma y la segunda para la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios puede que no obtengan los datos más recientes, pero disfrutarán de tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se desinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché actualizada regularmente descrita anteriormente y los [paywalls de respaldo](fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el respaldo local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes solicitudes internamente.
| Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) con una lista de IDs de productos, el identificador del paywall, el Remote Config y otras propiedades. | ## Obtener la configuración de vista del paywall diseñado con Paywall Builder \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important Asegúrate de activar el botón **Show on device** en el Paywall Builder. Si esta opción no está activada, la configuración de vista no estará disponible para recuperar. ::: Después de obtener el paywall, comprueba si incluye un `ViewConfiguration`, lo que indica que fue creado con el Paywall Builder. Esto te guiará sobre cómo mostrar el paywall. Si el `ViewConfiguration` está presente, trátalo como un paywall del Paywall Builder; si no, [trátalo como un paywall de Remote Config](present-remote-config-paywalls-unity). En el SDK de Unity, llama directamente al método `CreatePaywallView` sin necesidad de obtener primero la configuración de vista de forma manual. :::warning El resultado del método `CreatePaywallView` solo puede usarse una vez. Si necesitas usarlo de nuevo, vuelve a llamar al método `CreatePaywallView`. Llamarlo dos veces sin recrearlo puede provocar el error `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers var parameters = new AdaptyUICreatePaywallViewParameters() .SetPreloadProducts(preloadProducts) .SetLoadTimeout(new TimeSpan(0, 0, 3)); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { // handle the result }); ``` Parámetros: | Parámetro | Presencia | Descripción | | :------------------ | :------------- | :----------------------------------------------------------- | | **paywall** | obligatorio | Un objeto `AdaptyPaywall` para obtener un controlador del paywall deseado. | | **loadTimeout** | por defecto: 5 seg | Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el respaldo local. Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes solicitudes internamente. | | **PreloadProducts** | opcional | Proporciona un array de `AdaptyPaywallProducts` para optimizar el tiempo de visualización de los productos en pantalla. Si se pasa `nil`, AdaptyUI obtendrá automáticamente los productos necesarios. | | **CustomTags** | opcional | Define un diccionario de etiquetas personalizadas y sus valores resueltos. Las etiquetas personalizadas actúan como marcadores de posición en el contenido del paywall, reemplazados dinámicamente por cadenas específicas para personalizar el contenido. Consulta el tema sobre etiquetas personalizadas en el Paywall Builder para más detalles. | | **CustomTimers** | opcional | Define un diccionario de temporizadores personalizados y sus fechas de finalización. Los temporizadores personalizados te permiten mostrar cuentas atrás en tu paywall. | :::note Si usas varios idiomas, aprende cómo añadir una [localización al Paywall Builder](add-paywall-locale-in-adapty-paywall-builder) y cómo usar los códigos de idioma correctamente [aquí](localizations-and-locale-codes). ::: Una vez que tengas la vista, [presenta el paywall](unity-present-paywalls). ## Personalizar recursos \{#customize-assets\} Para personalizar imágenes y vídeos en tu paywall, implementa los recursos personalizados. Las imágenes y vídeos destacados tienen IDs predefinidos: `hero_image` y `hero_video`. En un bundle de recursos personalizados, apuntas a estos elementos por sus IDs y personalizas su comportamiento. Para otras imágenes y vídeos, necesitas [establecer un ID personalizado](custom-media) en el dashboard de Adapty. Por ejemplo, puedes: - Mostrar una imagen o vídeo diferente a algunos usuarios. - Mostrar una imagen de vista previa local mientras se carga la imagen principal remota. - Mostrar una imagen de vista previa antes de reproducir un vídeo. :::important Para usar esta función, actualiza el SDK de Adapty para Unity a la versión 3.8.0 o superior. ::: Aquí tienes un ejemplo de cómo proporcionar recursos personalizados mediante un diccionario simple: ```csharp showLineNumbers var customAssets = new Dictionaryopcional
por defecto: `en`
|El identificador de la localización del paywall. Se espera que este parámetro sea un código de idioma compuesto de uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta es para el idioma y la segunda para la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de error. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios puede que no obtengan los datos más recientes, pero disfrutarán de tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se desinstala la app o mediante una limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché actualizada regularmente descrita anteriormente y los paywalls de respaldo. También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| --- # File: unity-present-paywalls --- --- title: "Mostrar paywalls" description: "Aprende cómo mostrar paywalls en tu app de Unity con el SDK de Adapty." --- Si has personalizado un paywall con el Paywall Builder, no necesitas preocuparte por renderizarlo en el código de tu app para mostrárselo al usuario. Ese paywall contiene tanto lo que debe mostrarse como la forma en que debe hacerse. :::warning Esta guía cubre el **nuevo Paywall Builder**, que requiere el SDK de Adapty 3.3.0 o posterior. Para mostrar paywalls con Remote Config, consulta [Renderizar paywalls diseñados con remote config](present-remote-config-paywalls). ::: Para mostrar un paywall, usa el método `view.Present()` sobre el `view` creado por el método [`CreatePaywallView`](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder). Cada `view` solo puede usarse una vez. Si necesitas mostrar el paywall de nuevo, llama a `CreatePaywallView` otra vez para crear una nueva instancia de `view`. :::warning Reutilizar el mismo `view` sin recrearlo puede provocar el error `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers title="Unity" view.Present((error) => { // handle the error }); ``` :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ## Mostrar diálogo \{#show-dialog\} Usa este método en lugar de los diálogos de alerta nativos cuando hay un paywall visible en Android. En Android, las alertas normales aparecen detrás del paywall y el usuario no puede verlas. Este método garantiza que el diálogo se muestre correctamente por encima del paywall en todas las plataformas. ```csharp showLineNumbers title="Unity" var dialog = new AdaptyUIDialogConfiguration() .SetTitle("Close paywall?") .SetContent("You will lose access to exclusive offers.") .SetDefaultActionTitle("Stay") .SetSecondaryActionTitle("Close"); AdaptyUI.ShowDialog(view, dialog, (action, error) => { if (error == null) { if (action == AdaptyUIDialogActionType.Secondary) { // User confirmed - close the paywall view.Dismiss(); } // If primary - do nothing, user stays } }); ``` ## Configurar el estilo de presentación en iOS \{#configure-ios-presentation-style\} Configura cómo se presenta el paywall en iOS pasando el parámetro `iosPresentationStyle` al método `Present()`. El parámetro acepta los valores `AdaptyUIIOSPresentationStyle.FullScreen` (predeterminado) o `AdaptyUIIOSPresentationStyle.PageSheet`. ```csharp showLineNumbers title="Unity" view.Present(AdaptyUIIOSPresentationStyle.PageSheet, (error) => { // handle the error }); ``` --- # File: unity-handle-paywall-actions --- --- title: "Responder a acciones de botones en el SDK de Unity" description: "Gestiona las acciones de botones de paywall en Unity usando Adapty para una mejor monetización de la app." --- Si estás creando paywalls con el Paywall Builder de Adapty, es fundamental configurar los botones correctamente: 1. Añade un [botón en el Paywall Builder](paywall-buttons) y asígnale una acción existente o crea un ID de acción personalizado. 2. Escribe código en tu app para gestionar cada acción que hayas asignado. Esta guía muestra cómo gestionar acciones personalizadas y predefinidas en tu código. :::warning **Solo las compras y restauraciones se gestionan automáticamente.** El resto de acciones de botones, como cerrar paywalls o abrir enlaces, requieren implementar respuestas específicas en el código de la app. ::: ## Cerrar paywalls \{#close-paywalls\} Para añadir un botón que cierre tu paywall: 1. En el Paywall Builder, añade un botón y asígnale la acción **Close**. 2. En el código de tu app, implementa un handler para la acción `close` que descarte el paywall. ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: view.Dismiss(null); break; default: // handle other events break; } } ``` ## Abrir URLs desde paywalls \{#open-urls-from-paywalls\} :::tip Si quieres añadir un grupo de enlaces (p. ej., términos de uso y restauración de compras), añade un elemento **Link** en el Paywall Builder y gestíonalo igual que los botones con la acción **Open URL**. ::: Para añadir un botón que abra un enlace desde tu paywall (p. ej., **Terms of use** o **Privacy policy**): 1. En el Paywall Builder, añade un botón, asígnale la acción **Open URL** e introduce la URL que quieres abrir. 2. En el código de tu app, implementa un handler para la acción `openUrl` que abra la URL recibida en un navegador. ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.OpenUrl: var urlString = action.Value; if(!string.IsNullOrWhiteSpace(urlString)) { Application.OpenURL(urlString); } break; default: // handle other events break; } } ``` ## Iniciar sesión en la app \{#log-into-the-app\} Para añadir un botón que permita a los usuarios iniciar sesión en tu app: 1. En el Paywall Builder, añade un botón y asígnale la acción **Custom** con el ID `login`. 2. En el código de tu app, implementa un handler para la acción personalizada `login` que identifique a tu usuario. ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Custom: if (action.Value == "login") { // Navigate to login scene SceneManager.LoadScene("LoginScene"); } break; default: // handle other events break; } } ``` ## Gestionar acciones personalizadas \{#handle-custom-actions\} Para añadir un botón que gestione cualquier otra acción: 1. En el Paywall Builder, añade un botón, asígnale la acción **Custom** y asígnale un ID. 2. En el código de tu app, implementa un handler para el ID de acción que hayas creado. Por ejemplo, si tienes otro conjunto de ofertas de suscripción o compras únicas, puedes añadir un botón que muestre otro paywall: ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Custom: if (action.Value == "openNewPaywall") { // Display another paywall ShowAlternativePaywall(); } break; default: // handle other events break; } } private void ShowAlternativePaywall() { // Implement your logic to show alternative paywall } ``` --- # File: unity-handling-events --- --- title: "Gestionar eventos del paywall" description: "Aprende a gestionar eventos del paywall en tu aplicación Unity con el SDK de Adapty." --- :::important Esta guía cubre la gestión de eventos para compras, restauraciones, selección de productos y renderizado del paywall. También debes implementar el manejo de botones (cerrar paywall, abrir enlaces, etc.). Consulta nuestra [guía sobre el manejo de acciones de botones](unity-handle-paywall-actions) para más detalles. ::: Los paywalls configurados con el [Paywall Builder](adapty-paywall-builder) no necesitan código adicional para realizar y restaurar compras. Sin embargo, generan ciertos eventos a los que tu aplicación puede responder. Estos eventos incluyen pulsaciones de botones (botones de cierre, URLs, selecciones de productos, etc.), así como notificaciones sobre acciones relacionadas con compras realizadas en el paywall. A continuación aprenderás cómo responder a estos eventos. :::warning Esta guía es **exclusivamente para paywalls del nuevo Paywall Builder**, que requieren el SDK de Adapty v3.3.0 o posterior. ::: :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: ## Gestión de eventos \{#handling-events\} Para controlar o monitorear los procesos que ocurren en la pantalla del paywall dentro de tu aplicación móvil, implementa la interfaz `AdaptyPaywallsEventsListener`: ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; public class PaywallEventsHandler : MonoBehaviour, AdaptyPaywallsEventsListener { void Start() { Adapty.SetPaywallsEventsListener(this); } // Implement all required interface methods below } ``` ### Eventos generados por el usuario \{#user-generated-events\} #### Paywall mostrado \{#paywall-appeared\} Se invoca cuando la vista del paywall aparece en pantalla. :::note En iOS, también se invoca cuando el usuario pulsa el [botón del web paywall](web-paywall#step-2a-add-a-web-purchase-button) dentro de un paywall y el web paywall se abre en un navegador integrado. ::: ```csharp showLineNumbers title="Unity" public void PaywallViewDidAppear(AdaptyUIPaywallView view) { } ``` #### Paywall ocultado \{#paywall-disappeared\} Se invoca cuando la vista del paywall desaparece de la pantalla. :::note En iOS, también se invoca cuando un [web paywall](web-paywall#step-2a-add-a-web-purchase-button) abierto desde un paywall en un navegador integrado desaparece de la pantalla. ::: ```csharp showLineNumbers title="Unity" public void PaywallViewDidDisappear(AdaptyUIPaywallView view) { } ``` #### Selección de producto \{#product-selection\} Se invoca cuando se selecciona un producto para comprar (por el usuario o por el sistema). ```csharp showLineNumbers title="Unity" public void PaywallViewDidSelectProduct( AdaptyUIPaywallView view, string productId ) { } ```
## El número de vistas del paywall es demasiado alto \{#the-paywall-view-number-is-too-big\}
**Problema**: El contador de vistas del paywall muestra el doble del número esperado.
**Causa**: Es posible que estés llamando a `LogShowPaywall` en tu código, lo que duplica el contador de vistas cuando se usa el Paywall Builder. Para los paywalls diseñados con el Paywall Builder, el seguimiento de análisis es automático, por lo que no es necesario usar este método.
**Solución**: Asegúrate de no llamar a `LogShowPaywall` en tu código si estás usando el Paywall Builder.
## Otros problemas \{#other-issues\}
**Problema**: Estás experimentando otros problemas relacionados con el Paywall Builder que no se han cubierto anteriormente.
**Solución**: Si es necesario, migra el SDK a la versión más reciente usando las [guías de migración](unity-sdk-migration-guides). Muchos problemas se resuelven en versiones más nuevas del SDK.
---
# File: unity-quickstart-manual
---
---
title: "Habilitar compras en tu paywall personalizado con Unity SDK"
description: "Integra el SDK de Adapty en tus paywalls personalizados de Unity para habilitar compras in-app."
---
Esta guía describe cómo integrar Adapty en tus paywalls personalizados. Mantén el control total sobre la implementación del paywall, mientras el SDK de Adapty obtiene los productos, gestiona las nuevas compras y restaura las anteriores.
:::important
**Esta guía está dirigida a desarrolladores que implementan paywalls personalizados.** Si quieres la forma más sencilla de habilitar compras, usa el [Adapty Paywall Builder](unity-quickstart-paywalls). Con Paywall Builder, creas paywalls en un editor visual sin código, Adapty gestiona toda la lógica de compras automáticamente y puedes probar distintos diseños sin volver a publicar tu app.
:::
## Antes de empezar \{#before-you-start\}
### Configura los productos \{#set-up-products\}
Para habilitar las compras in-app, necesitas entender tres conceptos clave:
- [**Productos**](product) – cualquier cosa que los usuarios pueden comprar (suscripciones, consumibles, acceso de por vida)
- [**Paywalls**](paywalls) – configuraciones que definen qué productos ofrecer. En Adapty, los paywalls son la única forma de obtener productos, pero este diseño te permite modificar productos, precios y ofertas sin tocar el código de tu app.
- [**Placements**](placements) – dónde y cuándo muestras los paywalls en tu app (como `main`, `onboarding`, `settings`). Configuras los paywalls para los placements en el dashboard y luego los solicitas por ID de placement en tu código. Esto facilita ejecutar pruebas A/B y mostrar distintos paywalls a diferentes usuarios.
Asegúrate de entender estos conceptos incluso si trabajas con tu paywall personalizado. Básicamente, son solo tu forma de gestionar los productos que vendes en tu app.
Para implementar tu paywall personalizado, necesitarás crear un **paywall** y añadirlo a un **placement**. Esta configuración te permite obtener tus productos. Para saber qué debes hacer en el dashboard, sigue la guía de inicio rápido [aquí](quickstart).
### Gestiona usuarios \{#manage-users\}
Puedes trabajar con o sin autenticación de backend en tu lado.
Sin embargo, el SDK de Adapty gestiona de forma diferente a los usuarios anónimos e identificados. Lee la [guía de inicio rápido de identificación](unity-quickstart-identify) para entender las particularidades y asegurarte de que trabajas correctamente con los usuarios.
## Paso 1. Obtén los productos \{#step-1-get-products\}
Para obtener los productos de tu paywall personalizado, necesitas:
1. Obtener el objeto `paywall` pasando el ID del [placement](placements) al método `getPaywall`.
2. Obtener el array de productos para este paywall usando el método `getPaywallProducts`.
```csharp showLineNumbers
using AdaptySDK;
void LoadPaywall() {
Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => {
if (error != null) {
// Handle the error
return;
}
Adapty.GetPaywallProducts(paywall, (products, productsError) => {
if (productsError != null) {
// Handle the error
return;
}
// Use products to build your custom paywall UI
});
});
}
```
## Paso 2. Acepta compras \{#step-2-accept-purchases\}
Cuando un usuario toca un producto en tu paywall personalizado, llama al método `makePurchase` con el producto seleccionado. Esto gestionará el flujo de compra y devolverá el perfil actualizado.
```csharp showLineNumbers
using AdaptySDK;
void PurchaseProduct(AdaptyPaywallProduct product) {
Adapty.MakePurchase(product, (result, error) => {
if (error != null) {
// Handle the error
return;
}
switch (result.Type) {
case AdaptyPurchaseResultType.Success:
var profile = result.Profile;
// Purchase successful, profile updated
break;
case AdaptyPurchaseResultType.UserCancelled:
// User canceled the purchase
break;
case AdaptyPurchaseResultType.Pending:
// Purchase is pending (e.g., user will pay offline with cash)
break;
}
});
}
```
## Paso 3. Restaura compras \{#step-3-restore-purchases\}
Los app stores requieren que todas las apps con suscripciones ofrezcan una forma de que los usuarios puedan restaurar sus compras.
Llama al método `restorePurchases` cuando el usuario toque el botón de restaurar. Esto sincronizará su historial de compras con Adapty y devolverá el perfil actualizado.
```csharp showLineNumbers
using AdaptySDK;
void RestorePurchases() {
Adapty.RestorePurchases((profile, error) => {
if (error != null) {
// Handle the error
return;
}
// Restore successful, profile updated
});
}
```
## Próximos pasos \{#next-steps\}
:::tip
¿Tienes preguntas o estás teniendo algún problema? Consulta nuestro [foro de soporte](https://adapty.featurebase.app/) donde encontrarás respuestas a preguntas frecuentes o podrás plantear las tuyas. ¡Nuestro equipo y la comunidad están aquí para ayudarte!
:::
Tu paywall está listo para mostrarse en la app. Prueba tus compras en el [sandbox de App Store](test-purchases-in-sandbox) o en [Google Play Store](testing-on-android) para asegurarte de que puedes completar una compra de prueba desde el paywall.
A continuación, [comprueba si los usuarios han completado su compra](unity-check-subscription-status) para determinar si mostrar el paywall o dar acceso a las funciones de pago.
---
# File: fetch-paywalls-and-products-unity
---
---
title: "Obtener paywalls y productos para paywalls con Remote Config en Unity SDK"
description: "Obtén paywalls y productos en el SDK de Unity de Adapty para mejorar la monetización de los usuarios."
---
Antes de mostrar paywalls con Remote Config y personalizados, necesitas obtener la información sobre ellos. Ten en cuenta que este tema hace referencia a paywalls con Remote Config y personalizados. Para obtener orientación sobre cómo recuperar paywalls creados con Paywall Builder, consulta [Obtener paywalls de Paywall Builder y su configuración](unity-get-pb-paywalls).
:::tip
¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas.
:::
opcional
por defecto: `en`
|El identificador de la [localización del paywall](add-remote-config-locale). Se espera que este parámetro sea un código de idioma compuesto por una o más subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de idioma](unity-localizations-and-locale-codes) para más información sobre los códigos de idioma y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen conexiones a internet inestables, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.
El SDK de Adapty almacena los paywalls en dos capas: la caché actualizada regularmente descrita anteriormente y los [paywalls de respaldo](unity-use-fallback-paywalls). También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo límite, se devolverán los datos en caché o el respaldo local.
Ten en cuenta que en casos excepcionales este método puede superar ligeramente el tiempo especificado en `loadTimeout`, ya que la operación puede constar de diferentes solicitudes internamente.
| ¡No escribas los IDs de producto en el código! Dado que los paywalls se configuran de forma remota, los productos disponibles, el número de productos y las ofertas especiales (como pruebas gratuitas) pueden cambiar con el tiempo. Asegúrate de que tu código gestione estos escenarios. Por ejemplo, si inicialmente obtienes 2 productos, tu app debería mostrar esos 2 productos. Sin embargo, si más adelante obtienes 3 productos, tu app debería mostrar los 3 sin requerir cambios en el código. Lo único que tienes que incluir en el código es el ID del placement. Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | Un objeto [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) con: una lista de IDs de producto, el identificador del paywall, el Remote Config y varias otras propiedades. | ## Obtener productos \{#fetch-products\} Una vez que tienes el paywall, puedes consultar el array de productos correspondiente: ```csharp showLineNumbers Adapty.GetPaywallProducts(paywall, (products, error) => { if(error != null) { // handle the error return; } // products - the requested products array }); ``` Parámetros de respuesta: | Parámetro | Descripción | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | Lista de objetos [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html) con: identificador del producto, nombre del producto, precio, moneda, duración de la suscripción y varias otras propiedades. | Al implementar tu propio diseño de paywall, probablemente necesitarás acceder a estas propiedades del objeto [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html). A continuación se muestran las propiedades más utilizadas, pero consulta el documento enlazado para obtener todos los detalles de las propiedades disponibles. | Propiedad | Descripción | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | Para mostrar el título del producto, usa `product.LocalizedTitle`. Ten en cuenta que la localización se basa en el país del store seleccionado por el usuario, no en el idioma del propio dispositivo. | | **Price** | Para mostrar una versión localizada del precio, usa `product.Price.LocalizedString`. Esta localización se basa en la configuración regional del dispositivo. También puedes acceder al precio como número usando `product.Price.Amount`. El valor se proporcionará en la moneda local. Para obtener el símbolo de moneda asociado, usa `product.Price.CurrencySymbol`. | | **Subscription Period** | Para mostrar el período (p. ej., semana, mes, año, etc.), usa `product.Subscription?.LocalizedPeriod`. Esta localización se basa en la configuración regional del dispositivo. Para obtener el período de suscripción mediante programación, usa `product.Subscription?.Period`. Desde ahí puedes acceder al enum `Unit` para obtener la duración (es decir, `AdaptySubscriptionPeriodUnit.Day`, `AdaptySubscriptionPeriodUnit.Week`, `AdaptySubscriptionPeriodUnit.Month`, `AdaptySubscriptionPeriodUnit.Year` o `AdaptySubscriptionPeriodUnit.Unknown`). El valor `NumberOfUnits` te dará el número de unidades del período. Por ejemplo, para una suscripción trimestral, verías `AdaptySubscriptionPeriodUnit.Month` en la propiedad Unit y `3` en la propiedad NumberOfUnits. | | **Introductory Offer** | Para mostrar un distintivo u otro indicador de que una suscripción incluye una oferta introductoria, revisa la propiedad `product.Subscription?.Offer?.Phases`. Esta es una lista que puede contener hasta dos fases de descuento: la fase de prueba gratuita y la fase de precio introductorio. Dentro de cada objeto de fase están las siguientes propiedades útiles:opcional
por defecto: `en`
|El identificador de la localización del paywall. Se espera que este parámetro sea un código de idioma compuesto por una o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre obtengan los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen conexiones a internet inestables, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, los usuarios podrían no obtener los datos más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de la calidad de su conexión. La caché se actualiza regularmente, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.
El SDK de Adapty almacena los paywalls localmente en dos capas: la caché actualizada regularmente descrita anteriormente y los paywalls de respaldo. También usamos CDN para obtener los paywalls más rápido y un servidor de respaldo independiente en caso de que el CDN no esté disponible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus paywalls, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| --- # File: present-remote-config-paywalls-unity --- --- title: "Renderizar paywall diseñado con Remote Config en Unity SDK" description: "Descubre cómo presentar paywalls con Remote Config en Adapty Unity SDK para personalizar la experiencia de usuario." --- Si has personalizado un paywall usando Remote Config, necesitarás implementar el renderizado en el código de tu app para mostrárselo a los usuarios. Como Remote Config ofrece flexibilidad adaptada a tus necesidades, tú decides qué incluir y cómo se ve tu paywall. Proporcionamos un método para obtener la configuración remota, dándote la autonomía de mostrar tu paywall personalizado configurado a través de Remote Config. ## Obtener el Remote Config del paywall y presentarlo \{#get-paywall-remote-config-and-present-it\} Para obtener el Remote Config de un paywall, accede a la propiedad `remoteConfig` y extrae los valores que necesites. ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => { if (error != null) { // handle the error return; } // Access remote config dictionary var dictionary = paywall.RemoteConfig?.Dictionary; var headerText = dictionary?["header_text"] as string; // Or access raw JSON data var jsonData = paywall.RemoteConfig?.Data; }); ``` En este punto, una vez que hayas recibido todos los valores necesarios, es momento de renderizarlos y ensamblarlos en una página visualmente atractiva. Asegúrate de que el diseño se adapte a distintos tamaños de pantalla y orientaciones de dispositivos móviles, garantizando una experiencia fluida y amigable en todos los dispositivos. :::warning Asegúrate de [registrar el evento de visualización del paywall](present-remote-config-paywalls-unity#track-paywall-view-events) tal como se describe a continuación, para que los análisis de Adapty puedan recopilar información para los embudos y las pruebas A/B. ::: Una vez que hayas terminado de mostrar el paywall, continúa configurando el flujo de compra. Cuando el usuario realice una compra, simplemente llama a `.MakePurchase()` con el producto de tu paywall. Para más detalles sobre el método `.MakePurchase()`, consulta [Realizar compras](unity-making-purchases). Te recomendamos [crear un paywall de respaldo denominado paywall de respaldo](unity-use-fallback-paywalls). Este respaldo se mostrará al usuario cuando no haya conexión a internet ni caché disponible, garantizando una experiencia fluida incluso en esas situaciones. ## Registrar eventos de visualización del paywall \{#track-paywall-view-events\} Adapty te ayuda a medir el rendimiento de tus paywalls. Aunque recopilamos datos de compras automáticamente, registrar las visualizaciones del paywall requiere tu intervención, ya que solo tú sabes cuándo un usuario ve un paywall. Para registrar un evento de visualización del paywall, simplemente llama a `.LogShowPaywall(paywall)` y se reflejará en las métricas de tu paywall en los embudos y las pruebas A/B. :::important No es necesario llamar a `.LogShowPaywall(paywall)` si estás mostrando paywalls creados en el [Paywall Builder](adapty-paywall-builder). ::: ```csharp showLineNumbers Adapty.LogShowPaywall(paywall, (error) => { // handle the error }); ``` Parámetros de la solicitud: | Parámetro | Presencia | Descripción | | :---------- | :-------- |:------------------------------------------------------------------| | **paywall** | obligatorio | Un objeto [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). | --- # File: unity-making-purchases --- --- title: "Realizar compras in-app en Unity SDK" description: "Guía sobre cómo gestionar compras in-app y suscripciones con Adapty." --- Mostrar paywalls dentro de tu aplicación móvil es un paso esencial para ofrecer a los usuarios acceso a contenido o servicios premium. Sin embargo, simplemente mostrar estos paywalls solo es suficiente para gestionar las compras si usas [Paywall Builder](adapty-paywall-builder) para personalizar tus paywalls. Si no usas el Paywall Builder, debes usar un método independiente llamado `.makePurchase()` para completar una compra y desbloquear el contenido deseado. Este método es la puerta de entrada para que los usuarios interactúen con los paywalls y realicen sus transacciones. Si tu paywall tiene una oferta promocional activa para el producto que el usuario intenta comprar, Adapty la aplicará automáticamente en el momento de la compra. :::warning Ten en cuenta que la oferta introductoria solo se aplicará de forma automática si usas paywalls configurados con el Paywall Builder. En otros casos, necesitarás [verificar la elegibilidad del usuario para una oferta introductoria en iOS](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios). Omitir este paso puede provocar que tu app sea rechazada durante la revisión. Además, podría suponer cobrar el precio completo a usuarios que son elegibles para una oferta introductoria. ::: Asegúrate de haber completado la [configuración inicial](quickstart) sin saltarte ningún paso. Sin ella, no podemos validar las compras. ## Realizar una compra \{#make-purchase\} :::note **¿Usas [Paywall Builder](adapty-paywall-builder)?** Las compras se procesan automáticamente; puedes saltarte este paso. **¿Buscas una guía paso a paso?** Consulta la [guía de inicio rápido](unity-implement-paywalls-manually) para obtener instrucciones de implementación completas con todo el contexto. ::: ```csharp showLineNumbers using AdaptySDK; void MakePurchase(AdaptyPaywallProduct product) { Adapty.MakePurchase(product, (result, error) => { switch (result.Type) { case AdaptyPurchaseResultType.Pending: // handle pending purchase break; case AdaptyPurchaseResultType.UserCancelled: // handle purchase cancellation break; case AdaptyPurchaseResultType.Success: var profile = result.Profile; // handle successfull purchase break; default: break; } }); } ``` Parámetros de la solicitud: | Parámetro | Presencia | Descripción | | :---------- | :-------- |:------------------------------------------------------------------------------------------------------| | **Product** | requerido | Un objeto [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html) obtenido del paywall. | Parámetros de respuesta: | Parámetro | Descripción | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** |Si la solicitud se ha realizado correctamente, la respuesta contiene este objeto. Un objeto [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html) proporciona información completa sobre los niveles de acceso, suscripciones y compras únicas de un usuario dentro de la app.
Comprueba el estado del nivel de acceso para determinar si el usuario tiene el acceso necesario a la app.
| :::warning **Nota:** si todavía usas una versión de StoreKit de Apple inferior a v2.0 y una versión del SDK de Adapty inferior a v2.9.0, debes proporcionar el [secreto compartido de Apple App Store](app-store-connection-configuration#step-5-enter-app-store-shared-secret) en su lugar. Este método está actualmente obsoleto por Apple. ::: ## Cambiar la suscripción al realizar una compra \{#change-subscription-when-making-a-purchase\} Cuando un usuario elige una suscripción nueva en lugar de renovar la actual, el funcionamiento depende del store: - En el App Store, la suscripción se actualiza automáticamente dentro del grupo de suscripciones. Si un usuario compra una suscripción de un grupo mientras ya tiene activa otra de un grupo distinto, ambas suscripciones estarán activas al mismo tiempo. - En Google Play, la suscripción no se actualiza automáticamente. Tendrás que gestionar el cambio en el código de tu app tal como se describe a continuación. Para reemplazar la suscripción por otra en Android, llama al método `.makePurchase()` con el parámetro adicional: ```csharp showLineNumbers // Create subscription update parameters var subscriptionUpdateParams = new AdaptySubscriptionUpdateParameters( "old_product_id", // Product ID of the current subscription AdaptySubscriptionUpdateReplacementMode.WithTimeProration ); Adapty.MakePurchase(product, subscriptionUpdateParams, (profile, error) => { if(error != null) { // Handle the error return; } // successful cross-grade }); ``` Parámetro de solicitud adicional: | Parámetro | Presencia | Descripción | | :--------------------------- | :-------- |:-------------------------------------------------------------------------------------------------------| | **subscriptionUpdateParams** | obligatorio | un objeto [`AdaptySubscriptionUpdateParameters`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_subscription_update_parameters.html). | Puedes leer más sobre suscripciones y modos de reemplazo en la documentación para desarrolladores de Google: - [Acerca de los modos de reemplazo](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [Recomendaciones de Google para los modos de reemplazo](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - Modo de reemplazo [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE()). Nota: este método solo está disponible para actualizaciones de suscripción. No se admiten cambios a un plan inferior. - Modo de reemplazo [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED()). Nota: el cambio real de suscripción solo se producirá cuando finalice el período de facturación actual. ## Canjear códigos de oferta en iOS \{#redeem-offer-codes-in-ios\}Un objeto [`AdaptyProfile`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). Este modelo contiene información sobre los niveles de acceso, suscripciones y compras únicas.
Comprueba el **estado del nivel de acceso** para determinar si el usuario tiene acceso a la app.
| :::tip ¿Quieres ver un ejemplo real de cómo se integra el SDK de Adapty en una app móvil? Echa un vistazo a nuestras [apps de ejemplo](sample-apps), que muestran la configuración completa, incluyendo la visualización de paywalls, la realización de compras y otras funcionalidades básicas. ::: --- # File: implement-observer-mode-unity --- --- title: "Implementar el modo Observer en el SDK de Unity" description: "Implementa el modo observer en Adapty para registrar eventos de suscripción de usuarios en el SDK de Unity." --- Si ya tienes tu propia infraestructura de compras y no estás listo para migrar completamente a Adapty, puedes explorar el [modo Observer](observer-vs-full-mode). En su forma básica, el modo Observer ofrece analíticas avanzadas e integración fluida con sistemas de atribución y analíticas. Si esto cubre tus necesidades, solo tienes que: 1. Activarlo al configurar el SDK de Adapty estableciendo el parámetro `observerMode` en `true`. Sigue las instrucciones de configuración para [Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk). 2. [Reportar transacciones](report-transactions-observer-mode-unity) desde tu infraestructura de compras existente a Adapty. ### Configuración del modo Observer \{#observer-mode-setup\} Activa el modo Observer si gestionas las compras y el estado de suscripción por tu cuenta y utilizas Adapty para enviar eventos de suscripción y analíticas. :::important Cuando se ejecuta en modo Observer, el SDK de Adapty no cerrará ninguna transacción, así que asegúrate de gestionarlo tú mismo. ::: ```csharp showLineNumbers title="C#" using UnityEngine; using AdaptySDK; public class AdaptyListener : MonoBehaviour, AdaptyEventListener { void Start() { DontDestroyOnLoad(this.gameObject); Adapty.SetEventListener(this); var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetObserverMode(true); // Enable observer mode Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); } public void OnLoadLatestProfile(AdaptyProfile profile) { } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } } ``` Parámetros: | Parámetro | Descripción | |--------------|----------------------------------------------------------------------------------------------------------------| | observerMode | Un valor booleano que controla el [modo Observer](observer-vs-full-mode). El valor por defecto es `false`. | ## Usar los paywalls de Adapty en el modo Observer \{#using-adapty-paywalls-in-observer-mode\} Si también quieres usar los paywalls y las funciones de pruebas A/B de Adapty, puedes hacerlo, pero requiere algo de configuración adicional en el modo Observer. Esto es lo que necesitarás hacer además de los pasos anteriores: 1. Muestra los paywalls de la forma habitual para [paywalls con Remote Config](present-remote-config-paywalls-unity). 3. [Asocia los paywalls](report-transactions-observer-mode-unity) con las transacciones de compra. --- # File: report-transactions-observer-mode-unity --- --- title: "Reportar transacciones en Observer Mode en el SDK de Unity" description: "Reporta transacciones de compras en el Observer Mode de Adapty para obtener información sobre usuarios y seguimiento de ingresos en el SDK de Unity." ---Para iOS, StoreKit 1: un objeto [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction).
Para iOS, StoreKit 2: objeto [Transaction](https://developer.apple.com/documentation/storekit/transaction).
Para Android: Identificador de cadena (purchase.getOrderId de la compra, donde la compra es una instancia de la clase [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) de la biblioteca de facturación).
| | variationId | requerido | El identificador de cadena de la variante. Puedes obtenerlo usando la propiedad `variationId` del objeto [AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html). |phoneNumber
firstName
lastName
| String | | gender | Enum, los valores permitidos son: `female`, `male`, `other` | | birthday | Date | ### Atributos de usuario personalizados \{#custom-user-attributes\} Puedes definir tus propios atributos personalizados. Normalmente están relacionados con el uso de tu app. Por ejemplo, en apps de fitness podrían ser el número de ejercicios por semana; en apps de aprendizaje de idiomas, el nivel de conocimiento del usuario, etc. Puedes utilizarlos en segmentos para crear paywalls y ofertas segmentadas, y también en análisis para identificar qué métricas de producto influyen más en los ingresos. ```csharp showLineNumbers try { builder = builder.SetCustomStringAttribute("string_key", "string_value"); builder = builder.SetCustomDoubleAttribute("double_key", 123.0f); } catch (Exception e) { // handle the exception } ``` Para eliminar una clave existente, usa el método `.withRemoved(customAttributeForKey:)`: ```csharp showLineNumbers try { builder = builder.RemoveCustomAttribute("key_to_remove"); } catch (Exception e) { // handle the exception } ``` A veces necesitas saber qué atributos personalizados ya se han establecido. Para ello, usa el campo `customAttributes` del objeto `AdaptyProfile`. :::warning Ten en cuenta que el valor de `customAttributes` puede estar desactualizado, ya que los atributos de usuario pueden enviarse desde distintos dispositivos en cualquier momento, por lo que los atributos en el servidor pueden haber cambiado desde la última sincronización. ::: ### Límites \{#limits\} - Hasta 30 atributos personalizados por usuario - Los nombres de clave pueden tener hasta 30 caracteres. El nombre de la clave puede incluir caracteres alfanuméricos y cualquiera de los siguientes: `_` `-` `.` - El valor puede ser una cadena de texto o un número flotante con un máximo de 50 caracteres. --- # File: unity-listen-subscription-changes --- --- title: "Comprobar el estado de la suscripción en Unity SDK" description: "Rastrea y gestiona el estado de la suscripción del usuario en Adapty para mejorar la retención de clientes en tu aplicación Unity." --- Con Adapty, hacer seguimiento del estado de la suscripción es muy sencillo. No tienes que insertar manualmente los IDs de producto en tu código. En cambio, puedes confirmar fácilmente el estado de suscripción de un usuario comprobando si tiene un [nivel de acceso](access-level) activo.Un objeto [AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html). En general, solo tienes que comprobar el estado del nivel de acceso del perfil para determinar si el usuario tiene acceso premium a la app.
El método `.getProfile` proporciona el resultado más actualizado, ya que siempre intenta consultar la API. Si por algún motivo (por ejemplo, sin conexión a internet) el SDK de Adapty no puede obtener información del servidor, se devuelven los datos de la caché. También es importante tener en cuenta que el SDK de Adapty actualiza la caché de `AdaptyProfile` de forma periódica para mantener esta información lo más actualizada posible.
| El método `.getProfile()` te proporciona el perfil del usuario a partir del cual puedes obtener el estado del nivel de acceso. Puedes tener múltiples niveles de acceso por app. Por ejemplo, si tienes una app de noticias y vendes suscripciones a diferentes temáticas de forma independiente, puedes crear los niveles de acceso "sports" y "science". Sin embargo, la mayoría de las veces solo necesitarás un nivel de acceso; en ese caso, puedes usar simplemente el nivel de acceso "premium" predeterminado. Aquí tienes un ejemplo para comprobar el nivel de acceso "premium" predeterminado: ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // "premium" is an identifier of default access level var accessLevel = profile.AccessLevels["premium"]; if (accessLevel != null && accessLevel.IsActive) { // grant access to premium features } }); ``` ### Escuchar actualizaciones del estado de la suscripción \{#listening-for-subscription-status-updates\} Cada vez que la suscripción del usuario cambia, Adapty lanza un evento. Para recibir mensajes de Adapty, necesitas hacer una configuración adicional: ```csharp showLineNumbers // Extend `AdaptyEventListener ` with `OnLoadLatestProfile ` method: public class AdaptyListener : MonoBehaviour, AdaptyEventListener { public void OnLoadLatestProfile(AdaptyProfile profile) { // handle any changes to subscription state } } ``` Adapty también lanza un evento al inicio de la aplicación. En ese caso, se pasará el estado de suscripción almacenado en caché. ### Caché del estado de la suscripción \{#subscription-status-cache\} La caché implementada en el SDK de Adapty almacena el estado de suscripción del perfil. Esto significa que, incluso si el servidor no está disponible, se puede acceder a los datos en caché para obtener información sobre el estado de suscripción del perfil. No obstante, hay que tener en cuenta que no es posible solicitar datos directamente desde la caché. El SDK consulta periódicamente el servidor cada minuto para comprobar si hay actualizaciones o cambios relacionados con el perfil. Si hay modificaciones, como nuevas transacciones u otras actualizaciones, se enviarán a los datos en caché para mantenerlos sincronizados con el servidor. --- # File: unity-deal-with-att --- --- title: "Gestionar ATT en el SDK de Unity" description: "Comienza con Adapty en Unity para simplificar la configuración y gestión de suscripciones." --- Si tu aplicación utiliza el framework AppTrackingTransparency y presenta al usuario una solicitud de autorización de seguimiento de la app, debes enviar el [estado de autorización](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) a Adapty. ```csharp showLineNumbers var builder = new Adapty.ProfileParameters.Builder() .SetAppTrackingTransparencyStatus(IOSAppTrackingTransparencyStatus.Authorized); Adapty.UpdateProfile(builder.Build(), (error) => { if(error != null) { // handle the error } }); ``` :::warning Te recomendamos encarecidamente que envíes este valor lo antes posible cuando cambie; solo así los datos se enviarán a tiempo a las integraciones que hayas configurado. ::: --- # File: kids-mode-unity --- --- title: "Kids Mode en Unity SDK" description: "Activa fácilmente el Modo Niños para cumplir con las políticas de Apple y Google. No se recopilan IDFA, GAID ni datos publicitarios en Unity SDK." --- Si tu aplicación Unity está destinada a niños, debes seguir las políticas de [Apple](https://developer.apple.com/kids/) y [Google](https://support.google.com/googleplay/android-developer/answer/9893335). Si usas el SDK de Adapty, unos pocos pasos sencillos te ayudarán a configurarlo para cumplir con estas políticas y superar las revisiones de las tiendas. ## ¿Qué se necesita? \{#whats-required\} Debes configurar el SDK de Adapty para desactivar la recopilación de: - [IDFA (Identifier for Advertisers)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) (iOS) - [Android Advertising ID (AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) (Android) - [Dirección IP](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) Además, te recomendamos usar el ID de usuario del cliente con cuidado. Un ID en formato `opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto de uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
Consulta [Localizaciones y códigos de localización](flutter-localizations-and-locale-codes) para más información sobre los códigos de localización y cómo recomendamos usarlos.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché actualizada periódicamente descrita anteriormente y los onboardings de respaldo. También usamos CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus onboardings, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| | **loadTimeout** | por defecto: 5 seg |Este valor limita el tiempo de espera para este método. Si se alcanza el tiempo de espera, se devolverán los datos en caché o el respaldo local.
Ten en cuenta que, en casos excepcionales, este método puede agotar el tiempo de espera un poco más tarde de lo especificado en `loadTimeout`, ya que la operación puede consistir en diferentes solicitudes internas.
| Parámetros de respuesta: | Parámetro | Descripción | |:----------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | Un objeto [`AdaptyOnboarding`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_onboarding.html) con: el identificador y la configuración del onboarding, Remote Config y otras propiedades. | Tras obtener el onboarding, llama al método `CreateOnboardingView`. :::warning El resultado del método `CreateOnboardingView` solo puede usarse una vez. Si necesitas usarlo de nuevo, llama al método `CreateOnboardingView` otra vez. Llamarlo dos veces sin volver a crearlo puede provocar el error `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers AdaptyUI.CreateOnboardingView(onboarding, (view, error) => { // handle the result }); ``` Parámetros: | Parámetro | Presencia | Descripción | |:---------------| :------------- |:-----------------------------------------------------------------------------| | **onboarding** | obligatorio | Un objeto `AdaptyOnboarding` para obtener una vista del onboarding deseado. | | **externalUrlsPresentation** |opcional
por defecto: `InAppBrowser`
|Controla cómo se abren los enlaces en el onboarding. Opciones disponibles:
- `AdaptyWebPresentation.InAppBrowser` - Abre los enlaces en un navegador dentro de la app (por defecto)
- `AdaptyWebPresentation.ExternalBrowser` - Abre los enlaces en el navegador externo del dispositivo
Consulta [Personalizar cómo se abren los enlaces en los onboardings](unity-present-onboardings#customize-how-links-open-in-onboardings) para ver ejemplos de uso.
| Una vez que hayas cargado correctamente el onboarding y su configuración de vista, puedes [mostrarlo en tu app móvil](unity-present-onboardings). ## Acelerar la obtención del onboarding con el onboarding de audiencia por defecto \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} Normalmente, los onboardings se obtienen casi de inmediato, por lo que no necesitas preocuparte por acelerar este proceso. Sin embargo, en los casos en que tienes numerosas audiencias y onboardings, y tus usuarios tienen una conexión a internet débil, obtener un onboarding puede tardar más de lo que te gustaría. En estas situaciones, puede que quieras mostrar un onboarding por defecto para garantizar una experiencia de usuario fluida en lugar de no mostrar ninguno. Para resolver esto, puedes usar el método `GetOnboardingForDefaultAudience`, que obtiene el onboarding del placement especificado para la audiencia **All Users**. Sin embargo, es fundamental entender que el enfoque recomendado es obtener el onboarding con el método `getOnboarding`, tal como se detalla en la sección [Obtener el onboarding](#fetch-onboarding) anterior. :::warning Considera usar `GetOnboarding` en lugar de `GetOnboardingForDefaultAudience`, ya que este último tiene limitaciones importantes: - **Problemas de compatibilidad**: Puede generar problemas al admitir varias versiones de la app, lo que requiere diseños compatibles con versiones anteriores o aceptar que las versiones más antiguas puedan mostrarse incorrectamente. - **Sin personalización**: Solo muestra contenido para la audiencia "All Users", eliminando la segmentación basada en país, atribución o atributos personalizados. Si una obtención más rápida supera estos inconvenientes para tu caso de uso, usa `GetOnboardingForDefaultAudience` como se muestra a continuación. De lo contrario, usa `GetOnboarding` como se describe [arriba](#fetch-onboarding). ::: ```csharp showLineNumbers Adapty.GetOnboardingForDefaultAudience("YOUR_PLACEMENT_ID", (onboarding, error) => { if (error != null) { // handle the error return; } // the requested onboarding }); ``` Parámetros: | Parámetro | Presencia | Descripción | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | obligatorio | El identificador del [Placement](placements) deseado. Es el valor que especificaste al crear un placement en el Adapty Dashboard. | | **locale** |opcional
por defecto: `en`
|El identificador de la localización del onboarding. Se espera que este parámetro sea un código de idioma compuesto de uno o dos subetiquetas separadas por el carácter menos (**-**). La primera subetiqueta corresponde al idioma y la segunda a la región.
Ejemplo: `en` significa inglés, `pt-br` representa el portugués de Brasil.
| | **fetchPolicy** | por defecto: `.reloadRevalidatingCacheData` |Por defecto, el SDK intentará cargar los datos desde el servidor y devolverá los datos en caché en caso de fallo. Recomendamos esta opción porque garantiza que tus usuarios siempre reciban los datos más actualizados.
Sin embargo, si crees que tus usuarios tienen una conexión a internet inestable, considera usar `.returnCacheDataElseLoad` para devolver los datos en caché si existen. En este caso, es posible que los usuarios no obtengan los datos absolutamente más recientes, pero experimentarán tiempos de carga más rápidos, independientemente de lo inestable que sea su conexión. La caché se actualiza con regularidad, por lo que es seguro usarla durante la sesión para evitar solicitudes de red.
Ten en cuenta que la caché permanece intacta al reiniciar la app y solo se borra cuando se reinstala la app o mediante limpieza manual.
El SDK de Adapty almacena los onboardings localmente en dos capas: la caché actualizada periódicamente descrita anteriormente y los onboardings de respaldo. También usamos CDN para obtener los onboardings más rápido y un servidor de respaldo independiente en caso de que el CDN no sea accesible. Este sistema está diseñado para garantizar que siempre obtengas la versión más reciente de tus onboardings, asegurando la fiabilidad incluso cuando la conexión a internet es escasa.
| --- # File: unity-present-onboardings --- --- title: "Presentar onboardings en Unity SDK" description: "Aprende cómo presentar onboardings de forma efectiva para conseguir más conversiones." --- Si has personalizado un onboarding con el builder, no tienes que preocuparte por renderizarlo en el código de tu app Unity para mostrárselo al usuario. Ese onboarding ya contiene tanto lo que se debe mostrar como la forma en que debe mostrarse. Antes de empezar, asegúrate de que: 1. Has instalado [Adapty Unity SDK](sdk-installation-unity) 3.14.0 o posterior. 2. Has [creado un onboarding](create-onboarding). 3. Has añadido el onboarding a un [placement](placements). Para mostrar un onboarding, usa el método `view.Present()` en el `view` creado por el método `CreateOnboardingView`. Cada `view` solo puede usarse una vez. Si necesitas mostrar el paywall de nuevo, llama a `CreateOnboardingView` otra vez para crear una nueva instancia de `view`. :::warning Reutilizar el mismo `view` sin recrearlo puede producir un error `AdaptyUIError.viewAlreadyPresented`. ::: ```csharp showLineNumbers title="Unity" view.Present((presentError) => { if (presentError != null) { // handle the error } }; ``` ## Configurar el estilo de presentación en iOS \{#configure-ios-presentation-style\} Configura cómo se presenta el onboarding en iOS pasando el parámetro `iosPresentationStyle` al método `Present()`. El parámetro acepta los valores `AdaptyUIIOSPresentationStyle.FullScreen` (predeterminado) o `AdaptyUIIOSPresentationStyle.PageSheet`. ```csharp showLineNumbers title="Unity" view.Present(AdaptyUIIOSPresentationStyle.PageSheet, (error) => { // handle the error }); ``` ## Personaliza cómo se abren los enlaces en los onboardings \{#customize-how-links-open-in-onboardings\} :::important La personalización de cómo se abren los enlaces en los onboardings es compatible a partir de Adapty SDK v3.15. ::: Por defecto, los enlaces en los onboardings se abren en un navegador integrado en la app, lo que ofrece una experiencia fluida al mostrar páginas web dentro de tu aplicación sin cambiar de app. Para abrir los enlaces en un navegador externo, pasa `AdaptyWebPresentation.ExternalBrowser` al método `CreateOnboardingView`: ```csharp showLineNumbers title="Unity" AdaptyUI.CreateOnboardingView( onboarding, AdaptyWebPresentation.ExternalBrowser, // default — InAppBrowser (view, error) => { if (error != null) { // handle the error return; } // present the onboarding view view.Present((presentError) => { if (presentError != null) { // handle the error } }); } ); ``` Opciones disponibles: - `AdaptyWebPresentation.InAppBrowser` - Abre los enlaces en un navegador integrado (por defecto) - `AdaptyWebPresentation.ExternalBrowser` - Abre los enlaces en el navegador externo del dispositivo --- # File: unity-handling-onboarding-events --- --- title: "Manejar eventos de onboarding en Unity SDK" description: "Maneja eventos relacionados con onboarding en Unity usando Adapty." --- Antes de empezar, asegúrate de que: 1. Has instalado el [SDK de Adapty para Unity](sdk-installation-unity) 3.14.0 o posterior. 2. Has [creado un onboarding](create-onboarding). 3. Has añadido el onboarding a un [placement](placements). Los onboardings configurados con el builder generan eventos a los que tu app puede responder. A continuación se explica cómo hacerlo. Para controlar o monitorizar los procesos que ocurren en la pantalla de onboarding dentro de tu app de Unity, implementa la interfaz `AdaptyOnboardingsEventsListener`. ## Acciones personalizadas \{#custom-actions\} En el builder, puedes añadir una acción **personalizada** a un botón y asignarle un ID.
Luego, puedes usar este ID en tu código y gestionarlo como una acción personalizada. Por ejemplo, si un usuario pulsa un botón personalizado, como **Login** o **Allow notifications**, el método `OnboardingViewOnCustomAction` se activará con el parámetro `actionId` siendo el **Action ID** del builder. Puedes crear tus propios IDs, como "allowNotifications".
Para gestionar los eventos del onboarding, implementa la interfaz `AdaptyOnboardingsEventsListener`:
```csharp showLineNumbers title="Unity"
public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener
{
void Start()
{
Adapty.SetOnboardingsEventsListener(this);
}
public void OnboardingViewOnCustomAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
string actionId
)
{
if (actionId == "allowNotifications") {
// request notification permissions
}
}
public void OnboardingViewDidFailWithError(
AdaptyUIOnboardingView view,
AdaptyError error
)
{
// handle errors
}
// Implement other required interface methods (see examples below)
}
```
:::important
Ten en cuenta que debes gestionar qué ocurre cuando el usuario cierra el onboarding. Por ejemplo, debes dejar de mostrar el onboarding en sí.
:::
Implementa el método `OnboardingViewOnCloseAction` en tu clase:
```csharp showLineNumbers title="Unity"
public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener
{
public void OnboardingViewOnCloseAction(
AdaptyUIOnboardingView view,
AdaptyUIOnboardingMeta meta,
string actionId
)
{
view.Dismiss((error) => {
if (error != null) {
// handle the error
}
});
}
// ... other interface methods
}
```
2. Haz clic en el nombre del grupo de suscripción. Verás tus productos listados en la sección **Subscriptions**.
3. Asegúrate de que el producto que estás probando aparece como **Ready to Submit**.
4. Compara el ID del producto de la tabla con el que aparece en la pestaña [**Products**](https://app.adapty.io/products) del Adapty Dashboard. Si los IDs no coinciden, copia el ID del producto de la tabla y [crea un producto](create-product) con ese ID en el Adapty Dashboard.
## Paso 3. Comprueba la disponibilidad del producto \{#step-4-check-product-availability\}
1. Vuelve a **App Store Connect** y abre la misma sección **Subscriptions**.
2. Haz clic en el nombre del grupo de suscripción para ver tus productos.
3. Selecciona el producto que estás probando.
4. Desplázate hasta la sección **Availability** y comprueba que todos los países y regiones requeridos están en la lista.
## Paso 4. Comprueba los precios del producto \{#step-5-check-product-prices\}
1. De nuevo, ve a la sección **Monetization** → **Subscriptions** en **App Store Connect**.
2. Haz clic en el nombre del grupo de suscripción.
3. Selecciona el producto que estás probando.
4. Desplázate hacia abajo hasta **Subscription Pricing** y despliega la sección **Current Pricing for New Subscribers**.
5. Asegúrate de que todos los precios requeridos están en la lista.
## Paso 5. Comprueba que el estado de pago de la app, la cuenta bancaria y los formularios fiscales están activos \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\}
1. En la página de inicio de [**App Store Connect**](https://appstoreconnect.apple.com/), haz clic en **Business**.
2. Selecciona el nombre de tu empresa.
3. Desplázate hacia abajo y comprueba que tu **Paid Apps Agreement**, **Bank Account** y **Tax forms** aparecen todos como **Active**.
Siguiendo estos pasos deberías poder resolver la advertencia `InvalidProductIdentifiers` y publicar tus productos en el store.
## Paso 6. Vuelve a crear el producto si está bloqueado \{#step-6-recreate-the-product-if-its-stuck\}
Puede que los pasos 1 a 5 pasen todos correctamente — estado `Approved`, Bundle ID correcto, API key válida — y aun así el SDK siga devolviendo `1000 noProductIDsFound`. En ese caso, es posible que el producto esté bloqueado en el registro de Apple. El registro de productos de Apple puede entrar en un estado en el que un producto existe en la interfaz de App Store Connect pero no está expuesto en la ruta de búsqueda de StoreKit.
Elimina el producto en App Store Connect y vuelve a crearlo con el mismo ID de producto. Espera hasta 24 horas después de volver a crearlo para que los cambios se propaguen.
---
# File: cantMakePayments-unity
---
---
title: "Solución para el error Code-1003 cantMakePayment en el SDK de Unity"
description: "Resuelve el error de pagos al gestionar suscripciones en Adapty."
---
El error 1003, `cantMakePayments`, indica que no es posible realizar compras in-app en este dispositivo.
Si encuentras el error `cantMakePayments`, normalmente se debe a una de estas razones:
- Restricciones del dispositivo: El error no está relacionado con Adapty. Consulta las soluciones más abajo.
- Configuración del modo Observer: El método `makePurchase` y el modo Observer no pueden usarse al mismo tiempo. Consulta la sección más abajo.
## Problema: Restricciones del dispositivo \{#issue-device-restrictions\}
| Problema | Solución |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| Restricciones de Screen Time | Desactiva las restricciones de compras in-app en [Screen Time](https://support.apple.com/en-us/102470) |
| Cuenta suspendida | Contacta con el soporte de Apple para resolver problemas con la cuenta |
| Restricciones regionales | Usa una cuenta de App Store de una región compatible |
## Problema: Usar el modo Observer y makePurchase a la vez \{#issue-using-both-observer-mode-and-makepurchase\}
Si usas `makePurchases` para gestionar las compras, no necesitas el modo Observer. El [modo Observer](observer-vs-full-mode) solo es necesario si implementas la lógica de compra tú mismo.
Por lo tanto, si usas `makePurchase`, puedes eliminar sin problema la activación del modo Observer del código de inicialización del SDK.
---
# File: migration-to-unity-sdk-314
---
---
title: "Migrar el SDK de Adapty para Unity a v3.14"
description: "Migra al SDK de Adapty para Unity v3.14 para obtener mejor rendimiento y nuevas funcionalidades de monetización."
---
El SDK de Adapty 3.14.0 es una versión mayor que incluye mejoras que, sin embargo, pueden requerir algunos pasos de migración por tu parte:
1. Listener de eventos separado para eventos de paywall.
2. Cambiar el nombre de `AdaptyUI.CreateView` a `AdaptyUI.CreatePaywallView` y métodos relacionados.
3. Actualizar el método `MakePurchase` para usar `AdaptyPurchaseParameters` en lugar de parámetros individuales.
4. Reemplazar `SetFallbackPaywalls` con el método `SetFallback`.
5. Actualizar el acceso a propiedades del paywall para usar `AdaptyPlacement`.
6. Actualizar el acceso a la configuración remota para usar el objeto `AdaptyRemoteConfig`.
7. Reemplazar `VendorProductIds` con `ProductIdentifiers` en el modelo `AdaptyPaywall`.
8. Actualizar la política de fetch de `GetPaywall` para usar `AdaptyFetchPolicy`.
## Receptor de eventos separado para eventos de paywall \{#separate-event-listener-for-paywall-events\}
Si muestras paywalls diseñados con el [Paywall Builder](adapty-paywall-builder), los eventos de vista de paywall ahora utilizan la interfaz `AdaptyPaywallsEventsListener` y el método `SetPaywallsEventsListener` dedicados. La interfaz principal `AdaptyEventListener` se mantiene para las actualizaciones de perfil y los detalles de instalación.
```diff showLineNumbers
using UnityEngine;
using AdaptySDK;
public class AdaptyListener : MonoBehaviour,
- AdaptyEventListener {
+ AdaptyEventListener,
+ AdaptyPaywallsEventsListener {
void Start() {
Adapty.SetEventListener(this);
+ Adapty.SetPaywallsEventsListener(this);
}
// AdaptyEventListener methods
public void OnLoadLatestProfile(AdaptyProfile profile) { }
public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { }
public void OnInstallationDetailsFail(AdaptyError error) { }
+ // AdaptyPaywallsEventsListener methods
+ // Implement paywall event handlers here
}
```
[Más información sobre el manejo de eventos de paywall](unity-handling-events).
## Renombrar los métodos de creación y presentación de vistas \{#rename-view-creation-and-presentation-methods\}
Los métodos de creación y presentación de vistas han sido renombrados:
```diff showLineNumbers
using AdaptySDK;
- AdaptyUI.CreateView(paywall, parameters, (view, error) => {
+ AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => {
if (error != null) {
// handle the error
return;
}
- AdaptyUI.PresentView(view, (error) => {
+ AdaptyUI.PresentPaywallView(view, (error) => {
// handle the error
});
});
}
```
Del mismo modo, el método de cierre ha sido renombrado:
```diff showLineNumbers
- AdaptyUI.DismissView(view, (error) => {
+ AdaptyUI.DismissPaywallView(view, (error) => {
// handle the error
});
```
## Actualizar el método MakePurchase \{#update-makepurchase-method\}
El método `MakePurchase` ahora usa `AdaptyPurchaseParameters` en lugar de los argumentos individuales `subscriptionUpdateParams` e `isOfferPersonalized`. Esto proporciona mayor seguridad de tipos y permite ampliar los parámetros de compra en el futuro.
```diff showLineNumbers
using AdaptySDK;
void MakePurchase(
AdaptyPaywallProduct product,
AdaptySubscriptionUpdateParameters subscriptionUpdate,
bool? isOfferPersonalized
) {
- Adapty.MakePurchase(product, subscriptionUpdate, isOfferPersonalized, (result, error) => {
+ var parameters = new AdaptyPurchaseParametersBuilder()
+ .SetSubscriptionUpdateParams(subscriptionUpdate)
+ .SetIsOfferPersonalized(isOfferPersonalized)
+ .Build();
+
+ Adapty.MakePurchase(product, parameters, (result, error) => {
switch (result.Type) {
case AdaptyPurchaseResultType.Pending:
// handle pending purchase
break;
case AdaptyPurchaseResultType.UserCancelled:
// handle purchase cancellation
break;
case AdaptyPurchaseResultType.Success:
var profile = result.Profile;
// handle successful purchase
break;
default:
break;
}
});
}
```
Si no se necesitan parámetros adicionales, puedes usar simplemente:
```csharp showLineNumbers
using AdaptySDK;
void MakePurchase(AdaptyPaywallProduct product) {
Adapty.MakePurchase(product, (result, error) => {
// handle purchase result
});
}
```
## Actualizar el método de respaldo \{#update-fallback-method\}
:::important
Al actualizar al SDK de Unity 3.14, deberás descargar los nuevos archivos de respaldo desde el Adapty Dashboard y reemplazar los existentes en tu proyecto.
:::
El método para configurar los respaldos ha sido actualizado. El método `SetFallbackPaywalls` ha sido renombrado a `SetFallback`:
```diff showLineNumbers
using AdaptySDK;
void SetFallBackPaywalls() {
#if UNITY_IOS
var assetId = "adapty_fallback_ios.json";
#elif UNITY_ANDROID
var assetId = "adapty_fallback_android.json";
#else
var assetId = "";
#endif
- Adapty.SetFallbackPaywalls(assetId, (error) => {
+ Adapty.SetFallback(assetId, (error) => {
// handle the error
});
}
```
Consulta el ejemplo de código completo en la página [Usar paywalls de respaldo en Unity](unity-use-fallback-paywalls).
## Actualizar el acceso a propiedades del paywall \{#update-paywall-property-access\}
Las siguientes propiedades se han movido de `AdaptyPaywall` a `AdaptyPlacement`:
```diff showLineNumbers
using AdaptySDK;
void ProcessPaywall(AdaptyPaywall paywall) {
- var abTestName = paywall.ABTestName;
- var audienceName = paywall.AudienceName;
- var revision = paywall.Revision;
- var placementId = paywall.PlacementId;
+ var abTestName = paywall.Placement.ABTestName;
+ var audienceName = paywall.Placement.AudienceName;
+ var revision = paywall.Placement.Revision;
+ var placementId = paywall.Placement.Id;
}
```
## Actualizar el acceso a la configuración remota \{#update-remote-config-access\}
Las propiedades de Remote Config se han reestructurado en un objeto `AdaptyRemoteConfig` para una mejor organización:
```diff showLineNumbers
using AdaptySDK;
void ProcessRemoteConfig(AdaptyPaywall paywall) {
- var remoteConfigString = paywall.RemoteConfigString;
- var locale = paywall.Locale;
- var remoteConfigDict = paywall.RemoteConfig;
+ var remoteConfigString = paywall.RemoteConfig.Data;
+ var locale = paywall.RemoteConfig.Locale;
+ var remoteConfigDict = paywall.RemoteConfig.Dictionary;
}
```
## Actualización del uso del modelo AdaptyPaywall \{#update-adaptypaywall-model-usage\}
La propiedad `VendorProductIds` ha quedado obsoleta en favor de `ProductIdentifiers`. La nueva propiedad devuelve objetos `AdaptyProductIdentifier` en lugar de simples cadenas de texto, lo que proporciona información de producto más estructurada.
```diff showLineNumbers
using AdaptySDK;
void ProcessPaywallProducts(AdaptyPaywall paywall) {
- var productIds = paywall.VendorProductIds;
- foreach (var vendorId in productIds) {
- // use vendorId
- }
+ var productIdentifiers = paywall.ProductIdentifiers;
+ foreach (var productId in productIdentifiers) {
+ var vendorId = productId.VendorProductId;
+ // use vendorId
+ }
}
```
El objeto `AdaptyProductIdentifier` proporciona acceso al ID del producto del proveedor a través de la propiedad `VendorProductId`, manteniendo la misma funcionalidad y ofreciendo una mejor estructura para mejoras futuras.
## Actualizar la política de obtención en GetPaywall \{#update-getpaywall-fetch-policy\}
El tipo del parámetro `fetchPolicy` en el método `GetPaywall` ha cambiado de `AdaptyPaywallFetchPolicy` a `AdaptyPlacementFetchPolicy`. Este cambio unifica el uso de la política de obtención en todo el SDK.
```diff showLineNumbers
using AdaptySDK;
void GetPaywall(string placementId) {
- Adapty.GetPaywall(placementId, AdaptyPaywallFetchPolicy.ReloadRevalidatingCacheData, null, (paywall, error) => {
+ Adapty.GetPaywall(placementId, AdaptyPlacementFetchPolicy.ReloadRevalidatingCacheData, null, (paywall, error) => {
// handle the result
});
}
```
---
# File: migration-to-unity-sdk-34
---
---
title: "Migrar Adapty Unity SDK a v. 3.4"
description: "Migra al Adapty Unity SDK v3.4 para mejorar el rendimiento y acceder a nuevas funciones de monetización."
---
Adapty SDK 3.4.0 es una versión mayor que incluye mejoras que requieren pasos de migración por tu parte.
## Actualizar los archivos de paywall de respaldo \{#update-fallback-paywall-files\}
Actualiza los archivos de paywall de respaldo para garantizar la compatibilidad con la nueva versión del SDK:
1. [Descarga los archivos de paywall de respaldo actualizados](fallback-paywalls) desde el Adapty Dashboard.
2. [Reemplaza los paywalls de respaldo existentes en tu aplicación móvil](unity-use-fallback-paywalls) con los nuevos archivos.
## Actualiza la implementación del modo Observer \{#update-implementation-of-observer-mode\}
Si utilizas el modo Observer, asegúrate de actualizar su implementación.
Anteriormente, se usaban distintos métodos para reportar transacciones a Adapty. En la nueva versión, el método `reportTransaction` debe usarse de forma consistente tanto en Android como en iOS. Este método reporta explícitamente cada transacción a Adapty, asegurando que sea reconocida. Si se utilizó un paywall, pasa el ID de variación para vincular la transacción a él.
:::warning
**¡No omitas el reporte de transacciones!**
Si no llamas a `reportTransaction`, Adapty no reconocerá la transacción, no aparecerá en los análisis y no se enviará a las integraciones.
:::
```diff showLineNumbers
- #if UNITY_ANDROID && !UNITY_EDITOR
- Adapty.RestorePurchases((profile, error) => {
- // handle the error
- });
- #endif
Adapty.ReportTransaction(
"YOUR_TRANSACTION_ID",
"PAYWALL_VARIATION_ID", // optional
(error) => {
// handle the error
});
```
---
# File: migration-to-unity330
---
---
title: "Migrar el SDK de Adapty para Unity a v3.3"
description: "Migra al SDK de Adapty para Unity v3.3 para mejorar el rendimiento y acceder a nuevas funciones de monetización."
---
Adapty SDK 3.3.0 es una versión mayor que incluye mejoras que, sin embargo, pueden requerir algunos pasos de migración por tu parte.
1. Actualiza a Adapty SDK v3.3.x.
2. Se han renombrado varias clases, propiedades y métodos en los módulos Adapty y AdaptyUI del SDK de Adapty.
3. A partir de ahora, el método `SetLogLevel` acepta un callback como argumento.
4. A partir de ahora, el método `PresentCodeRedemptionSheet` acepta un callback como argumento.
5. Cambia la forma en que se crea la vista del paywall.
6. Elimina el método `GetProductsIntroductoryOfferEligibility`.
7. Guarda los paywalls de respaldo en archivos separados (uno por plataforma) en `Assets/StreamingAssets/` y pasa los nombres de los archivos al método `SetFallbackPaywalls`.
8. Actualiza la lógica de compra.
9. Actualiza el manejo de eventos del Paywall Builder.
10. Actualiza el manejo de errores del paywall en el Paywall Builder.
11. Actualiza las configuraciones de integración para Adjust, Amplitude, AppMetrica, Appsflyer, Branch, Firebase y Google Analytics, Mixpanel, OneSignal, Pushwoosh.
13. Actualiza la implementación del modo Observer.
14. Actualiza la inicialización del plugin de Unity con una llamada explícita a `Activate`.
## Actualización del SDK de Adapty para Unity a la versión 3.3.x \{#upgrade-adapty-unity-sdk-to-33x\}
Hasta esta versión, el SDK de Adapty era el núcleo obligatorio necesario para el correcto funcionamiento de Adapty en tu app, mientras que el SDK de AdaptyUI era opcional y solo se necesitaba si usabas el Paywall Builder de Adapty.
A partir de la versión 3.3.0, el SDK de AdaptyUI queda obsoleto y AdaptyUI se integra en el SDK de Adapty como un módulo. Debido a estos cambios, es necesario eliminar AdaptyUI SDK y reinstalar Adapty SDK.
1. Elimina las dependencias de los paquetes **AdaptySDK** y **AdaptyUISDK** de tu proyecto.
2. Borra las carpetas **AdaptySDK** y **AdaptyUISDK**.
3. Importa de nuevo el paquete AdaptySDK como se describe en la página [Instalación y configuración del SDK de Adapty para Unity](sdk-installation-unity).
## Cambios de nombre \{#renamings\}
1. Renombrar en el módulo de Adapty:
| Versión antigua | Nueva versión |
| ------------------------- | ------------------------ |
| Adapty.sdkVersion | Adapty.SDKVersion |
| Adapty.LogLevel | AdaptyLogLevel |
| Adapty.Paywall | AdaptyPaywall |
| Adapty.PaywallFetchPolicy | AdaptyPaywallFetchPolicy |
| PaywallProduct | AdaptyPaywallProduct |
| Adapty.Profile | AdaptyProfile |
| Adapty.ProfileParameters | AdaptyProfileParameters |
| ProfileGender | AdaptyProfileGender |
| Error | AdaptyError |
2. Renombrar en el módulo AdaptyUI:
| Versión anterior | Nueva versión |
| ------------------ | ------------------ |
| CreatePaywallView | CreateView |
| PresentPaywallView | PresentView |
| DismissPaywallView | DismissView |
| AdaptyUI.View | AdaptyUIView |
| AdaptyUI.Action | AdaptyUIUserAction |
## Cambiar el método SetLogLevel \{#change-the-setloglevel-method\}
A partir de ahora, el método `SetLogLevel` acepta un callback como argumento.
```diff showLineNumbers
- Adapty.SetLogLevel(Adapty.LogLevel.Verbose);
+ Adapty.SetLogLevel(Adapty.LogLevel.Verbose, null); // or you can pass the callback to handle the possible error
```
## Cambiar el método PresentCodeRedemptionSheet \{#change-the-presentcoderedemptionsheet-method\}
A partir de ahora, el método `PresentCodeRedemptionSheet` acepta un callback como argumento.
```diff showLineNumbers
- Adapty.PresentCodeRedemptionSheet();
+ Adapty.PresentCodeRedemptionSheet(null); // or you can pass the callback to handle the possible error
```
## Cambiar la forma en que se crea la vista del paywall \{#change-how-the-paywall-view-is-created\}
Para ver el ejemplo de código completo, consulta [Obtener la configuración de vista del paywall diseñado con el Paywall Builder](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder).
```diff showLineNumbers
+ var parameters = new AdaptyUICreateViewParameters()
+ .SetPreloadProducts(true);
- AdaptyUI.CreatePaywallView(
+ AdaptyUI.CreateView(
paywall,
- preloadProducts: true,
+ parameters,
(view, error) => {
// use the view
});
```
## Eliminar el método GetProductsIntroductoryOfferEligibility \{#remove-the-getproductsintroductoryoffereligibility-method\}
Antes de Adapty iOS SDK 3.3.0, el objeto producto siempre incluía las ofertas, independientemente de si el usuario era elegible. Había que comprobar la elegibilidad manualmente antes de usar la oferta.
Ahora, el objeto producto solo incluye una oferta si el usuario es elegible. Esto significa que ya no es necesario comprobar la elegibilidad: si hay una oferta disponible, el usuario es elegible.
## Método actualizado para proporcionar paywalls de respaldo \{#update-method-for-providing-fallback-paywalls\}
Hasta esta versión, los paywalls de respaldo se pasaban como JSON serializado. A partir de la v 3.3.0, el mecanismo ha cambiado:
1. Guarda los paywalls de respaldo en archivos dentro de `/Assets/StreamingAssets/`, un archivo para Android y otro para iOS.
2. Pasa los nombres de los archivos al método `SetFallbackPaywalls`.
Tu código cambiará de la siguiente manera:
```diff showLineNumbers
using AdaptySDK;
void SetFallBackPaywalls() {
+ #if UNITY_IOS
+ var assetId = "adapty_fallback_ios.json";
+ #elif UNITY_ANDROID
+ var assetId = "adapty_fallback_android.json";
+ #else
+ var assetId = "";
+ #endif
- Adapty.SetFallbackPaywalls("FALLBACK_PAYWALLS_JSON_STRING", (error) => {
+ Adapty.SetFallbackPaywalls(assetId, (error) => {
// handle the error
});
}
```
Consulta el ejemplo de código completo en la página [Usar paywalls de respaldo en Unity](unity-use-fallback-paywalls).
## Actualizar la realización de compras \{#update-making-purchase\}
Las compras previamente canceladas y pendientes se consideraban errores y devolvían los códigos `PaymentCancelled` y `PendingPurchase`, respectivamente.
Ahora se usa la nueva clase `AdaptyPurchaseResultType` para procesar compras canceladas, exitosas y pendientes. Actualiza el código de compra de la siguiente manera:
```diff showLineNumbers
using AdaptySDK;
void MakePurchase(AdaptyPaywallProduct product) {
- Adapty.MakePurchase(product, (profile, error) => {
- // handle successfull purchase
+ Adapty.MakePurchase(product, (result, error) => {
+ switch (result.Type) {
+ case AdaptyPurchaseResultType.Pending:
+ // handle pending purchase
+ break;
+ case AdaptyPurchaseResultType.UserCancelled:
+ // handle purchase cancellation
+ break;
+ case AdaptyPurchaseResultType.Success:
+ var profile = result.Profile;
+ // handle successful purchase
+ break;
+ default:
+ break;
}
});
}
```
Mira el ejemplo de código final en la página [Realizar compras en la app móvil](unity-making-purchases).
## Actualización del manejo de eventos del Paywall Builder \{#update-handling-of-paywall-builder-events\}
Las compras canceladas y pendientes ya no se consideran errores; todos estos casos se procesan con el método `PaywallViewDidFinishPurchase`.
1. Elimina el procesamiento del evento de compra cancelada.
2. Actualiza el manejo del evento de compra exitosa de la siguiente manera:
```diff showLineNumbers
- public void OnFinishPurchase(
- AdaptyUI.View view,
- Adapty.PaywallProduct product,
- Adapty.Profile profile
- ) { }
+ public void PaywallViewDidFinishPurchase(
+ AdaptyUIView view,
+ AdaptyPaywallProduct product,
+ AdaptyPurchaseResult purchasedResult
+ ) { }
```
3. Actualiza el manejo de acciones:
```diff showLineNumbers
- public void OnPerformAction(
- AdaptyUI.View view,
- AdaptyUI.Action action
- ) {
+ public void PaywallViewDidPerformAction(
+ AdaptyUIView view,
+ AdaptyUIUserAction action
+ ) {
switch (action.Type) {
- case AdaptyUI.ActionType.Close:
+ case AdaptyUIUserActionType.Close:
view.Dismiss(null);
break;
- case AdaptyUI.ActionType.OpenUrl:
+ case AdaptyUIUserActionType.OpenUrl:
var urlString = action.Value;
if (urlString != null {
Application.OpenURL(urlString);
}
default:
// handle other events
break;
}
}
```
4. Actualiza el manejo del inicio de compra:
```diff showLineNumbers
- public void OnSelectProduct(
- AdaptyUI.View view,
- Adapty.PaywallProduct product
- ) { }
+ public void PaywallViewDidSelectProduct(
+ AdaptyUIView view,
+ string productId
+ ) { }
```
5. Actualiza el manejo de compra fallida:
```diff showLineNumbers
- public void OnFailPurchase(
- AdaptyUI.View view,
- Adapty.PaywallProduct product,
- Adapty.Error error
- ) { }
+ public void PaywallViewDidFailPurchase(
+ AdaptyUIView view,
+ AdaptyPaywallProduct product,
+ AdaptyError error
+ ) { }
```
6. Actualiza el manejo del evento de restauración exitosa:
Check out the final code example in the [Handle paywall events](unity-handling-events) page.
## Actualización del manejo de errores en paywalls del Paywall Builder \{#update-handling-of-paywall-builder-paywall-errors\}
El manejo de errores también ha cambiado; actualiza tu código siguiendo las indicaciones a continuación.
1. Actualiza el manejo de errores de carga de productos:
```diff showLineNumbers
- public void OnFailLoadingProducts(
- AdaptyUI.View view,
- Adapty.Error error
- ) { }
+ public void PaywallViewDidFailLoadingProducts(
+ AdaptyUIView view,
+ AdaptyError error
+ ) { }
```
2. Actualiza el manejo de errores de renderizado:
```diff showLineNumbers
- public void OnFailRendering(
- AdaptyUI.View view,
- Adapty.Error error
- ) { }
+ public void PaywallViewDidFailRendering(
+ AdaptyUIView view,
+ AdaptyError error
+ ) { }
```
## Actualizar la configuración del SDK de integraciones de terceros \{#update-third-party-integration-sdk-configuration\}
A partir de Adapty Unity SDK 3.3.0, hemos actualizado la API pública del método `updateAttribution`. Anteriormente, aceptaba un diccionario `[AnyHashable: Any]`, lo que permitía pasar objetos de atribución directamente desde varios servicios. Ahora requiere un `[String: any Sendable]`, por lo que tendrás que convertir los objetos de atribución antes de pasarlos.
Para garantizar que las integraciones funcionen correctamente con Adapty Unity SDK 3.3.0 y versiones posteriores, actualiza las configuraciones de tu SDK para las siguientes integraciones tal como se describe en las secciones a continuación.
### Adjust
Actualiza el código de tu app como se muestra a continuación. Para ver el ejemplo de código completo, consulta la [configuración del SDK para la integración con Adjust](adjust#connect-your-app-to-adjust).
```diff showLineNumbers
- using static AdaptySDK.Adapty;
using AdaptySDK;
Adjust.GetAdid((adid) => {
- Adjust.GetAttribution((attribution) => {
- Dictionary