YAML Construction Guide

This guide provides comprehensive instructions for building YAML files that Survey123Py can convert to Survey123-compatible Excel files.

Overview

Survey123Py uses YAML files to define surveys in a human-readable format, which are then converted to Excel files with proper Survey123 formatting. Each YAML file contains three main sections:

  • settings: Form configuration and metadata

  • choices: Choice lists for select questions

  • survey: The actual survey questions and structure

Understanding the “-” Syntax

The YAML “-” (dash) syntax indicates a list item. In Survey123Py:

  • Each “-” in the survey section represents a single row in the Excel survey sheet

  • Each “-” in the choices section represents a single row in the Excel choices sheet

  • The fields within each list item map to specific Excel columns

Example:

survey:
  - type: text          # First row. "text" will be written to the cell in the "type" column in Excel
    name: q1            # "q1" will be written in the "name" column
    label: Your name?   # "Your name?" will be written in the "label" column
  - type: integer       # This creates a second row in Excel
    name: q2
    label: Your age?

Excel Column Mappings

Survey Sheet Columns

Each question (marked with “-”) in the survey section maps to these Excel columns:

YAML Field

Excel Column

Description

type

A

Question type (text, integer, select_one, etc.)

name

B

Unique identifier for the question

label

C

Display text shown to users

hint

D

Additional help text

guidance_hint

E

Extended guidance information

appearance

F

Visual styling options

required

G

Whether question is mandatory (yes/no)

required_message

H

Custom message when required field is empty

readonly

I

Whether field is read-only (yes/no)

default

J

Default value for the field

calculation

K

Formula for calculated fields

constraint

L

Validation rules

constraint_message

M

Message shown when constraint fails

relevant

N

Logic for when question appears

choice_filter

O

Filter choices dynamically

repeat_count

P

Number of repetitions for repeat groups

media::audio

Q

Audio file reference

media::image

R

Image file reference

bind::type

S

Data type binding

bind::esri:fieldType

T

Esri field type

bind::esri:fieldLength

U

Maximum field length

bind::esri:fieldAlias

V

Display alias for field

body::esri:style

W

Esri styling options

bind::esri:parameters

X

Additional Esri parameters

parameters

Y

General parameters

body::accept

Z

Accepted file types

body::esri:visible

AA

Visibility settings

body::esri:inputMask

AB

Input formatting mask

Choices Sheet Columns

Each choice (marked with “-”) in the choices section maps to these Excel columns:

YAML Field

Excel Column

Description

list_name

A

Name of the choice list

name

B

Internal value for the choice

label

C

Display text for the choice

media::audio

D

Audio file for the choice

media::image

E

Image file for the choice

Settings Sheet Columns

Settings fields map to these Excel columns:

YAML Field

Excel Column

Description

form_title

A

Title of the form

form_id

B

Unique form identifier

instance_name

C

Instance naming pattern

submission_url

D

URL for form submissions

default_language

E

Default language code

version

F

Form version number

style

G

Form styling options

namespaces

H

XML namespaces

YAML Structure Examples

Basic Survey Structure

settings:
  form_title: "My Survey"
  instance_name: "survey_${q1}"

choices:
  - list_name: yes_no
    name: yes
    label: "Yes"
  - list_name: yes_no
    name: no
    label: "No"

survey:
  - type: text
    name: q1
    label: "What is your name?"
    required: yes
  - type: select_one yes_no
    name: q2
    label: "Do you agree?"

Question Types

Text Questions:

- type: text
  name: name_field
  label: "Enter your name"
  required: yes
  hint: "First and last name"

Integer Questions:

- type: integer
  name: age_field
  label: "Enter your age"
  constraint: ". > 0 and . < 120"
  constraint_message: "Age must be between 1 and 119"

Select Questions:

- type: select_one colors
  name: favorite_color
  label: "What is your favorite color?"
  appearance: "minimal"

Calculated Fields:

- type: text
  name: full_name
  label: "Full Name"
  calculation: "concat(${first_name}, ' ', ${last_name})"
  readonly: yes

Note Fields:

- type: note
  name: instructions
  label: "Please answer all questions carefully"

Groups and Repeats

Groups (questions grouped together):

- type: group
  name: personal_info
  label: "Personal Information"
  children:
    - type: text
      name: first_name
      label: "First Name"
    - type: text
      name: last_name
      label: "Last Name"

Repeats (repeating sections):

- type: repeat
  name: family_members
  label: "Family Members"
  children:
    - type: text
      name: member_name
      label: "Member Name"
    - type: integer
      name: member_age
      label: "Member Age"

Choice Lists

Simple Yes/No List:

choices:
  - list_name: yes_no
    name: yes
    label: "Yes"
  - list_name: yes_no
    name: no
    label: "No"

Multiple Choice List:

choices:
  - list_name: colors
    name: red
    label: "Red"
  - list_name: colors
    name: blue
    label: "Blue"
  - list_name: colors
    name: green
    label: "Green"

Choices with Images:

choices:
  - list_name: animals
    name: cat
    label: "Cat"
    media::image: "cat.jpg"
  - list_name: animals
    name: dog
    label: "Dog"
    media::image: "dog.jpg"

Advanced Features

Variable Substitution

Use ${variable_name} syntax to reference other fields:

- type: text
  name: first_name
  label: "First Name"
- type: note
  name: greeting
  label: "Hello ${first_name}!"

Conditional Logic

Use the relevant field to show/hide questions:

- type: select_one yes_no
  name: has_children
  label: "Do you have children?"
- type: integer
  name: num_children
  label: "How many children?"
  relevant: "${has_children} = 'yes'"

Validation Rules

Use constraint for validation:

- type: integer
  name: age
  label: "Age"
  constraint: ". >= 18"
  constraint_message: "You must be at least 18 years old"

Default Values

Set default values for fields:

- type: text
  name: country
  label: "Country"
  default: "USA"

Appearance Options

Control how questions appear:

- type: select_one colors
  name: color
  label: "Choose color"
  appearance: "minimal"    # dropdown instead of radio buttons

Media Integration

Add audio or image prompts:

- type: text
  name: description
  label: "Describe what you see"
  media::image: "photo.jpg"
  media::audio: "instructions.mp3"

Testing and Preview

Preview Input Fields

Add test data using the survey123py::preview_input field:

- type: text
  name: name
  label: "Your name"
  survey123py::preview_input: "John Doe"

This allows you to test variable substitution and preview your form with sample data.

Common Patterns

Required Fields

- type: text
  name: email
  label: "Email Address"
  required: yes
  required_message: "Email is required"

Read-only Calculated Fields

- type: text
  name: timestamp
  label: "Submission Time"
  calculation: "now()"
  readonly: yes

Conditional Sections

- type: select_one yes_no
  name: need_help
  label: "Do you need assistance?"
- type: group
  name: help_section
  label: "Help Information"
  relevant: "${need_help} = 'yes'"
  children:
    - type: text
      name: help_type
      label: "What kind of help do you need?"

Best Practices

  1. Use descriptive names: Field names should be clear and consistent

  2. Group related questions: Use groups to organize related questions

  3. Add hints: Provide helpful hints for complex questions

  4. Validate input: Use constraints to ensure data quality

  5. Test thoroughly: Use preview inputs to test your form logic

  6. Keep it simple: Don’t overcomplicate the structure

Common Errors to Avoid

  1. Duplicate names: Each field must have a unique name

  2. Invalid choice references: Ensure choice lists exist before referencing them

  3. Circular references: Don’t create loops in variable substitutions

  4. Missing required fields: Include all mandatory fields for your question types

  5. Incorrect boolean values: Use “yes”/”no” strings, not true/false

Example Complete Survey

settings:
  form_title: "Customer Feedback Survey"
  instance_name: "feedback_${customer_name}_${today()}"
  namespaces: "esri=https://esri.com/xforms"

choices:
  - list_name: satisfaction
    name: very_satisfied
    label: "Very Satisfied"
  - list_name: satisfaction
    name: satisfied
    label: "Satisfied"
  - list_name: satisfaction
    name: neutral
    label: "Neutral"
  - list_name: satisfaction
    name: dissatisfied
    label: "Dissatisfied"
  - list_name: satisfaction
    name: very_dissatisfied
    label: "Very Dissatisfied"

  - list_name: yes_no
    name: yes
    label: "Yes"
  - list_name: yes_no
    name: no
    label: "No"

survey:
  - type: text
    name: customer_name
    label: "Customer Name"
    required: yes
    survey123py::preview_input: "John Smith"

  - type: select_one satisfaction
    name: overall_satisfaction
    label: "How satisfied are you with our service?"
    required: yes

  - type: select_one yes_no
    name: would_recommend
    label: "Would you recommend us to others?"
    required: yes

  - type: text
    name: improvement_suggestions
    label: "What could we improve?"
    relevant: "${overall_satisfaction} = 'dissatisfied' or ${overall_satisfaction} = 'very_dissatisfied'"

  - type: group
    name: contact_info
    label: "Contact Information (Optional)"
    children:
      - type: text
        name: email
        label: "Email Address"
        hint: "We'll only use this for follow-up if needed"
      - type: text
        name: phone
        label: "Phone Number"

  - type: text
    name: submission_id
    label: "Submission ID"
    calculation: "concat('FB_', ${customer_name}, '_', format-date(today(), '%Y%m%d'))"
    readonly: yes

This creates a complete customer feedback survey with conditional logic, validation, and automatic ID generation.