---
lang: en-GB
title: "Deploying a survey and collecting responses on free hosting"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Deploying a survey and collecting responses on free hosting}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{=html}
<style>
/* WCAG 2.2 AA pass: darker link and syntax-token colours (at least
   4.5:1 on the #f7f7f7 code background), wrapped code lines instead of a
   keyboard-inaccessible scroll region, empty per-line anchors removed from
   the accessibility tree, and 24px minimum TOC link targets. */
a { color: #0e7c7a; }
code span.at { color: #576419; }
code span.dv, code span.fl, code span.bn { color: #276245; }
code span.co { color: #396a80; }
pre, pre code { white-space: pre-wrap; word-break: break-word; }
div.sourceCode { overflow: visible; }
pre.sourceCode a:empty { display: none; }
#TOC a { display: inline-block; min-height: 24px; }
</style>
```

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(surveyframe)
```

This guide takes a finished instrument to a live, public survey that writes
responses into a Google Sheet. Every step is free, and the survey itself is a
single HTML file that runs in any browser with no server.

The deployment has three parts.

1. A Google Apps Script collector turns a Google Sheet into a response endpoint.
2. The survey HTML carries that endpoint URL and posts each submission to it.
3. A free static host serves the HTML file to respondents.

You can do all of this from the SurveyBuilder without writing R, or from R with
two function calls. Both routes produce the same files.

## What you need

* A Google account, for the Sheet and the Apps Script collector.
* A finished instrument, either an `.sframe` file from the SurveyBuilder or an
  `sframe` object in R.
* A free static host. This guide covers GitHub Pages and Blogger. Netlify Drop
  and Google Sites work the same way.

## Step 1: Create the Google Sheet and the collector

Create an empty Google Sheet. The collector adds a `Responses` tab with the
correct column headers on the first submission, so you do not prepare the sheet
by hand.

Generate the Apps Script collector. From the SurveyBuilder, open
Survey settings, choose the Google Sheets tab, paste your Sheet URL, and click
**Download collector (.gs)**. From R, call `export_google_sheet()`.

```{r collector, eval = FALSE}
study <- read_sframe("my_study.sframe")

export_google_sheet(
  study,
  sheet_url  = "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID",
  output_dir = "."
)
```

Both routes write `surveyframe_collector.gs`. The file contains one column per
question, plus `respondent_id`, `started_at`, and `submitted_at`. Matrix,
multiple-choice, and ranking questions expand into more than one column: a
matrix gets one column per row, a multiple-choice question gets one 0/1
column per option, and a ranking question gets one column per option holding
its rank.

## Step 2: Deploy the collector as a web app

1. Open the Google Sheet.
2. Click Extensions, then Apps Script.
3. Paste the contents of `surveyframe_collector.gs`, replacing any existing
   code, and save.
4. Click Deploy, then New deployment. Set the type to Web app.
5. Set "Who has access" to Anyone.
6. Authorise the script when Google prompts you.
7. Copy the Web App URL. It ends in `/exec`.

This URL is your collection endpoint. Keep it for the next step.

## Step 3: Put the endpoint into the survey

The exported survey posts each response to whatever endpoint it carries. Set the
endpoint before you export.

From the SurveyBuilder, paste the Web App URL into the
Apps Script Web App URL field on the Google Sheets settings tab, then click
**Export survey**. From R, store the URL on the instrument and call
`export_static_survey()`.

```{r endpoint-export, eval = FALSE}
study$render$google_sheets_endpoint <-
  "https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec"

export_static_survey(
  study,
  output_path = "index.html",
  open        = FALSE
)
```

The result is a single HTML file. Each respondent who submits gets a CSV copy
downloaded to their own device, and the same row is posted to the Google Sheet.
The two paths are independent, so a failed post never loses a response.

Name the file `index.html` if you plan to host it at the root of a site, because
most hosts serve `index.html` as the default page.

## Step 4a: Host on GitHub Pages

GitHub Pages serves static files straight from a repository.

1. Create a public repository, for example `my-survey`.
2. Upload `index.html` to the repository. Use the web uploader at
   Add file, then Upload files, or push with git.
3. Open the repository Settings, then Pages.
4. Under Build and deployment, set Source to Deploy from a branch, choose the
   `main` branch and the `/ (root)` folder, then Save.
5. Wait for the green confirmation. Your survey is now live at
   `https://YOUR_USERNAME.github.io/my-survey/`.

Share that link. To update the survey, re-export the HTML and upload it again
over the old file.

## Step 4b: Host on Blogger

Blogger can serve a survey inside a page.

1. In Blogger, create a new Page, not a Post.
2. Switch the editor from Compose to HTML view.
3. The exported survey is a full HTML document, so embed it in an iframe rather
   than pasting the whole file. Upload `index.html` to any static host first
   (GitHub Pages or Netlify Drop), then embed it:

```html
<iframe src="https://YOUR_USERNAME.github.io/my-survey/"
        style="width:100%;height:1200px;border:0"></iframe>
```

4. Publish the page and share its address.

The iframe approach keeps the survey self-contained and avoids conflicts with
the Blogger theme. The same iframe works in Google Sites, WordPress, and most
content systems.

## Step 5: Read the responses back

Once responses arrive in the Sheet, pull them into R for analysis. Use the Sheet
ID or full URL.

```{r read, eval = FALSE}
responses <- read_sheet_responses(
  sheet_id   = "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID",
  instrument = study
)

qr <- quality_report(responses, study, respondent_id = "respondent_id")
```

The returned data frame is validated against the instrument and is ready for
`quality_report()`, `score_scales()`, `reliability_report()`, and
`run_analysis_plan()`.

## Updating a live survey

Editing the instrument changes the questions, so the column set can change too.
When you add, remove, or rename questions:

1. Re-export and re-deploy the collector so the headers match.
2. Re-export the survey HTML and upload it over the hosted file.

Existing rows in the Sheet stay in place. New submissions use the new columns.

## Checklist

* Sheet created and collector deployed as a web app set to Anyone.
* Web App URL copied and stored on the instrument.
* Survey exported with the endpoint embedded.
* HTML uploaded to a static host and confirmed live.
* A test submission appears as a new row in the Sheet.
* `read_sheet_responses()` returns that row in R.
