# How to Build a Multi-Step Survey with Conditional Logic in FlutterFlow

- Tool: FlutterFlow
- Difficulty: Beginner
- Time required: 25-35 min
- Compatibility: FlutterFlow Free+
- Last updated: March 2026

## TL;DR

Build a survey with conditional branching using a PageView where each page renders a different question type based on a Firestore questions subcollection. Each question document includes a conditionalNext map that routes users to a specific question order based on their answer. Responses are collected in a Page State Map keyed by questionId, and the progress bar adapts to the expected remaining path rather than total question count. On submit, responses are saved to a survey_responses collection.

## Building a Branching Survey in FlutterFlow

This tutorial creates a survey system where questions branch based on user answers. Unlike a linear quiz, selecting a specific option can skip irrelevant questions or dive deeper into a topic. Each question supports different input types: single choice, multiple choice, text, rating, and scale. The progress bar adapts to the current branch path so users always see accurate completion estimates. This pattern is used in intake forms, diagnostic tools, customer feedback, and onboarding questionnaires.

## Before you start

- A FlutterFlow project with Firestore configured
- A surveys collection and questions subcollection in Firestore
- Basic understanding of PageView and Conditional Visibility in FlutterFlow
- Familiarity with Page State variables

## Step-by-step guide

### 1. Design the Firestore data model for surveys with conditional questions

Create a surveys collection with fields: title (String), description (String), questionCount (int), createdBy (String). Under each survey document, create a questions subcollection with fields: questionText (String), type (String: singleChoice, multiChoice, text, rating, scale), options (String array, used for choice types), isRequired (bool), order (int), conditionalNext (Map: keys are option indexes as strings, values are the target question order numbers). For example, if question 2 has conditionalNext {"0": 5, "1": 3}, selecting option 0 jumps to question order 5 while option 1 goes to question order 3. Create a survey_responses collection with fields: surveyId (String), userId (String), responses (Map of questionId to answer), completedAt (Timestamp).

**Expected result:** Firestore has surveys with branching question definitions and a response storage collection.

### 2. Build the survey page with a PageView and adaptive progress bar

Create a SurveyPage with Route Parameter surveyId. Add a Backend Query for the questions subcollection ordered by order ascending. Store all questions in Page State questionList (Document List). Add Page State: currentQuestionIndex (int, tracking position in questionList), responses (Map, keyed by questionId), questionPath (int List, tracking which question orders the user has visited). At the top, display a LinearPercentIndicator where the percent is calculated from the current path position relative to the estimated total remaining questions in the current branch. Below, add a PageView with NeverScrollableScrollPhysics.

**Expected result:** A survey page loads with an adaptive progress bar and a PageView ready for question rendering.

### 3. Render different question types using Conditional Builder

Inside each PageView page, add a Column with the questionText in Headline Small style. Below, use a Conditional Builder (or stacked Conditional Visibility containers) that checks the question type field. For singleChoice: display a RadioButton group bound to options. For multiChoice: display a CheckboxGroup. For text: display a multiline TextField. For rating: display a row of 5 star IconButtons. For scale: display a Slider from 1 to 10. When the user selects or enters a value, update the responses Map in Page State with the questionId as key and the answer as value.

**Expected result:** Each question renders the correct input widget based on its type, and answers are stored in the responses Map.

### 4. Implement conditional branching navigation on the Next button

Add a Next button below the question area. On tap, first validate that required questions have an answer (check isRequired and responses Map). Then check if the current question has a conditionalNext map with a matching key for the selected answer index. If a match exists, find the question in questionList with the matching order value and animate the PageView to that page index. If no conditional match exists, go to the next sequential question. Append the visited question order to questionPath for back-navigation support. On the last reachable question, change the button to Submit.

**Expected result:** Selecting specific answers routes users to different questions, skipping irrelevant ones.

### 5. Save survey responses to Firestore on submission

When the user taps Submit on the final question, create a document in survey_responses with surveyId, userId (current user), responses Map (the complete Page State responses), and completedAt (server timestamp). Navigate to a ThankYouPage showing a confirmation message, the number of questions answered, and an optional summary of their responses. Add a Back button that returns to the survey list.

**Expected result:** Survey responses are saved to Firestore and the user sees a confirmation screen.

## Complete code example

File: `FlutterFlow Branching Survey Setup`

```text
FIRESTORE DATA MODEL:
  surveys/{surveyId}
    title: String
    description: String
    questionCount: int
    createdBy: String
    └── questions/{questionId}
          questionText: String
          type: String (singleChoice / multiChoice / text / rating / scale)
          options: ["Option A", "Option B", ...] (for choice types)
          isRequired: bool
          order: int
          conditionalNext: Map
            { "0": 5, "1": 3 }  // option index → target order

  survey_responses/{responseId}
    surveyId: String
    userId: String
    responses: Map { questionId: answer }
    completedAt: Timestamp

PAGE: SurveyPage
  Route Parameter: surveyId
  Backend Query: questions subcollection, orderBy order asc

PAGE STATE:
  questionList: List<Document> (all questions)
  currentQuestionIndex: int = 0
  responses: Map = {}
  questionPath: List<int> = [1]  // tracks visited question orders

WIDGET TREE:
  Column
    ├── LinearPercentIndicator
    │     percent: questionPath.length / estimatedTotalQuestions
    ├── PageView (NeverScrollableScrollPhysics)
    │     └── Per question:
    │           Column
    │             ├── Text (questionText, Headline Small)
    │             ├── Conditional Builder (by question.type):
    │             │     singleChoice → RadioButtonGroup (options)
    │             │     multiChoice  → CheckboxGroup (options)
    │             │     text         → TextField (multiline)
    │             │     rating       → Row of 5 star IconButtons
    │             │     scale        → Slider (1-10)
    │             └── SizedBox (16)
    └── Row
          ├── Button ("Back", visible if questionPath.length > 1)
          │     On Tap: pop last from questionPath → animate to previous
          └── Button ("Next" / "Submit")
                On Tap:
                  1. Validate required
                  2. Save answer to responses Map
                  3. Check conditionalNext for selected option
                  4. If match → jump to target order question
                  5. Else → next sequential question
                  6. Append to questionPath
                  7. If last → save to survey_responses + navigate to ThankYou
```

## Common mistakes

- **Progress bar showing currentQuestion divided by totalQuestions regardless of branching** — When a branch skips three questions, the progress bar jumps abruptly from 30 percent to 60 percent, confusing users about how much remains. Fix: Calculate the estimated remaining questions by following the default path from the current question. Display progress as questionsAnswered divided by estimatedTotal.
- **Not validating required questions before allowing the Next tap** — Users advance past required questions without answering, resulting in incomplete survey data that cannot be analyzed. Fix: On Next tap, check if the current question isRequired and whether a response exists in the Map. Show a SnackBar error if missing.
- **Storing conditional branching logic only in the Action Flow instead of Firestore** — Hardcoded branching means every survey change requires rebuilding the app. Survey creators cannot modify paths without developer access. Fix: Store conditionalNext rules as a Map field on each question document. The Action Flow reads this map dynamically at runtime.

## Best practices

- Store branching rules in Firestore so surveys can be updated without app changes
- Use Conditional Builder to render different input types from a single PageView template
- Show an adaptive progress bar based on the current branch path, not total questions
- Validate required fields before allowing navigation to the next question
- Track the question path in Page State to support a Back button through branches
- Save responses as a Map keyed by questionId for easy analysis
- Test all branching paths with sample data before publishing the survey

## Frequently asked questions

### How many branching levels can a survey have?

There is no technical limit on branching depth. Each question can point to any other question by order number. However, keep surveys under 20 questions total for good user experience, even with branching.

### Can I add a Back button that works with branching?

Yes. Track the visited question orders in a questionPath list. On Back tap, pop the last entry from the list and animate the PageView to the previous question in the path.

### How do I analyze responses from branching surveys?

Each response document contains the full responses Map. Not all users answer the same questions. When analyzing, group by the questions that were actually answered rather than assuming all users saw every question.

### Can I make a question conditionally required?

Yes. Add a conditionalRequired field to the question document that specifies under which conditions the question becomes required. Check this field in your validation logic before allowing Next.

### How do I handle loops in branching logic?

Avoid creating circular paths where question A routes to B and B routes back to A. If you need repeated sections, use a loop counter in Page State and exit the loop after a set number of iterations.

### Can RapidDev help build an advanced survey platform?

Yes. RapidDev can build full survey platforms with complex branching, piping answers into later questions, response analytics dashboards, and export to CSV or Google Sheets.

---

Source: https://www.rapidevelopers.com/flutterflow-tutorials/how-to-build-a-multi-step-survey-with-conditional-logic-in-flutterflow
© RapidDev — https://www.rapidevelopers.com/flutterflow-tutorials/how-to-build-a-multi-step-survey-with-conditional-logic-in-flutterflow
