Skip to contents



  flatten = FALSE,
  odata = FALSE,
  parse = TRUE,
  draft = FALSE,
  pid = get_default_pid(),
  fid = get_default_fid(),
  url = get_default_url(),
  un = get_default_un(),
  pw = get_default_pw(),
  odkc_version = get_default_odkc_version(),
  retries = get_retries(),
  verbose = get_ru_verbose()



Whether to flatten the resulting list of lists (TRUE) or not (FALSE, default). Only applies to ODK Central version < 0.8.


Whether to sanitise the field names to match the way they will be outputted for OData. While the original field names as given in the XForms definition may be used as-is for CSV output, OData has some restrictions related to the domain-qualified identifier syntax it uses. Only applies to ODK Central version < 0.8. Default: FALSE.


Whether to parse the form schema into a tibble of form field type and name. This uses form_schema_parse internally. If used together with flatten=TRUE, form_schema will raise a warning and return the unparsed, flattened form schema. Only applies to ODK Central version < 0.8. Default: TRUE.


Whether the form is published (FALSE) or a draft (TRUE). Default: TRUE.


The numeric ID of the project, e.g.: 2.

Default: get_default_pid.

Set default pid through ru_setup(pid="...").

See vignette("Setup", package = "ruODK").


The alphanumeric form ID, e.g. "build_Spotlighting-0-8_1559885147".

Default: get_default_fid.

Set default fid through ru_setup(fid="...").

See vignette("Setup", package = "ruODK").


The ODK Central base URL without trailing slash.

Default: get_default_url.

Set default url through ru_setup(url="...").

See vignette("Setup", package = "ruODK").


The ODK Central username (an email address). Default: get_default_un. Set default un through ru_setup(un="..."). See vignette("Setup", package = "ruODK").


The ODK Central password. Default: get_default_pw. Set default pw through ru_setup(pw="..."). See vignette("Setup", package = "ruODK").


The ODK Central version as a semantic version string (year.minor.patch), e.g. "2023.5.1". The version is shown on ODK Central's version page /version.txt. Discard the "v". ruODK uses this parameter to adjust for breaking changes in ODK Central.

Default: get_default_odkc_version or "2023.5.1" if unset.

Set default get_default_odkc_version through ru_setup(odkc_version="2023.5.1").

See vignette("Setup", package = "ruODK").


The number of attempts to retrieve a web resource.

This parameter is given to RETRY(times = retries).

Default: 3.


Whether to display debug messages or not.

Read vignette("setup", package = "ruODK") to learn how ruODK's verbosity can be set globally or per function.


A tibble or nested list (v0.7) containing the form definition. At the lowest nesting level, each form field consists of a list of two nodes, name (the underlying field name) and type (the XForms field type, as in "string", "select1", "geopoint", "binary" and so on). These fields are nested in lists of tuples name (the XForms screen name), children (the fields as described above), type ("structure" for non- repeating screens, "repeat" for repeating screens). A list with name "meta" may precede the structure, if several metadata fields are captured (e.g. "instanceId", form start datetimes etc.). In all cases for ODK Central 0.8, and with default parameters (parse=TRUE) for ODK Central 0.7, form_schema returns a tibble with the columns:

  • name The field name as given in the form schema.

  • type The field type, e.g. "string", "select1", etc.

  • path The XForms path of the field,

  • selectMultiple Whether a field of type "select" is a select multiple (TRUE). Any other types are NA.

  • ruodk_name The predicted field name as generated by odata_submission_get, prefixed by the path, additionally cleaned with make_clean_names to match the cleaned column names from odata_submission_rectangle.


ODK Central has introduced a new API endpoint in version 0.8 which returns a parsed and flattened list of fields. This replaces the nested form schema which is challenging to parse.

While users of newer ODK Central versions (> 0.8) can ignore the legacy support for ODK Central's earlier form schema API, users of ODK Central version < 0.8 can set an environment variable ODKC_VERSION to their ODKC's version in format <major>.<minor> e.g. 0.7. This variable caters for future breaking changes.

Either way, form_schema will always return a tibble with columns name, type, path and ruodk_name.


if (FALSE) {
# See vignette("setup") for setup and authentication options
# ruODK::ru_setup(svc = "....svc", un = "", pw = "...")

# With explicit pid and fid
fs_defaults <- form_schema(pid = 1, fid = "build_xformsId")

# With current ODK Central (v0.8)
fs <- form_schema()

# With defaults, ODK Central v0.7
fs_nested <- form_schema(
  flatten = FALSE,
  odata = FALSE,
  parse = FALSE,
  odkc_version = 0.7

fs_flattened <- form_schema(
  flatten = TRUE,
  odata = FALSE,
  parse = FALSE,
  odkc_version = 0.7

# form_schema returns a nested list. There's nothing to change about that.
# > "list"

# > "list"

# This assumes knowledge of that exact form being tested.
# First node: type "structure" (a field group) named "meta".
# > "structure"

# > "meta"

# The first node contains children, which means it's an XForms field group.
# > "name" "children" "type"

# Next node: a "meta" field of type "string" capturing the  "instanceId".
# First child node of "meta": type "string", name "instanceId".
# > "string"
# > "instanceID"

# In the flattened version, the field's and it's ancestors' names are the
# components of "path".
# > "meta". "instanceId"

# > "string"

# Last node: a "meta" field capturing the datetime of form completion
# > "dateTime"
# > "dateTime"

# Parsed into a tibble of form field type/name:
# Useful to inform further parsing of submission data (attachments, dates)
fs <- form_schema(parse = TRUE, odkc_version = 0.7)
fs <- form_schema(odkc_version = 0.8)

# Attachments: used by handle_ru_attachments
fs %>% dplyr::filter(type == "binary")

# dateTime: used by handle_ru_datetimes
fs %>% dplyr::filter(type == "dateTime")

# Point location: used by handle_ru_geopoints
fs %>% dplyr::filter(type == "geopoint")