> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appdna.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Android Surveys & Feedback

> Collect NPS, CSAT, and custom feedback with 9 question types

<Info>
  **Supported on:** Android SDK `1.0.33+`
</Info>

<Tip>
  You can A/B test this survey with no extra code — create an experiment on it in the Console and the SDK serves the assigned variant automatically. See [Servable Surface Experiments](/sdks/android/experiments#servable-surface-experiments).
</Tip>

The surveys module lets you collect user feedback through in-app surveys. Surveys can trigger automatically based on events (like in-app messages) or be presented manually from your code.

## How It Works

Surveys are configured in the Console with content, question types, and trigger rules. Like in-app messages, they can appear automatically when trigger conditions are met — no code required for trigger-based surveys.

## Present a Survey Manually

```kotlin theme={null}
AppDNA.surveys.present("nps_q1_2026")
```

The SDK uses the foreground Activity captured at configure time to launch its internal `SurveyActivity`. If the survey ID is unknown or the config hasn't loaded, the call is a no-op and an SDK log line explains why.

## Module Access

```kotlin theme={null}
val surveys = AppDNA.surveys
```

### Module Methods

| Method        | Signature                                      | Description                                   |
| ------------- | ---------------------------------------------- | --------------------------------------------- |
| `present`     | `present(surveyId: String)`                    | Present a survey by ID                        |
| `setDelegate` | `setDelegate(delegate: AppDNASurveyDelegate?)` | Set a delegate for survey lifecycle callbacks |

## 9 Question Types

| Type                     | Display                                              | Response                    |
| ------------------------ | ---------------------------------------------------- | --------------------------- |
| `nps`                    | 0-10 numeric scale                                   | Integer 0-10                |
| `csat`                   | 1-5 satisfaction scale                               | Integer 1-5                 |
| `rating`                 | Star rating                                          | Integer 1-5                 |
| `emoji_scale`            | Emoji options                                        | Selected emoji value        |
| `yes_no`                 | Binary choice                                        | Boolean                     |
| `single_choice`          | Radio button options                                 | Selected option string      |
| `multi_choice`           | Checkbox options                                     | List of selected strings    |
| `free_text`              | Text input field                                     | Free-form string            |
| `likert` (alias `scale`) | Numeric scale with optional left/right anchor labels | Integer in configured range |

<Info>
  Question types and their content are defined entirely in the Console. The SDK renders them automatically based on the survey configuration.
</Info>

## Smart Review Prompting

The SDK supports a two-step review-prompt flow: an in-app screener routes happy users to the Google In-App Review dialog and unhappy users to a feedback form. Configure the prompt in the Console under **Feedback → Review Prompts** and target it like any other survey — the SDK presents it automatically when trigger conditions match.

## AppDNASurveyDelegate

All 3 methods on this delegate fire from `SurveyManager` alongside the analytics events. Register your delegate via `AppDNA.surveys.setDelegate(...)`.

* `onSurveyPresented(surveyId)` — fires when the survey view appears (alongside the `survey_shown` event).
* `onSurveyCompleted(surveyId, responses)` — fires when the user submits the final question. `responses` is a `List<SurveyResponse>` (one entry per answered question with `questionId` + the raw answer), suitable for forwarding to your own analytics or CRM.
* `onSurveyDismissed(surveyId)` — fires when the user closes the survey before completing it (back button, swipe-to-dismiss, outside tap).

Implement the delegate to capture survey responses and lifecycle events:

```kotlin theme={null}
interface AppDNASurveyDelegate {
    fun onSurveyPresented(surveyId: String)
    fun onSurveyCompleted(surveyId: String, responses: List<SurveyResponse>)
    fun onSurveyDismissed(surveyId: String)
}
```

### SurveyResponse

| Property     | Type                | Description                                                                                                                                    |
| ------------ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `questionId` | `String`            | Identifier for the question                                                                                                                    |
| `answer`     | `Any`               | The raw answer — `Int` for NPS/CSAT/rating/Likert, `String` for free-text/single-choice, `List<String>` for multi-choice, `Boolean` for yes-no |
| `metadata`   | `Map<String, Any>?` | Optional per-question metadata (question type, timing, etc.)                                                                                   |

Cast `answer` to the type matching the question (see [Question Types](#8-question-types)).

### Example Implementation

```kotlin theme={null}
import ai.appdna.sdk.AppDNA
import ai.appdna.sdk.AppDNASurveyDelegate
import ai.appdna.sdk.SurveyResponse

class FeedbackHandler : AppDNASurveyDelegate {

    override fun onSurveyPresented(surveyId: String) {
        Log.d("Survey", "Survey shown: $surveyId")
    }

    override fun onSurveyCompleted(surveyId: String, responses: List<SurveyResponse>) {
        for (response in responses) {
            when (val a = response.answer) {
                is Int -> {
                    // NPS / CSAT / rating / likert
                    if (response.questionId == "nps_question") {
                        if (a >= 9) showReferralPrompt()    // Promoter
                        else if (a <= 6) showSupportLink()  // Detractor
                    }
                }
                is String -> Log.d("Survey", "Feedback: $a")
                is List<*> -> Log.d("Survey", "Multi-select: $a")
                is Boolean -> Log.d("Survey", "Yes/No: $a")
            }
        }
    }

    override fun onSurveyDismissed(surveyId: String) {
        Log.d("Survey", "Survey dismissed: $surveyId")
    }

    private fun showReferralPrompt() { /* ... */ }
    private fun showSupportLink() { /* ... */ }
}

AppDNA.surveys.setDelegate(FeedbackHandler())
```

## Rich Media

Survey questions support rich media content configured in the Console:

* **Header images** -- add images above survey questions
* **Icons in options** -- use icon references in choice options (Lucide, Material, or emoji)
* **Thank-you animations** -- Lottie or confetti effects on survey completion
* **Haptic feedback** -- triggered on option selection and submission

See the [Rich Media](/sdks/android/rich-media) guide for details on supported formats.

## Auto-Tracked Events

| Event                           | Trigger                                                              |
| ------------------------------- | -------------------------------------------------------------------- |
| `survey_shown`                  | A survey is displayed                                                |
| `survey_question_answered`      | User answers an individual question                                  |
| `survey_completed`              | User submits the final answer                                        |
| `survey_dismissed`              | Survey is closed without completing                                  |
| `survey_followup_prompt_review` | Smart Review prompt routed the user to the Google Play review dialog |
| `survey_followup_feedback_form` | Smart Review prompt routed the user to a feedback form               |
| `survey_followup_winback`       | A win-back follow-up was triggered after a low-rating response       |
| `survey_feedback_submitted`     | User submits the in-app feedback form                                |
| `feedback_form_submitted`       | Standalone feedback form submitted                                   |
| `feedback_form_dismissed`       | Standalone feedback form dismissed                                   |

## Full Example

```kotlin theme={null}
import ai.appdna.sdk.AppDNA
import ai.appdna.sdk.AppDNASurveyDelegate
import ai.appdna.sdk.SurveyResponse

class FeedbackManager : AppDNASurveyDelegate {

    init {
        AppDNA.surveys.setDelegate(this)
    }

    /** Present NPS survey after a key moment */
    fun askForFeedback() {
        AppDNA.surveys.present("nps_q1_2026")
    }

    // MARK: AppDNASurveyDelegate

    override fun onSurveyPresented(surveyId: String) {
        // Survey is visible
    }

    override fun onSurveyCompleted(surveyId: String, responses: List<SurveyResponse>) {
        // React to feedback
        val nps = responses.firstOrNull { it.questionId == "nps_question" }
        val score = nps?.answer as? Int ?: return
        when {
            score >= 9 -> showReferralPrompt()
            score <= 6 -> showSupportLink()
        }
    }

    override fun onSurveyDismissed(surveyId: String) {
        // User dismissed without responding
    }

    private fun showReferralPrompt() { /* ... */ }
    private fun showSupportLink() { /* ... */ }
}
```

<Note>
  Surveys are created in the Console under **Feedback > Surveys**. Trigger-based surveys appear automatically -- manual presentation with `present()` is for precise control over timing.
</Note>
