Survey structure
Survey definitions are read from the surveys array in survey.json. The current structure nests sessions → screens → questions. A legacy format with screens directly under a survey remains supported.
Give each question a stable id, type, and label. Configure slider ranges, choices, and required responses per question. Changing a question ID can affect interpretation of existing responses.
Minimal survey example
This illustrates the survey.json format. It is not a replacement for an existing study file.
{
"surveys": [{
"id": "demo-mood",
"title": "Mood check-in",
"sessions": [{
"id": "demo-session",
"screens": [{
"id": "demo-screen",
"questions": [{
"id": "mood",
"type": "slider",
"label": "How do you feel right now?",
"required": true,
"min": 0,
"max": 10
}]
}]
}]
}]
}
Required responses and branching
question.required differs from a screen's required and skippable settings. A question's required flag alone does not decide whether the screen can be skipped. The skipScreens field on an option identifies screens to skip after that answer. Verify the resulting navigation and completion state in the study app.
Use the current models and renderer for exact question type strings and supported properties, including sliders, single/multiple choice, input, date/time, and voice. Inventing a new type string does not add renderer support.
Response storage
Submission passes through the SurveyResponseSubmitter contract to the app's implementation. Room's survey_response_records contains the survey ID, owner, submission time, bundleJson, syncState, and dedupeKey.
Submitting the same occurrence does not necessarily append a new record. The implementation determines response IDs and deduplication keys from an occurrence or time slot. Time-limited surveys also check availability at submission.
See scheduling and reminders and data formats.