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

# Grouped surveys

> Define question groups and request one group per page in a human survey.

Grouped presentation puts related questions on the same page—for example, background questions together and feedback questions on the next page. Participants can review the questions in a group before submitting that page. Define the page boundaries on your `Survey`, then pass `{"survey": {"presentation": "group"}}` to `.humanize()`.

> [!NOTE]
>
> Grouped presentation requires support in both your installed EDSL version and the hosted survey interface. Preview with the same schema to check that the intended questions appear together.

## Create a two-page survey

This example puts two background questions on the first page and two feedback questions on the second.

```python theme={null}
from edsl import Survey, QuestionFreeText, QuestionMultipleChoice

survey = Survey([
    QuestionMultipleChoice(
        question_name="work_location",
        question_text="Where do you usually work?",
        question_options=["At home", "In an office", "A mix of both"],
    ),
    QuestionFreeText(
        question_name="role",
        question_text="What is your role?",
    ),
    QuestionMultipleChoice(
        question_name="satisfaction",
        question_text="How satisfied are you with your work arrangement?",
        question_options=["Satisfied", "Neutral", "Dissatisfied"],
    ),
    QuestionFreeText(
        question_name="improvement",
        question_text="What would improve your work arrangement?",
    ),
])

# First question, last question (inclusive), group name.
survey.add_question_group("work_location", "role", "background")
survey.add_question_group("satisfaction", "improvement", "feedback")

humanize_schema = {
    "survey": {"presentation": "group"},
    "questions": {"improvement": {"optional": True}},
}
```

| Page | Group name | Questions |
| - | - | - |
| 1 | `background` | `work_location`, `role` |
| 2 | `feedback` | `satisfaction`, `improvement` |

Preview with the same schema you intend to use when creating the survey:

```python theme={null}
preview_url = survey.preview(humanize_schema=humanize_schema)
# print() also shows output in scripts. In a notebook, you can instead
# put the value you want to inspect on the last line of a cell.
print(preview_url)
```

When ready, create the human survey:

```python theme={null}
info = survey.humanize(
    human_survey_name="Workplace experience",
    humanize_schema=humanize_schema,
)
print(info["respondent_url"])
print(info["admin_url"])
```

The groups live on the survey; the schema selects how to present them. Adding groups alone does not enable grouped presentation. Omit `presentation`, or set it to `"question"`, for the default question-by-question mode.

## Set group boundaries

`survey.add_question_group(start_question, end_question, group_name)` accepts question names or question objects and returns the survey for chaining.

* Each group includes both endpoints and every question between them.
* Groups must not overlap. A one-question page uses the same question for both endpoints.
* Names must be unique Python identifiers, such as `background`, and must not match a question name.
* Pages follow question order in the survey.
* Assign every question you want displayed to a group. With groups defined, the current grouped navigator skips questions outside those groups.

For example, to make a page containing only `work_location`, define its group with `survey.add_question_group("work_location", "work_location", "location_page")` on a survey where that question is not already grouped.

## Inspect navigation locally

Use `survey.next_group()` to inspect which questions belong on the next page for a given set of answers, without publishing the survey. This is useful when checking a route that should skip a page. For a visual check of the participant experience, use `survey.preview()` instead.

With the two-page survey constructed above:

```python theme={null}
first_page = survey.next_group()
assert first_page["group_name"] == "background"
assert first_page["question_names"] == ["work_location", "role"]

second_page = survey.next_group(
    current_group="background",
    answers={
        "work_location.answer": "At home",
        "role.answer": "Researcher",
    },
)
assert second_page["group_name"] == "feedback"
```

Pass all answers collected so far, including those from the just-submitted group. Use `include_instructions=False` to return questions only.

| Returned field | Meaning |
| - | - |
| `group_name` | Selected group name, or `None` at the end |
| `items` | Question and instruction objects; `[EndOfSurvey]` at the end |
| `question_names` | Names of the questions selected for this page |
| `is_end` | `True` when the survey has finished |

See [Humanize](https://docs.expectedparrot.com/en/latest/humanize.md) for retrieving responses and [Humanize schema](https://docs.expectedparrot.com/en/latest/humanize_schema.md) for styling and other presentation options.

## Plan branching around pages

The navigator uses the answers supplied when a page is requested to filter skipped questions. After a page is submitted, it applies the normal navigation rules from that group's **last renderable question** to choose the next page. Put page-level jump or stop rules on that question.

If a later question depends on an earlier answer, put the dependent question on a later page so that answer is available when the page is selected. The navigation API does not establish live, within-page updates to conditional questions.

For example, starting with the two-page survey above, omit the improvement question for satisfied respondents:

```python theme={null}
# Keep the controlling answer on an earlier page.
survey.question_groups.clear()
survey.add_question_group("work_location", "satisfaction", "background")
survey.add_question_group("improvement", "improvement", "improvements")
survey.add_skip_rule(
    "improvement",
    "{{ satisfaction.answer }} == 'Satisfied'",
)
```

Now the first page collects work location, role, and satisfaction. A satisfied respondent skips the improvements page and reaches the end; other respondents continue to it. Add the rule before previewing or creating the human survey.

Additional navigation behavior:

* A group with no remaining questions is skipped.
* A jump into the middle of a group starts at the target question; earlier questions in that group are omitted.
* Relevant instructions before or within the selected group are included by default.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.