Skip to main content
Supported on: Android SDK 1.0.33+
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.
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

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

val surveys = AppDNA.surveys

Module Methods

MethodSignatureDescription
presentpresent(surveyId: String)Present a survey by ID
setDelegatesetDelegate(delegate: AppDNASurveyDelegate?)Set a delegate for survey lifecycle callbacks

8 Question Types

TypeDisplayResponse
nps0-10 numeric scaleInteger 0-10
csat1-5 satisfaction scaleInteger 1-5
ratingStar ratingInteger 1-5
emoji_scaleEmoji optionsSelected emoji value
yes_noBinary choiceBoolean
single_choiceRadio button optionsSelected option string
multi_choiceCheckbox optionsList of selected strings
free_textText input fieldFree-form string
likert (alias scale)Numeric scale with optional left/right anchor labelsInteger in configured range
Question types and their content are defined entirely in the Console. The SDK renders them automatically based on the survey configuration.

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:
interface AppDNASurveyDelegate {
    fun onSurveyPresented(surveyId: String)
    fun onSurveyCompleted(surveyId: String, responses: List<SurveyResponse>)
    fun onSurveyDismissed(surveyId: String)
}

SurveyResponse

PropertyTypeDescription
questionIdStringIdentifier for the question
answerAnyThe raw answer — Int for NPS/CSAT/rating/Likert, String for free-text/single-choice, List<String> for multi-choice, Boolean for yes-no
metadataMap<String, Any>?Optional per-question metadata (question type, timing, etc.)
Cast answer to the type matching the question (see Question Types).

Example Implementation

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 guide for details on supported formats.

Auto-Tracked Events

EventTrigger
survey_shownA survey is displayed
survey_question_answeredUser answers an individual question
survey_completedUser submits the final answer
survey_dismissedSurvey is closed without completing
survey_followup_prompt_reviewSmart Review prompt routed the user to the Google Play review dialog
survey_followup_feedback_formSmart Review prompt routed the user to a feedback form
survey_followup_winbackA win-back follow-up was triggered after a low-rating response
survey_feedback_submittedUser submits the in-app feedback form
feedback_form_submittedStandalone feedback form submitted
feedback_form_dismissedStandalone feedback form dismissed

Full Example

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() { /* ... */ }
}
Surveys are created in the Console under Feedback > Surveys. Trigger-based surveys appear automatically — manual presentation with present() is for precise control over timing.