---
title: "iOS SDK'da flow'lardan gelen verileri işleme"
description: "Kullanıcılarınızın flow'larda girdiği verileri iOS uygulamanızda Adapty SDK ile kaydedin ve kullanın."
---

> **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`

Bir kullanıcı [flow](adapty-flow-builder)'daki bir giriş alanına bir şey yazdığında, bir quiz'i yanıtladığında veya bir düğmeyi çevirdiğinde, SDK bu değeri analytics callback'i aracılığıyla uygulamanıza iletir.

Uygulamalar bu verileri genellikle şu amaçlarla kullanır:

- **Kullanıcıları kendi backend'lerinde kaydedin**: Kullanıcının onboarding flow'unuzda girdiği e-posta adresi ve adı alın, flow kapandığında hesabını oluşturun.
- **Yanıtları ve tercihleri kaydedin**: Kullanıcının ne seçtiğini takip edin, böylece uygulamanız bunu daha sonra kullanabilsin — örneğin, [bunu Adapty profiline yazın](setting-user-attributes) ve özel attribute olarak saklayın.
- **Gelecekteki flow'ları özelleştirin**: Quiz yanıtlarını özel attribute olarak kaydedin, ardından sonraki bir placement'ı hedefleyin; böylece her segment farklı bir flow veya içinde farklı bir paywall görsün.
- **Üçüncü taraf analitik platformlara iletin**: Yanıtları Amplitude, Mixpanel veya kullandığınız başka bir ürün analitiğine iletin.

Girdiler ve seçilebilir gruplar, değerlerini otomatik olarak raporlar. Kodunuzda girdileri birbirinden ayırt etmek için, builder'da her girdiye anlamlı bir **Element ID** ve her seçilebilir gruba bir **Group ID** verin.

## Başlamadan önce \{#before-you-start\}

Şunlara ihtiyacınız var:

- **Adapty SDK v4 veya üzeri**: Flow callback'leri önceki sürümlerde mevcut değildir.
- **[Flow & Paywall Builder](adapty-flow-builder)'da oluşturulmuş bir flow**: Yalnızca flow'lar bu callback aracılığıyla giriş değerlerini raporlar.
- **Yakın zamanda yayımlanmış bir flow sürümü**: Bir flow, yalnızca bu özellik kullanıma sunulduktan sonra yayımlandıysa giriş değerlerini raporlar. Uygulamanıza hiçbir şey ulaşmıyorsa flow'un yeni bir sürümünü yayımlayıp tekrar deneyin.

## Giriş değerlerini alma \{#receive-input-values\}

Giriş değerleri, bir flow'dan gelen diğer tüm analitik olaylarla aynı callback'e, `flow_user_input` olay adı altında iletilir. Callback'i diğer flow olay işleyicilerinizle birlikte kaydedin.

<Tabs>
<TabItem value="swiftui" label="SwiftUI" default>

`.flow` modifier'ına bir `didReceiveAnalyticEvent` closure'ı iletin:

```swift showLineNumbers title="Swift"
Text("Hello, AdaptyUI!")
    .flow(
        isPresented: $flowPresented,
        flowConfiguration: flowConfiguration,
        didFinishPurchase: { product, purchaseResult in /* handle the event */ },
        didFailPurchase: { product, error in /* handle the error */ },
        didFinishRestore: { profile in /* handle the event */ },
        didFailRestore: { error in /* handle the error */ },
        didReceiveError: { error in flowPresented = false },
        didReceiveAnalyticEvent: { name, params in
            handleFlowInput(name: name, params: params)
        }
    )
```

</TabItem>
<TabItem value="uikit" label="UIKit">

`AdaptyFlowControllerDelegate` üzerinde metodu uygulayın:

```swift showLineNumbers title="Swift"
func flowController(
    _ controller: AdaptyFlowController,
    didReceiveAnalyticEvent name: String,
    params: [String: any Sendable]
) {
    handleFlowInput(name: name, params: params)
}
```

</TabItem>
</Tabs>

Closure ve delegate metodu aynı iki argümanı alır; bu nedenle değeri okuyan kod her iki durumda da aynıdır.

`didReceiveAnalyticEvent` callback'i, [ekran görüntülemeleri](ios-flow-screen-views) dahil bir flow'daki tüm analitik olayları iletir.
- `name` parametresi olay adını içerir. Kullanıcı girişi olaylarını filtrelemek için `name`'i `flow_user_input` ile karşılaştırın.
- `element_type` parametresi öğe kategorisini belirtir.
- Girişin değeri, öğe türüne bağlı olarak farklı parametrelerde saklanır:
     - Metin alanları, seçiciler ve geçiş düğmeleri kullanıcının girişini `value` içinde saklar
     - Seçilebilir gruplar, aktif seçenekleri `item_ids` ve `item_titles` ile bildirir

```swift showLineNumbers title="Swift"
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
    }
}
```

Callback'in tetiklendiğini doğrulamak için kendi uygulamanızın test derlemesindeki input ile etkileşime girin. Callback handler'ınız bir event almıyorsa [ön koşulları](#before-you-start) kontrol edin. Flow'un bu özellik kullanıma sunulduktan sonra yayımlandığından emin olun.

## Uygulamanız girdiyi ne zaman alır \{#when-your-app-receives-the-input\}

:::important
Varsayılan giriş veya seçim değeri bu callback aracılığıyla uygulamanıza hiçbir zaman ulaşmaz. Kullanıcı **Set as default** olarak işaretlenmiş seçeneği kabul edip devam ederse herhangi bir olay tetiklenmez. Eksik olayı "yanıt yok" şeklinde yorumlamayın — kullanıcı yalnızca varsayılan değeri olduğu gibi bırakmıştır.
:::

**Aşağıdaki öğeler bu olayı tetikler:**

- Metin, e-posta, sayı ve telefon alanları
- Tarih, saat ve tarih-saat seçicileri
- Tekli seçim ve çoklu seçim grupları ile geçiş düğmeleri (toggle)

**Aşağıdakiler tetiklemez:**

- Parola alanları, ürün seçimleri ve sekme geçişleri
- Ekranlar arasında paylaşılan bir Header öğesinin içindeki giriş alanları
- Yinelenen veya eksik seçenek Element ID'lerine sahip ya da başka bir ekranda Group ID'si tekrarlanan seçilebilir gruplar. Bu tür bir grup, yanıtın bir kısmını göndermek yerine hiçbir şey göndermez.

**Olay şu durumlarda tetiklenir:**

- Bir alan odağı kaybettiğinde. Temizlenmiş bir alan boş dize bildirir; kullanıcının hiç düzenlemediği bir alan hiçbir şey bildirmez. Yer tutucu (placeholder) bir değer değildir. Kullanıcı alana geri dönür, düzenler ve tekrar ayrılırsa ikinci bir olay oluşur.
- Kullanıcı yeni bir değer seçtikten sonra seçiciyi kapattığında. Değiştirilmeden kapatılması hiçbir şey bildirmez.
- Kullanıcı bir seçenek veya geçiş düğmesine (toggle) dokunduğunda. Çoklu seçim olayı, seçili olan tüm seçenekleri listeler; bu nedenle son seçeneğin seçimini kaldırmak iki boş dizi gönderir.

**Olay şu durumlarda tetiklenmez:**

- Kullanıcı yazarken. Tuş vuruşu akışı yoktur; yalnızca odak ayrıldığında alanın tuttuğu değer bildirilir.
- Kullanıcı flow'u gönderdiğinde veya kapattığında. O anda hâlâ düzenlenmekte olan bir değer kaybolabilir; [teslimat sınırlamaları](#delivery-and-limitations) bölümü, son ekranın bu duruma göre nasıl tasarlanacağını ele alır.
- Kullanıcı etkileşimi olmadan bir değer ayarlandığında. **Set as default** olarak işaretlenen bir seçenek, ekran açıldığında önceden seçili gelir; **Set Variable** eylemi ise başka bir etkileşimden bir seçenek belirleyebilir veya bir girişi doldurabilir. Bu durumların hiçbiri olay göndermez; önceden doldurulmuş bir giriş yalnızca kullanıcı onu düzenlediğinde bildirilir.

## Ne alırsınız \{#what-you-receive\}

Callback iki olay iletir. Yalnızca `flow_user_input` olaylarını görüntülemek için `name` alanına göre filtreleyin. Yanıt JSON yükü şu şekilde görünür:

```json
{
  "name": "flow_user_input",
  "instanceId": "scr_registration",
  "isBackendEvent": false,
  "isCustomerEvent": true,
  "element_id": "email",
  "element_type": "email_input",
  "value": "jane@example.com"
}
```

| Parametre         | Açıklama |
|:------------------|:------------|
| `name`            | Girdi olayları için `flow_user_input`, ekran görüntülemeleri için `flow_screen_showed`. |
| `instanceId`      | Girdinin bulunduğu ekranın ID'si. Element ID'leri bir ekran içinde benzersizdir, flow genelinde değil. Flow'unuzda birden fazla ekranda girdi varsa, olayları filtrelerken `instanceId` ile `element_id`'yi birlikte kullanın. |
| `element_id`      | [Girdinin](builder-inputs-and-forms) **Element ID**'si ya da [seçilebilir grubun](flow-selectable-elements) **Group ID**'si. |
| `element_type`    | Olayı gönderen elementin türü. Aşağıdaki parametrelerden hangisinin girdi değerini taşıdığını belirler. |
| `value`           | **Yalnızca metin alanları, seçiciler ve geçiş düğmeleri için.** Girdi değeri: metin alanları için string, seçiciler için integer, geçiş düğmeleri için boolean. |
| `item_ids`        | **Yalnızca tek seçimli ve çok seçimli gruplar için.** Seçilen seçeneklerin **Element ID**'leri, builder'daki görünüm sırasıyla. Tek seçimli grupta bir kayıt; çok seçimlide herhangi bir sayıda kayıt bulunabilir. |
| `item_titles`     | **Yalnızca tek seçimli ve çok seçimli gruplar için.** `item_ids` içinde listelenen seçeneklerin başlıkları, aynı sırayla. Hiçbir zaman boş olmaz: başlığı olmayan bir seçenek kendi ID'sini bildirir. |
| `isCustomerEvent` | Yardımcı bir bayrak; bu olay için her zaman `true`'dur. SDK'nın callback'inize ilettiği olayları işaretler. Tek bir handler her flow olayını analytics'inize iletiyorsa ve `name` yerine bu bayrağa göre koşul koyuyorsanız kullanışlıdır. |
| `isBackendEvent`  | Yardımcı bir bayrak; bu olay için her zaman `false`'tur. Adapty'nin kendi analytics'i için de kaydettiği olayları işaretler. `false`, kullanıcıların girdiği verilerin yalnızca uygulamanıza ulaştığını, başka bir yere gitmediğini doğrular — Adapty bu verileri almaz veya saklamaz. |

Her elementin bildirdikleri:

| Builder'da | `element_type` | Değeri saklayan parametre | Ne içerir |
|:---------------|:---------------|:----------------------------|:--------------|
| **Text**, **Number**, **Phone number** girdi | `text_input`, `number_input`, `phone_input` | `value` | Kullanıcının yazdığı ham string. Sayılar numeric tip olarak değil, string olarak gelir. |
| **E-mail** girdi | `email_input` | `value` | Kullanıcının yazdığı ham string; builder'ın format doğrulamasından geçememiş olsa bile. Kullanmadan önce kendi tarafınızda doğrulayın. |
| **Password** girdi | yok | yok | Hiçbir olay göndermez. |
| **Date** girdi | `date_picker` | `value` | Seçilen tarihin yerel gece yarısında Unix zamanı, milisaniye cinsinden integer olarak. |
| **Time** girdi | `time_picker` | `value` | Dakikaya yuvarlanmış Unix zamanı, milisaniye cinsinden integer olarak. |
| **Date & Time** girdi | `date_picker` ve `time_picker` | `value` | İki element: bir tarih seçici ve bir saat seçici. Her biri kendi olayını gönderir. |
| **Type** açılır listesinde **Date & Time** olarak değiştirilen girdi | `date_time_picker` | `value` | Dakikaya yuvarlanmış Unix zamanı, milisaniye cinsinden integer olarak. |
| **Single choice** grubu | `single_choice` | `item_ids`, `item_titles` | İki dizi. `item_ids`: seçilen seçeneğin Element ID'sini içeren bir dizi. `item_titles`: o seçeneğin başlığını içeren bir dizi. |
| **Multi-choice** grubu | `multi_choice` | `item_ids`, `item_titles` | İki dizi. `item_ids`: seçilen tüm seçeneklerin Element ID'leri, builder'daki görünüm sırasıyla. `item_titles`: aynı sırayla başlıkları. Hiçbir şey seçilmediğinde her iki dizi de boştur. |
| **Toggle** grubu | `toggle` | `value` | Bir boolean. |

Bir cevaba göre dallanmak için `item_titles` değil `item_ids` ile karşılaştırın. Başlık türetilmiş bir değerdir: ayarladıysanız seçeneğin **Element Title**'ı, yoksa varsayılan dilinizdeki metni, o da yoksa Element ID'si kullanılır. Flow'u başka bir dilde okuyan kullanıcı farklı bir metin görmüştür.

## Etkinlik örnekleri \{#event-examples\}

Bu örnekler, her etkinlikte mevcut olan özellikleri, açıklayıcı değerlerle birlikte yorumlarda göstermektedir.

<Details>
<summary>Metin, e-posta, sayı ve telefon girişi (Genişletmek için tıklayın)</summary>

```swift
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)
}
```
</Details>

<Details>
<summary>Tarih, saat ve tarih-saat seçiciler (Genişletmek için tıklayın)</summary>

```swift
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)
}
```
</Details>

<Details>
<summary>Tek seçim (Genişletmek için tıklayın)</summary>

```swift
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"]
}
```
</Details>

<Details>
<summary>Multi choice (Click to expand)</summary>

```swift
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"]
}
```
</Details>

<Details>
<summary>Toggle (Click to expand)</summary>

```swift
func handleFlowInput(name: String, params: [String: any Sendable]) {
    params["element_id"];      // "reminders"
    params["element_type"];    // "toggle"
    params["value"];           // true   (Bool)
}
```
</Details>

## Teslimat ve sınırlamalar \{#delivery-and-limitations\}

:::warning
Flow'lar ham değerler gönderir — e-posta adresleri, telefon numaraları ve kullanıcının yazdığı her şey. Analytics callback'inin ilettiği her şeyi kişisel veri olarak değerlendirin ve bir kullanıcının e-posta adresini yazmayacağınız bir yere yazmayın.
:::

- **Son değer geçerlidir**: Alan başına bir olay alırsınız; bu olay, kullanıcının tuş tuş değil, en sonunda girdiği değeri taşır. Kullanıcı bir alanı düzenlerse yalnızca son sürüm size ulaşır.
- **Gönderim garantisi yoktur**: Kullanıcılar flow boyunca ilerledikçe değerler size ulaşır ve kullanıcı her an çıkabilir. Bir yanıt kümesini tamamlanmış saymadan önce flow'un kapanmasını bekleyin.
- **En iyi çaba teslimatı**: Bir alan odaklanmışken veya bir seçici açıkken kullanıcı flow'u kapatır ya da uygulamayı arka plana alırsa o değer kaybolabilir.

Son alanın değerinin güvenilir olmasını sağlamak için flow'u; giriş veya seçici içermeyen bir ekranla bitirin ve bu ekran açıldığında otomatik olarak değil, açık bir kullanıcı eylemiyle flow'u kapatın. Son ekrana geçmek, önceki alandaki odağı kaldırır ve bu sayede değer gönderilir.

Her girdi değerini handler'ınız aldığında saklayın ve flow kapandığında tam seti gönderin. Bu anı yakalamak için UIKit'te `AdaptyFlowControllerDelegate` üzerinde `flowControllerDidDisappear` metodunu uygulayın ya da SwiftUI'de `.flow` modifier'ına bir `didDisappear` closure'ı geçirin. Her ikisi de flow'un görünümü ekrandan ayrıldıktan sonra çalışır; kullanıcı flow'u tamamlamış ya da kapatmış olsun fark etmez.

## Kullanım Senaryoları \{#use-cases\}

### Kullanıcıları arka uç sisteminize kaydedin \{#register-users-on-your-backend\}

Değerler geldikçe toplayın ve flow kapandığında tek bir istekle gönderin; böylece bir istek eksiksiz bir yanıt kümesi taşır.

Kullanıcı flow'u tamamlamış olsun ya da yarıda bırakmış olsun, görünüm kaybolur. Arka uç sisteminizi çağırmadan önce ihtiyaç duyduğunuz alanları kontrol edin.

Flow, arka ucunuzdan gelen hataları gösteremez. Callback'in dönüş değeri yoktur ve SDK'nın çalışan bir flow'a veri gönderen bir metodu bulunmamaktadır. Kayıt başarısız olursa, örneğin e-posta adresi zaten kullanılıyorsa, hatayı flow kapandıktan sonra kendi arayüzünüzde gösterin.

```swift showLineNumbers title="Swift"
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()
}
```

### Kullanıcı profillerini verilerle zenginleştirme \{#enrich-user-profiles-with-data\}

Kullanıcının girdiği bilgileri profiline bağlamak ve aynı bilgileri tekrar sormaktan kaçınmak için değerler geldikçe [kullanıcı profilini güncelleyin](setting-user-attributes).

Örneğin, flow'unuzda `name` Element ID'li bir metin girişi ve `email` Element ID'li bir e-posta girişi varsa:

```swift showLineNumbers title="Swift"
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
        }
    }
}
```

### Daha sonra gösterilen flow'ları özelleştirme \{#customize-flows-shown-later\}

Quiz yanıtları, kullanıcının daha sonra bir [placement](placements)'da göreceği şeyi de belirleyebilir — farklı bir flow veya içindeki farklı bir paywall.

Örneğin, onboarding flow'unuzda kullanıcılara sporla deneyimlerini sorun, ardından her gruba farklı ürünler ve içerik içeren kendi flow'unu gösterin.

1. Flow'unuza bir [quiz](onboarding-quizzes) ekleyin. [Seçilebilir gruba](flow-selectable-elements) `experience` Group ID'sini ve her seçeneğe anlamlı bir Element ID verin.
2. Yanıtları işleyin ve kullanıcı için [özel nitelikler ayarlayın](setting-user-attributes).

```swift showLineNumbers title="Swift"
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
        }
    }
}
```

3. Her özel nitelik değeri için bir [segment](segments) oluşturun.
4. Bir [placement](placements) oluşturun ve her segment için bir [kitle](audience) ekleyin.
5. Uygulamanızda o placement için [flow'u görüntüleyin](ios-present-paywalls).