---
title: "Pasar datos a flows en el SDK de iOS"
description: "Pasa un valor desde tu app de iOS a un flow y muéstralo en un elemento de texto."
---

> **AI agents**: to search Adapty docs faster and with fewer tokens, install the Adapty skill. Claude Code (self-updating via plugin): `claude plugin marketplace add adaptyteam/adapty-skills && claude plugin install adapty-skills@adapty` — other tools: `npx skills add adaptyteam/adapty-skills --all`

Un [custom tag](flow-custom-tags) es una variable personalizada con un valor proveniente de tu app. Después de seleccionar **Value comes from outside the app** en la configuración de una variable, tu app puede establecer su valor a través del SDK de Adapty. Por ejemplo, un elemento de texto contiene "Coins:" y un custom tag. Si tu app pasa "120" para el tag, los usuarios ven "Coins: 120".

## Antes de empezar \{#before-you-start\}

Necesitas el SDK de Adapty v4 o posterior. Las versiones anteriores a v4 no muestran flows.

## Añade etiquetas personalizadas al flow \{#add-custom-tags-to-the-flow\}

Para mostrar los valores de tu app en un flow, configura etiquetas personalizadas en el builder:

1. [Crea una etiqueta personalizada](flow-custom-tags#create-a-custom-tag) para cada valor que tu app envíe.

   <ZoomImage id="flow-custom-tag-create.webp" width="500px" alt="Formulario para crear una variable con nombre, descripción, tipo de valor String y valor inicial" />

2. [Inserta cada etiqueta en un elemento de texto](flow-custom-tags#add-a-custom-tag-to-a-text-element).
3. Anota el nombre completo de cada etiqueta, incluido su grupo. El código de tu app pasa cada valor con ese nombre. Por ejemplo, si el grupo `user` contiene una etiqueta `streak`, el nombre completo de la etiqueta es `user.streak`.

   <ZoomImage id="flow-custom-tag-full-name.webp" width="500px" alt="Pestaña personalizada del desplegable Añadir variable con la etiqueta streak en el grupo user" />

## Pasar valores de etiquetas personalizadas \{#pass-custom-tag-values\}

Pasa los valores de tu app al parámetro `tagResolver` de `getFlowConfiguration`, como un diccionario `[String: String]`:

- Cada clave es el nombre completo de una etiqueta personalizada, como `user.streak`.
- Cada valor es el texto que verán los usuarios en lugar de la etiqueta.
- Cada valor debe ser legible para personas, como "1.250", no "1250.0". Adapty no lo formatea ni traduce.

```swift showLineNumbers title="Swift"
let customTags = [
    "username": "DragonSlayer42",
    "coins": "1,250",
]

do {
    let flowConfiguration = try await AdaptyUI.getFlowConfiguration(
        forFlow: flow,
        tagResolver: customTags
    )
    // present the flow
} catch {
    // handle the error
}
```

El [modificador `.flow` y `AdaptyFlowView`](ios-present-paywalls#present-flows-and-paywalls-in-swiftui) de SwiftUI y el [controlador de flow](ios-present-paywalls#present-flows-and-paywalls-in-uikit) de UIKit no tienen ningún parámetro para valores de etiquetas personalizadas. Muestran los valores de la configuración del flow que les proporcionas.

Para probar tus etiquetas personalizadas, abre el flow en tu app después de añadir el código que establece sus valores. El canvas del builder y la [vista previa en dispositivos](paywall-device-compatibility-preview#preview-on-devices) solo muestran los valores iniciales: la app móvil de Adapty no establece los valores de las etiquetas personalizadas.

Si tu app ya establece valores de etiquetas personalizadas para paywalls del antiguo Paywall Builder, revisa [en qué se diferencian las etiquetas personalizadas en los flows](migrate-to-flows#custom-tags-from-the-old-paywall-builder).

## Lo que ven los usuarios cuando no hay ningún valor \{#what-users-see-without-a-value\}

Los usuarios ven el **Valor inicial** de una etiqueta personalizada como valor de respaldo en los siguientes casos:

- Tu app no pasa ningún valor para la etiqueta.
- El usuario no ha actualizado tu app a una versión que envíe el valor.
- El nombre en el código de tu app no coincide con el nombre completo de la etiqueta, incluidas las mayúsculas y minúsculas.
- Otra etiqueta personalizada en el mismo elemento de texto no tiene valor. En ese caso, todas las etiquetas personalizadas de ese elemento de texto muestran su valor inicial.

Para no mostrar nada en lugar de una etiqueta, pasa una cadena vacía. Adapty trata una cadena vacía como un valor, por lo que el valor de respaldo no aparece.

## Ejemplo: mostrar un IMC a partir de las respuestas del onboarding \{#example-show-a-bmi-from-onboarding-answers\}

Un flow puede recoger respuestas de los usuarios, y una etiqueta personalizada puede mostrar un valor de tu app. Combina ambas cosas para mostrar a los usuarios un resultado que tu app calcula a partir de sus respuestas, como una puntuación, un plan recomendado o una métrica de salud:

1. Un flow recoge las respuestas y las envía a tu app.
2. Tu app calcula el resultado.
3. Tu app pasa el resultado al siguiente flow como valor de etiqueta personalizada.

En este ejemplo, un flow de onboarding recoge el peso y la altura del usuario. Cuando el usuario cierra el flow de onboarding tras su última pantalla, tu app calcula su índice de masa corporal (IMC). Luego abre un flow de paywall que muestra el IMC.

### Configura los flows \{#set-up-the-flows\}

1. [Crea dos flows](paywall-builder-templates): un flow de onboarding que recoja el peso y la altura del usuario, y un flow de paywall que muestre su IMC.
2. Añade dos campos de tipo [**Number**](builder-inputs-and-forms) al flow de onboarding:
   - Uno para el peso en kilogramos, con el **Element ID** `weight`.
   - Uno para la altura en centímetros, con el **Element ID** `height`.

   En ambos campos, establece el **Format** como **Integer**. Un campo envía su valor como texto, exactamente tal como lo escribe el usuario, y el [código de ejemplo](#pass-the-bmi-to-the-paywall) no interpreta "70.5" y "70,5" de la misma manera. Los números enteros no tienen separador decimal, por lo que el código los lee igual en cualquier idioma.
3. Para asegurarte de que tu app recibe ambos valores, termina el flow de onboarding con una pantalla que no tenga campos. En esa pantalla, añade un botón con la acción [**Close flow**](onboarding-actions#close-flow). Los campos envían sus valores cuando pierden el foco o cuando el usuario pasa a otra pantalla. La acción Close flow no los envía. El código de ejemplo solo abre el paywall si el usuario llegó a la última pantalla.
4. En el flow de paywall, [crea una etiqueta personalizada](flow-custom-tags#create-a-custom-tag) llamada `bmi`. En el campo **Initial value**, introduce un guion (`—`). Los usuarios verán el guion si tu app no pasa ningún IMC.
5. Añade un elemento de texto con las palabras "Your BMI:" al flow de paywall. Después de esas palabras, [inserta la etiqueta personalizada `bmi`](flow-custom-tags#add-a-custom-tag-to-a-text-element).
6. Añade el flow de onboarding a un [placement](placements), por ejemplo `onboarding`. Añade el flow de paywall a un placement con el ID `bmi_paywall`. El código de [Pass the BMI to the paywall](#pass-the-bmi-to-the-paywall) obtiene el paywall usando este ID.

### Pasar el IMC al paywall

Recoge el peso y la altura de los eventos `flow_user_input` del flow de onboarding, como se explica en [Procesar datos de flows](ios-flow-input). Para saber que el usuario llegó a la última pantalla, observa el evento `flow_screen_showed` con `is_last_screen` en `true`, como se explica en [Rastrear vistas de pantalla del flow](ios-flow-screen-views). Cuando el usuario cierre el flow de onboarding después de esa pantalla, calcula el IMC. Luego obtén la configuración del flow del paywall y pasa el IMC para la etiqueta personalizada `bmi`.

El siguiente código es para UIKit. Implementa los métodos de `AdaptyFlowControllerDelegate` en un único view controller, que actúa como delegado tanto del controlador del flow de onboarding como del controlador del paywall. El view controller también debe implementar los métodos de compra y restauración del delegado, que este ejemplo omite. Para verlos, consulta [Presentar flows y paywalls en UIKit](ios-present-paywalls#present-flows-and-paywalls-in-uikit).

```swift showLineNumbers title="Swift"
private var bodyAnswers: [String: String] = [:]
private var reachedLastScreen = false

func flowController(
    _ controller: AdaptyFlowController,
    didReceiveAnalyticEvent name: String,
    params: [String: any Sendable]
) {
    if name == "flow_screen_showed", params["is_last_screen"] as? Bool == true {
        reachedLastScreen = true
        return
    }
    guard name == "flow_user_input",
          let elementId = params["element_id"] as? String,
          let value = params["value"] as? String
    else { return }

    bodyAnswers[elementId] = value
}

func flowControllerDidDisappear(_ controller: AdaptyFlowController) {
    // This delegate receives events from both flows. Reset `bodyAnswers` and
    // `reachedLastScreen` whenever a flow disappears, so that the paywall
    // doesn't open again when the user closes it.
    let answers = bodyAnswers
    let finished = reachedLastScreen
    bodyAnswers.removeAll()
    reachedLastScreen = false

    // Number inputs send their values as strings.
    guard finished,
          let weight = answers["weight"].flatMap({ Double($0) }),
          let height = answers["height"].flatMap({ Double($0) }),
          height > 0
    else { return }

    let heightInMeters = height / 100
    let bmi = weight / (heightInMeters * heightInMeters)

    Task {
        await showBMIPaywall(bmi: bmi.formatted(.number.precision(.fractionLength(1))))
    }
}

func showBMIPaywall(bmi: String) async {
    do {
        let flow = try await Adapty.getFlow(placementId: "bmi_paywall")
        let flowConfiguration = try await AdaptyUI.getFlowConfiguration(
            forFlow: flow,
            tagResolver: ["bmi": bmi]
        )
        let flowController = try AdaptyUI.flowController(
            with: flowConfiguration,
            delegate: self
        )
        present(flowController, animated: true)
    } catch {
        // handle the error
    }
}
```

`formatted` usa el separador decimal de la configuración regional del usuario: "22.7" en inglés, "22,7" en alemán.

En SwiftUI, usa los closures del modificador `.flow` del onboarding en lugar de los métodos del delegado:

- `didReceiveAnalyticEvent`: Recoge el peso y la altura, y espera el evento `flow_screen_showed` de la última pantalla.
- `didDisappear`: Si el usuario llegó a la última pantalla, calcula el IMC. Luego obtén la configuración del flow del paywall y pasa el IMC para el tag personalizado `bmi`. Presenta esa configuración con un segundo modificador `.flow`.

### Guardar el IMC en el perfil del usuario \{#save-the-bmi-to-the-users-profile\}

Para mostrar distintos flows a los usuarios según su IMC, guárdalo como un [atributo personalizado](setting-user-attributes#custom-user-attributes) de su perfil. En el Adapty Dashboard, [crea un atributo personalizado de tipo **Number**](segments#custom-attributes) con la clave `bmi`. Luego muestra cada flow a una [audiencia](audience) definida a partir de ese atributo.

Llama al método `updateProfile` en `flowControllerDidDisappear`, justo después de la línea que calcula `bmi`. Pasa el `Double`, no el string formateado, para que un segmento pueda comparar el IMC con un umbral:

```swift showLineNumbers title="Swift"
do {
    let params = try AdaptyProfileParameters.Builder()
        .with(customAttribute: bmi, forKey: "bmi")
        .build()
    try await Adapty.updateProfile(params: params)
} catch {
    // handle the error
}
```