Traiter les données des flows dans le SDK iOS

Lorsqu’un utilisateur saisit quelque chose dans un champ de saisie, répond à un quiz ou active un interrupteur dans un flow, le SDK transmet la valeur à votre application via son callback d’analytics.

Les applications utilisent le plus souvent ces données pour :

  • Enregistrer les utilisateurs sur votre propre backend : récupérez l’adresse e-mail et le nom saisis dans votre onboarding, puis créez leur compte à la fermeture du flow.
  • Sauvegarder les réponses et préférences : suivez ce que l’utilisateur a choisi pour que votre app puisse en tenir compte plus tard — par exemple, écrivez-les dans son profil Adapty comme attributs personnalisés.
  • Personnaliser les flows futurs : enregistrez les réponses du quiz comme attributs personnalisés, puis ciblez un placement ultérieur pour que chaque segment voie un flow différent, ou un paywall différent à l’intérieur.
  • Alimenter des plateformes d’analytics tierces : transmettez les réponses à Amplitude, Mixpanel ou tout autre outil d’analyse produit que vous utilisez.

Les champs de saisie et les groupes sélectionnables transmettent automatiquement leurs valeurs. Pour les distinguer dans votre code, attribuez à chaque champ un Element ID significatif et à chaque groupe sélectionnable un Group ID dans le builder.

Avant de commencer

Vous avez besoin de :

  • Adapty SDK v4 ou supérieur : Les callbacks de flow n’existent pas dans les versions antérieures.
  • Un flow créé dans le Flow & Paywall Builder : Seuls les flows transmettent les valeurs d’entrée via ce callback.
  • Une version de flow publiée récemment : Un flow ne transmet les valeurs d’entrée que si vous l’avez publié après que cette fonctionnalité soit devenue disponible. Si rien ne parvient à votre application, publiez une nouvelle version du flow et réessayez.

Recevoir les valeurs saisies

Les valeurs saisies arrivent dans le même callback que tous les autres événements analytiques d’un flow, sous le nom d’événement flow_user_input. Enregistrez le callback avec vos autres gestionnaires d’événements de flow.

La closure et la méthode du délégué reçoivent les deux mêmes arguments, le code qui lit la valeur est donc identique dans les deux cas.

Le callback didReceiveAnalyticEvent transmet tous les événements analytiques d’un flow, y compris les vues d’écran.

  • Le paramètre name contient le nom de l’événement. Pour filtrer les événements de saisie utilisateur, comparez name à flow_user_input.
  • Le paramètre element_type indique la catégorie de l’élément.
  • La valeur saisie est stockée dans différents paramètres selon le type d’élément :
    • Les champs texte, les sélecteurs et les bascules stockent la saisie de l’utilisateur dans value
    • Les groupes sélectionnables indiquent les options actives dans item_ids et item_titles
func handleFlowInput(name: String, params: [String: any Sendable]) {
    guard name == "flow_user_input",
          let elementId = params["element_id"] as? String,
          let elementType = params["element_type"] as? String
    else { return }

    // The screen the input sits on. Pair it with elementId to tell apart
    // two fields that share an Element ID on different screens.
    let screenId = params["instanceId"] as? String

    switch elementType {
    case "text_input", "email_input", "number_input", "phone_input":
        let text = params["value"] as? String
    case "date_picker", "time_picker", "date_time_picker":
        // Integer Unix time in milliseconds, not the seconds Date expects.
        let date = (params["value"] as? Int).map { Date(timeIntervalSince1970: Double($0) / 1000) }
    case "single_choice":
        let optionId = (params["item_ids"] as? [String])?.first
    case "multi_choice":
        let optionIds = params["item_ids"] as? [String]
    case "toggle":
        let isOn = params["value"] as? Bool
    default:
        break
    }
}

Pour confirmer que le callback se déclenche, interagissez avec le champ de saisie dans une version de test de votre application. Si votre gestionnaire de callback ne reçoit pas d’événement, vérifiez les prérequis. Assurez-vous que le flow a bien été publié après que cette fonctionnalité est devenue disponible.

Quand votre application reçoit l’entrée

Important

La valeur saisie ou sélectionnée par défaut n’est jamais transmise à votre application via ce callback. Si un utilisateur accepte l’option marquée Set as default et continue, aucun événement ne se déclenche. Ne considérez pas l’absence d’événement comme « aucune réponse » — l’utilisateur a simplement conservé la valeur par défaut.

Les éléments suivants déclenchent cet événement :

  • Champs texte, e-mail, numérique et téléphone
  • Sélecteurs de date, d’heure et de date-heure
  • Groupes sélectionnables à choix unique et à choix multiple, et bascules

Les éléments suivants ne le déclenchent pas :

  • Champs de mot de passe, sélections de produits et changements d’onglet
  • Les saisies à l’intérieur d’un élément Header, partagé entre les écrans
  • Les groupes sélectionnables avec des identifiants d’élément dupliqués ou manquants, ou dont l’identifiant de groupe est réutilisé sur un autre écran. Un tel groupe n’envoie rien du tout, plutôt qu’une réponse partielle.

L’événement se déclenche lorsque :

  • Un champ perd le focus. Un champ vidé signale une chaîne vide ; un champ que l’utilisateur n’a jamais modifié ne signale rien. Un espace réservé n’est pas une valeur. Si l’utilisateur revient sur le champ, le modifie et le quitte à nouveau, un second événement est émis.
  • L’utilisateur ferme un sélecteur après avoir choisi une nouvelle valeur. Le fermer sans modification ne signale rien.
  • L’utilisateur appuie sur une option ou une bascule. Un événement à choix multiple liste toutes les options sélectionnées ; désélectionner la dernière envoie donc deux tableaux vides.

L’événement ne se déclenche pas lorsque :

  • L’utilisateur saisit du texte. Il n’y a pas de flux de frappes clavier, seulement la valeur que contient le champ au moment où il perd le focus.
  • L’utilisateur soumet ou ferme le flow. Une valeur encore en cours de saisie à cet instant peut être perdue ; la section limites de livraison explique comment concevoir le dernier écran en tenant compte de cela.
  • Une valeur est définie sans interaction de l’utilisateur. Une option marquée Set as default est présélectionnée à l’ouverture de l’écran, et une action Set Variable peut sélectionner une option ou remplir un champ depuis une autre interaction. Aucune des deux n’envoie d’événement ; une saisie préremplie n’est signalée que lorsque l’utilisateur la modifie.

Ce que vous recevez

Le callback transmet deux événements. Filtrez par name pour n’afficher que les événements flow_user_input. La charge utile JSON de la réponse ressemble à ceci :

{
  "name": "flow_user_input",
  "instanceId": "scr_registration",
  "isBackendEvent": false,
  "isCustomerEvent": true,
  "element_id": "email",
  "element_type": "email_input",
  "value": "jane@example.com"
}
ParamètreDescription
nameflow_user_input pour les événements de saisie, flow_screen_showed pour les affichages d’écran.
instanceIdL’ID de l’écran contenant le champ de saisie. Les IDs d’éléments sont uniques au sein d’un écran, pas dans l’ensemble du flow. Si votre flow comporte des champs de saisie sur plusieurs écrans, combinez instanceId avec element_id pour filtrer les événements.
element_idL’Element ID du champ de saisie, ou le Group ID du groupe sélectionnable.
element_typeLe type d’élément qui a envoyé l’événement. Il détermine lequel des paramètres ci-dessous contient la valeur saisie.
valueChamps texte, sélecteurs et bascules uniquement. La valeur saisie : une chaîne pour les champs texte, un entier pour les sélecteurs, un booléen pour les bascules.
item_idsGroupes sélectionnables à choix unique et à choix multiple uniquement. Les Element IDs des options sélectionnées, dans l’ordre d’apparition des options dans le builder. Une entrée pour un groupe à choix unique ; un nombre quelconque pour un groupe à choix multiple.
item_titlesGroupes sélectionnables à choix unique et à choix multiple uniquement. Les titres des options listées dans item_ids, dans le même ordre. Jamais vide : une option sans titre renvoie son ID à la place.
isCustomerEventIndicateur utilitaire, toujours true pour cet événement. Il identifie les événements que le SDK transmet à votre callback. Utile si un seul handler transfère tous les événements du flow vers vos analytics et que vous filtrez sur cet indicateur plutôt que sur name.
isBackendEventIndicateur utilitaire, toujours false pour cet événement. Il identifie les événements qu’Adapty enregistre également pour ses propres analytics. false confirme que ce que les utilisateurs saisissent ne parvient qu’à votre application — Adapty ne le reçoit pas et ne le stocke pas.

Ce que chaque élément remonte :

Dans le builderelement_typeParamètre contenant la valeurCe qu’il contient
Champ Texte, Nombre, Numéro de téléphonetext_input, number_input, phone_inputvalueLa chaîne brute saisie par l’utilisateur. Les nombres arrivent sous forme de chaînes, et non de types numériques.
Champ E-mailemail_inputvalueLa chaîne brute saisie par l’utilisateur, même si elle n’a pas passé la validation de format du builder. Validez-la de votre côté avant de l’utiliser.
Champ Mot de passeaucunaucunN’envoie aucun événement.
Champ Datedate_pickervalueHorodatage Unix en millisecondes, sous forme d’entier, à minuit heure locale de la date sélectionnée.
Champ Heuretime_pickervalueHorodatage Unix en millisecondes, sous forme d’entier, arrondi à la minute inférieure.
Champ Date et heuredate_picker et time_pickervalueDeux éléments : un sélecteur de date et un sélecteur d’heure. Chacun envoie son propre événement.
Champ passé en mode Date et heure dans le menu déroulant Typedate_time_pickervalueHorodatage Unix en millisecondes, sous forme d’entier, arrondi à la minute inférieure.
Groupe à choix uniquesingle_choiceitem_ids, item_titlesDeux tableaux. item_ids : un tableau contenant l’Element ID de l’option sélectionnée. item_titles : un tableau contenant le titre de cette option.
Groupe à choix multiplemulti_choiceitem_ids, item_titlesDeux tableaux. item_ids : les Element IDs de toutes les options sélectionnées, dans l’ordre d’apparition dans le builder. item_titles : leurs titres, dans le même ordre. Les deux tableaux sont vides si rien n’est sélectionné.
Groupe BasculetogglevalueUn booléen.

Pour brancher votre logique selon une réponse, comparez item_ids, pas item_titles. Un titre est dérivé : l’Element Title de l’option si vous en avez défini un, sinon son texte dans votre langue par défaut, sinon son Element ID. Un utilisateur ayant consulté le flow dans une autre langue a vu un texte différent.

Exemples d’événements

Ces exemples montrent les propriétés disponibles pour chaque événement, avec des valeurs illustratives en commentaires.

Text, email, number, and phone input (Click to expand)
func handleFlowInput(name: String, params: [String: any Sendable]) {
    name;                      // "flow_user_input"
    params["name"];            // "flow_user_input"
    params["instanceId"];      // "scr_J260KU5q"
    params["isCustomerEvent"]; // true
    params["isBackendEvent"];  // false
    params["element_id"];      // "email"
    params["element_type"];    // "email_input"
    params["value"];           // "jane@example.com"   (String)
}
Sélecteurs de date, d’heure et de date-heure (Cliquez pour développer)
func handleFlowInput(name: String, params: [String: any Sendable]) {
    params["element_id"];      // "birthday"
    params["element_type"];    // "date_picker"
    params["value"];           // 645408000000   (Unix milliseconds — 1990-06-15, local midnight)
}
Choix unique (Cliquez pour développer)
func handleFlowInput(name: String, params: [String: any Sendable]) {
    params["element_id"];      // "experience"
    params["element_type"];    // "single_choice"
    params["item_ids"];        // ["pro"]
    params["item_titles"];     // ["I train professionally"]
}
Multi choice (Click to expand)
func handleFlowInput(name: String, params: [String: any Sendable]) {
    params["element_id"];      // "interests"
    params["element_type"];    // "multi_choice"
    params["item_ids"];        // ["sports", "music"]
    params["item_titles"];     // ["Sports", "Music"]
}
Toggle (Click to expand)
func handleFlowInput(name: String, params: [String: any Sendable]) {
    params["element_id"];      // "reminders"
    params["element_type"];    // "toggle"
    params["value"];           // true   (Bool)
}

Livraison et limitations

Warning

Les flows transmettent les valeurs brutes — adresses e-mail, numéros de téléphone et tout ce qu’un utilisateur saisit. Traitez tout ce que le callback analytics vous fournit comme des données personnelles, et ne les écrivez nulle part où vous n’écririez pas l’adresse e-mail d’un utilisateur.

  • La dernière valeur gagne : Vous recevez un événement par champ, portant la valeur sur laquelle l’utilisateur s’est arrêté plutôt qu’un flux touche par touche. S’il modifie un champ, seule la dernière version vous parvient.
  • Aucune garantie d’envoi : Les valeurs vous parviennent au fur et à mesure que les utilisateurs avancent dans le flow, et un utilisateur peut partir à tout moment. Attendez que le flow se ferme avant de considérer un ensemble de réponses comme complet.
  • Distribution au mieux : Si un utilisateur ferme le flow ou réduit l’application pendant qu’un champ est encore actif ou qu’un sélecteur est encore ouvert, cette valeur peut être perdue.

Pour que la valeur du dernier champ soit fiable, terminez le flow par un écran sans champs de saisie ni sélecteurs, et fermez le flow depuis une action explicite de l’utilisateur plutôt qu’automatiquement à l’apparition de cet écran. Passer à l’écran final retire le focus du champ précédent, ce qui déclenche l’envoi de sa valeur.

Stockez chaque valeur d’entrée au fur et à mesure que votre handler la reçoit, puis envoyez l’ensemble complet lorsque le flow se ferme. Pour intercepter ce moment, implémentez flowControllerDidDisappear sur votre AdaptyFlowControllerDelegate en UIKit, ou passez une closure didDisappear au modificateur .flow en SwiftUI. Les deux s’exécutent une fois que la vue du flow a quitté l’écran, que l’utilisateur ait terminé le flow ou qu’il l’ait simplement fermé.

Cas d’usage

Enregistrer les utilisateurs sur votre backend

Collectez les valeurs au fur et à mesure qu’elles arrivent et envoyez-les une fois le flow fermé, afin qu’une seule requête contienne un ensemble complet de réponses.

La vue disparaît que l’utilisateur ait terminé le flow ou qu’il l’ait abandonné en cours de route. Vérifiez que les champs dont vous avez besoin sont bien renseignés avant d’appeler votre backend.

Le flow ne peut pas afficher les erreurs renvoyées par votre backend. Le callback n’a pas de valeur de retour, et le SDK ne dispose d’aucune méthode pour envoyer des données dans un flow en cours d’exécution. Si l’inscription échoue, par exemple parce que l’adresse e-mail est déjà utilisée, affichez l’erreur dans votre propre interface après la fermeture du flow.

private var flowAnswers: [String: String] = [:]

func handleFlowInput(name: String, params: [String: any Sendable]) {
    guard name == "flow_user_input",
          let elementId = params["element_id"] as? String,
          let value = params["value"] as? String
    else { return }

    flowAnswers[elementId] = value
}

func flowControllerDidDisappear(_ controller: AdaptyFlowController) {
    guard flowAnswers["email"] != nil else { return }

    // Send flowAnswers to your backend here to create the account.

    flowAnswers.removeAll()
}

Enrichir les profils utilisateurs avec des données

Pour relier ce qu’un utilisateur a saisi à son profil et éviter de lui redemander les mêmes informations, mettez à jour le profil utilisateur au fur et à mesure que les valeurs arrivent.

Par exemple, si votre flow comporte un champ texte avec l’ID d’élément name et un champ e-mail avec l’ID d’élément email :

func handleFlowInput(name: String, params: [String: any Sendable]) {
    guard name == "flow_user_input",
          let elementId = params["element_id"] as? String,
          let value = params["value"] as? String
    else { return }

    let builder = AdaptyProfileParameters.Builder()

    switch elementId {
    case "name":
        builder.with(firstName: value)
    case "email":
        builder.with(email: value)
    default:
        return
    }

    // Delegate methods are synchronous; kick off the async update in a Task.
    Task {
        do {
            try await Adapty.updateProfile(params: builder.build())
        } catch {
            // handle the error
        }
    }
}

Personnaliser les flows affichés ultérieurement

Les réponses à un quiz peuvent également déterminer ce qu’un utilisateur voit à un placement ultérieur — un flow différent, ou un paywall différent à l’intérieur de celui-ci.

Par exemple, demandez aux utilisateurs leur expérience sportive dans votre flow d’onboarding, puis montrez à chaque groupe son propre flow avec des produits et des textes différents.

  1. Ajoutez un quiz à votre flow. Donnez au groupe sélectionnable le Group ID experience, et à chaque option un Element ID significatif.
  2. Gérez les réponses et définissez des attributs personnalisés pour l’utilisateur.
func handleFlowInput(name: String, params: [String: any Sendable]) {
    guard name == "flow_user_input",
          params["element_id"] as? String == "experience",
          let optionId = (params["item_ids"] as? [String])?.first
    else { return }

    let builder = AdaptyProfileParameters.Builder()
    // Set the custom attribute 'experience' to the option the user selected
    // (beginner, amateur, or pro).
    try? builder.with(customAttribute: optionId, forKey: "experience")

    Task {
        do {
            try await Adapty.updateProfile(params: builder.build())
        } catch {
            // handle the error
        }
    }
}
  1. Créez un segment pour chaque valeur d’attribut personnalisé.
  2. Créez un placement et ajoutez une audience pour chaque segment.
  3. Affichez le flow correspondant à ce placement dans votre application.