Intro to surveydown
EMSE 6035: Marketing Analytics for Design Decisions
John Paul Helveston
September 30, 2026

Quiz 2

10:00
Write your name on the quiz!
Rules:
  • Work alone; no outside help of any kind is allowed.
  • No calculators, no notes, no books, no computers, no phones.

Week 6: Intro to surveydown

1. What is surveydown?

2. Survey basics

3. Conditional logic

4. Storing & fetching data

5. Reactivity

Before we start…


1. Install surveydown

install.packages("surveydown")


2. Download today’s class files

Each demo-* folder is a complete survey.
Open one in Positron with File › Open Folder…

Week 6: Intro to surveydown

1. What is surveydown?

2. Survey basics

3. Conditional logic

4. Storing & fetching data

5. Reactivity

Typical experience making a survey

❌ Reproducible
❌ Data Control
⚠️ Free to Use
⚠️ Open Source
⚠️ Easy Collaboration
⚠️ Feature Packed

Introducing surveydown

Components


survey.qmd

A Quarto doc defining the main survey content (pages, text, images, questions, etc).

app.R

An R script defining the survey Shiny app. It sets up the database and server, and launches the survey.

---
survey-settings:
  mode: preview
---

```{r}
library(surveydown)
```

--- welcome

# Welcome to our survey!

```{r}
sd_question(
  type  = "mc",
  id    = "penguins",
  label = "What's your favorite penguin?",
  option = c(
    "Adélie"    = "adelie",
    "Chinstrap" = "chinstrap",
    "Gentoo"    = "gentoo"
  )
)
```

--- end

This is the last page of the survey.

```{r}
sd_close()
```
survey.qmd
---
survey-settings:
  mode: preview
---

```{r}
library(surveydown)
```

--- welcome

# Welcome to our survey!

```{r}
sd_question(
  type  = "mc",
  id    = "penguins",
  label = "What's your favorite penguin?",
  option = c(
    "Adélie"    = "adelie",
    "Chinstrap" = "chinstrap",
    "Gentoo"    = "gentoo"
  )
)
```

--- end

This is the last page of the survey.

```{r}
sd_close()
```

YAML header (survey settings)

mode: preview saves responses to a local file while you build


Load surveydown package

---
survey-settings:
  mode: preview
---

```{r}
library(surveydown)
```

--- welcome

# Welcome to our survey!

```{r}
sd_question(
  type  = "mc",
  id    = "penguins",
  label = "What's your favorite penguin?",
  option = c(
    "Adélie"    = "adelie",
    "Chinstrap" = "chinstrap",
    "Gentoo"    = "gentoo"
  )
)
```

--- end

This is the last page of the survey.

```{r}
sd_close()
```

Start each page with
--- and a page id:

--- page_id

Page content


No closing tag needed:
the next --- starts the next page

---
survey-settings:
  mode: preview
---

```{r}
library(surveydown)
```

--- welcome

# Welcome to our survey!

```{r}
sd_question(
  type  = "mc",
  id    = "penguins",
  label = "What's your favorite penguin?",
  option = c(
    "Adélie"    = "adelie",
    "Chinstrap" = "chinstrap",
    "Gentoo"    = "gentoo"
  )
)
```

--- end

This is the last page of the survey.

```{r}
sd_close()
```






Use markdown for page content

Use sd_question() in a code chunk for survey questions


A Next button is added to every page automatically

---
survey-settings:
  mode: preview
---

```{r}
library(surveydown)
```

--- welcome

# Welcome to our survey!

```{r}
sd_question(
  type  = "mc",
  id    = "penguins",
  label = "What's your favorite penguin?",
  option = c(
    "Adélie"    = "adelie",
    "Chinstrap" = "chinstrap",
    "Gentoo"    = "gentoo"
  )
)
```

--- end

This is the last page of the survey.

```{r}
sd_close()
```














Use sd_close() on the last page for an “Exit Survey” button

library(surveydown)

# Connects to database
db <- sd_db_connect()

# Main UI
ui <- sd_ui()

server <- function(input, output, session) {
  # Main server
  sd_server(db)
}

shiny::shinyApp(
  ui = ui,
  server = server
)
app.R
library(surveydown)

# Connects to database
db <- sd_db_connect()

# Main UI
ui <- sd_ui()

server <- function(input, output, session) {
  # Main server
  sd_server(db)
}

shiny::shinyApp(
  ui = ui,
  server = server
)

Load package

Connect to database

Make standard UI


Run surveydown server

05:00
Your turn

Step 1: Open the demo-question-types folder in Positron
(File › Open Folder…)


Step 2: Open app.R and click the “Run App” arrow in the top-left (near where the “preview” button usually is for Quarto docs)


Step 3: Click through the survey, then look at survey.qmd to see how each question was made

Start a new survey from a template

In the R console, run:

surveydown::sd_create_survey()

Optional: Specify a path and / or a template:

surveydown::sd_create_survey(
  template = "question_types",
  path = "path/to/folder"
)

Warning

Every surveydown survey should be in its own separate project folder.

Week 6: Intro to surveydown

1. What is surveydown?

2. Survey basics

3. Conditional logic

4. Storing & fetching data

5. Reactivity

YAML header

All survey settings go in the YAML header at the top of survey.qmd

---
theme-settings:
  theme: default
  barposition: top
survey-settings:
  mode: preview
  show-previous: no
  all-required: no
  required: []
---

No header at all? Everything uses the defaults.
Full list of settings on the Survey Settings docs page

Survey mode

Set under survey-settings in the YAML header:

survey-settings:
  mode: preview


mode Where responses are saved
preview preview_data.csv in your survey folder
local local_data.csv in your survey folder
database (default) Your database (see part 4)


Use preview while you build, switch to database before you launch

Change the survey theme

Pick a different bootswatch theme with the theme key:

theme-settings:
  theme: united


Make a custom theme with a custom.scss file:

theme-settings:
  theme: [united, custom.scss]

Progress bar

Modify the survey progress bar with the barcolor and barposition keys:


Change to any color with barcolor:

theme-settings:
  barcolor: "#768692"

Change position: top, bottom, or none

theme-settings:
  barposition: bottom

Inserting pages

Start each page with --- and a page id:

--- page_id

Page content here

Next buttons are added automatically.

Add a Previous button to every page in the YAML:

survey-settings:
  show-previous: yes

Or control one page’s buttons with sd_nav() (e.g. change the label):

```{r}
sd_nav(label_next = "Continue")
```

Inserting questions

Insert questions using the sd_question() function, like this:

Code

sd_question(
  type = 'mc',
  id = 'fruit',
  label = "1. Do you like fruit?",
  option = c(
    'Yes!' = 'yes',
    'Kind of' = 'kind_of',
    'No :(' = 'no'
  )
)

Format is "Label" = "value"

Output

*

surveydown supports lots of question types

Some common types you may want to use:

Type Description
mc Multiple choice question (single choice)
mc_multiple Multiple choice question (multiple choices)
mc_buttons Multiple choice question (large buttons)
select Drop down menu (choose one)
text Open text, single row
textarea Open text, block
numeric Numbers only
matrix Several questions with the same options (e.g. agree / disagree)

Or define questions in a questions.yml file

In questions.yml:

fruit:
  type: mc
  label: 1. Do you like fruit?
  options:
    Yes!: yes
    Kind of: kind_of
    No :(: no

In survey.qmd:

```{r}
sd_question("fruit")
```


See the demo-questions-yml folder

Embed images with html

I recommend just writing html code, like this

<center>
<img src="https://surveydown.org/images/logo.png" width=250>
</center>

Embed images with markdown

![](https://surveydown.org/images/logo.png){fig-align="center" width="250"}

Try out the surveydown studio app

sdstudio::launch()

10:00

Your turn

  • Make a new survey with surveydown::sd_create_survey() and open its folder in Positron.
  • Pick a topic for your survey (a food, an animal, a sports team…whatever).
  • Draft a survey about that topic in survey.qmd. Include the following:
    • Page 1: A welcome message in large font (“Welcome to a survey about [topic]”) and an image about the topic (find an image somewhere).
    • Pages 2 to N: Add different questions about the topic using several different question types.
  • Try out different themes to change the look and feel.

Week 6: Intro to surveydown

1. What is surveydown?

2. Survey basics

3. Conditional logic

4. Storing & fetching data

5. Reactivity

Three conditional logic functions


All go in the server() function in app.R:


Function What it does
sd_show_if() Show a question or page if a condition is TRUE
sd_skip_if() Skip forward to a page if a condition is TRUE
sd_stop_if() Stop navigation (with a message) if a condition is TRUE

Conditional Showing

Conditional question showing

Conditional question showing

Define both conditional and target questions in survey.qmd

# Conditional question
sd_question(
  type = "mc",
  id = "penguins",
  label = "Which is your favorite type of penguin?",
  option = c(
    "Adélie" = "adelie",
    "Chinstrap" = "chinstrap",
    "Gentoo" = "gentoo",
    "Other" = "other"
  )
)

# Target question
sd_question(
  type = "text",
  id = "penguins_other",
  label = "Please specify the other penguin type:"
)

Conditional question showing

Define condition with sd_show_if() in app.R

server <- function(input, output, session) {
  sd_show_if(
    sd_value("penguins") == "other" ~ "penguins_other"
  )

  # ...other server code...
}
  1. The structure of the condition is always:
<condition> ~ "target_question_id"
  1. Use sd_value("id") to get the value of a question

Conditional Page Showing

Example: Randomly show one of two page versions


First, define all pages in your survey.qmd file:

--- page1

This is page 1

--- page2a

This is page 2A

--- page2b

This is page 2B

--- page3

This is page 3

```{r}
sd_close()
```

In app.R:

server <- function(input, output, session) {
  # Generate random condition
  rand_val <- sample(c('A', 'B'), 1)

  # Store the condition value
  sd_store_value(rand_val)

  # Use sd_show_if to show target pages
  sd_show_if(
    rand_val == 'A' ~ 'page2a',
    rand_val == 'B' ~ 'page2b'
  )

  sd_server()
}



sd_store_value() saves rand_val in your response data, so you know which version each respondent saw

Conditional Skipping

Example: Participant screen out

Example: Participant screen out


In survey.qmd: Target screenout question

sd_question(
  type = 'mc',
  id = 'vehicle_ownership',
  label = "Do you own a vehicle?",
  option = c(
    'Yes' = 'yes',
    'No' = 'no'
  )
)

In app.R:

server <- function(input, output, session) {
  sd_skip_if(
    sd_value("vehicle_ownership") == "no" ~ "screenout"
  )

  # ...other server code...
}

Target screenout page

--- screenout

Sorry, but you are not qualified to take our survey.

For all three functions, there are lots of
conditions to choose from

See the demo-conditional-showing and
demo-conditional-skipping folders

15:00

Your turn

  • Open the survey you were editing from your last practice.
  • Add conditional logic content:
    • Add one simple multiple choice question about your survey topic and another that will only show depending on a specific choice in the first question.
    • Add a target page that respondents should be sent to based on their choices in another question in an earlier page (e.g., a multiple choice question).

Break

05:00

Week 6: Intro to surveydown

1. What is surveydown?

2. Survey basics

3. Conditional logic

4. Storing & fetching data

5. Reactivity

Data is stored in any PostgreSQL database
We use Supabase as a free, open-source option

Store data in Supabase

Steps to connect a database via Supabase:

  1. Create a Supabase account
  2. Create a Supabase project
  3. Copy your credentials


Full details on the Storing Data docs page

Creating a project

  • Choose a project name (this is your “database”)
  • Each database can have multiple tables
  • Choose a strong password

Getting your Supabase credentials

Click the “connect” button in your project

Choose “Direct”, then find the “Transaction pooler” section

Store your database credentials

In your R console, run:

surveydown::sd_db_config()


Credentials are stored in a .env file in your survey folder.

Never share or commit this file — it has your password.

app.R
library(surveydown)

# Connects to database
db <- sd_db_connect()

# Main UI
ui <- sd_ui()

server <- function(input, output, session) {
  # Main server
  sd_server(db)
}

shiny::shinyApp(
  ui = ui,
  server = server
)





sd_db_connect() uses the .env file to make the database connection.


Then set mode: database in survey.qmd
(or delete the mode line — it’s the default)

Use sdstudio::launch() to locally view data

10:00

Your turn

  • Create a Supabase account and database.
  • Run surveydown::sd_db_config() in your console to store your Supabase credentials.
  • Change mode: preview to mode: database in your survey.qmd.
  • Run your survey locally, answer questions to generate data.
  • View your response data with sdstudio::launch()

Week 6: Intro to surveydown

1. What is surveydown?

2. Survey basics

3. Conditional logic

4. Storing & fetching data

5. Reactivity

Read the chapter in Mastering Shiny to
understand reactivity in general


Read the surveydown reactivity page
for reactivity in surveydown

Reactivity is about changing
something based on respondent input

Same example in surveydown

In survey.qmd:

```{r}
sd_question(
  type  = "text",
  id    = "name",
  label = "What is your name?"
)

textOutput("greeting")
```

In app.R:

server <- function(input, output, session) {
  output$greeting <- renderText({
    paste0("Hello ", sd_value("name"), "!")
  })

  sd_server()
}

Simplified with sd_output() to display question values

In survey.qmd:

```{r}
sd_question(
  type  = "text",
  id    = "name",
  label = "What is your name?"
)
```

Hello, `r sd_output("name", type = "value")`!

In app.R:

server <- function(input, output, session) {
  sd_server()
}

Understanding sd_output()

Question in survey.qmd:

sd_question(
  type = "mc",
  id = "penguins",
  label = "What's your favorite penguin?",
  option = c(
    "Adélie" = "adelie",
    "Chinstrap" = "chinstrap",
    "Gentoo" = "gentoo"
  )
)

Display a question value:

sd_output("penguins", type = "value")

Example: adelie


Display a question option label:

sd_output("penguins", type = "label_option")

Example: Adélie

Understanding sd_output()

Question in survey.qmd:

sd_question(
  type = "mc",
  id = "penguins",
  label = "What's your favorite penguin?",
  option = c(
    "Adélie" = "adelie",
    "Chinstrap" = "chinstrap",
    "Gentoo" = "gentoo"
  )
)

Display a question label:

sd_output("penguins", type = "label_question")

Example:
What's your favorite penguin?

07:00
Your turn

In your survey, display a question value somewhere with:

`r sd_output("id", type = "value")`


In your survey, display a question option label somewhere with:

`r sd_output("id", type = "label_option")`

Blog post on conjoint in surveydown
Next team deliverable:
Pilot Survey (Due 10/13)