Introduction
Survey Solutions questionnaires are sophisticated hierarchical documents comprising sections, multi-level rosters, conditional skip patterns, inline validation rules, static text instructions, and calculated variables.
With SurveySolutionsAPIv2, you can
extract the entire questionnaire specification in milliseconds into
clean, normalized flat tables. This enables automated codebook
generation, survey documentation, and pre-fieldwork verification of
routing logic.
1. Extracting Questionnaire Structure
To extract the structure of a questionnaire, supply the
QuestionnaireId (GUID), version, and specify
operation.type = "structure":
library(SurveySolutionsAPIv2)
# Extract questionnaire structure
quest_struct <- suso_getQuestDetails(
questID = "17a9fa22-1ef6-46d2-8c30-426aa876f273",
version = 1,
operation.type = "structure",
include_raw = FALSE
)The function returns a named list with 4 structured
data.table elements:
names(quest_struct)
#> [1] "q" "val" "v" "answers"-
q: Question, roster, and variable metadata. -
val: Validation rules, expressions, messages, and severity labels. -
v: Backward-compatible alias forval. -
answers: Categorical question answer codes, labels, and category mapping.
2. Question Hierarchy and Metadata (q)
The q table provides an atomic, row-by-row flat
representation of every item in the questionnaire:
dim(quest_struct$q)
#> [1] 925 29Inspecting Essential Columns
Key columns include: - intID:
Hierarchical index formatted as clean dot-separated levels
(e.g. 01, 01.02, 01.02.04). -
VariableName: Variable name used during
data export. - QuestionText: Formatted
question prompt or label. - type: Element
type (SingleQuestion, NumericQuestion,
TextQuestion, GpsCoordinateQuestion,
AreaQuestion, Variable,
StaticText, etc.). -
SectionTitle &
RosterTitle: Contextual hierarchy
indicating parent sections and rosters.
# Display a sample of questions
quest_struct$q[1:6, .(intID, VariableName, type, QuestionText = substr(QuestionText, 1, 40))]
#> intID VariableName type QuestionText
#> <char> <char> <char> <char>
#> 1: 01 Group <NA>
#> 2: 01.01 StaticText Household Budget Survey (HBS) 2025/26
#> 3: 01.02 cover01 SingleQuestion 1. Governorate
#> 4: 01.03 cover02 SingleQuestion 2. District
#> 5: 01.04 cover03 SingleQuestion 3. Sub-district
#> 6: 01.05 cover04 TextQuestion 4. Grid cell IDStatic Text and Calculated Variables
Unlike standard survey tools, Survey Solutions supports static text
blocks and calculated variables (derived formulas).
SurveySolutionsAPIv2 captures both without data loss:
# Calculated variables and expressions
calc_vars <- quest_struct$q[type == "Variable", .(VariableName, Expression, VariableType, VariableLabel)]#> VariableName Expression VariableType
#> <char> <char> <int>
#> 1: age_greg /* This calculate the age from the 1
#> 2: age_month CenturyMonthCode(start.Value.Month, 1
#> 3: S1Q06a hhr_brthcal==1?\nage_greg : S1Q06ya 1
#> 4: final_months hhr_brthcal==1?\nage_month : (S1Q06b 1
#> 5: S1Q10_over6m (S1Q12>6) ? 1:2 1
3. Skip Patterns and Routing Logic
Routing conditions (ConditionExpression) define when a
question or entire roster is visible or skipped:
# Questions with routing conditions
conditions <- quest_struct$q[!is.na(ConditionExpression) & nchar(ConditionExpression) > 0,
.(VariableName, ConditionExpression = substr(ConditionExpression, 1, 50))]
head(conditions, 5)
#> VariableName ConditionExpression
#> <char> <char>
#> 1: refusal_reason consent00==2
#> 2: refusal_others refusal_reason==96
#> 3: consent00==1
#> 4: consent00==1
#> 5: q14 consent00==1Survey designers can use this table to verify that skip patterns reference valid prior variables before piloting.
4. Validation Rules and Severity (val)
The val table extracts all Designer validation
expressions and their associated error messages:
dim(quest_struct$val)
#> [1] 308 10Each validation record provides: -
VariableName: The target variable being
validated. - Expression: The C# boolean
expression that must evaluate to true. -
Message: The message presented to the
enumerator if the expression evaluates to false. -
Severity: 0 for Error (blocks
completion), 1 for Warning (can be acknowledged). -
SeverityLabel: Human-readable
"Error" or "Warning".
# Inspect validation rules
quest_struct$val[1:5, .(VariableName, Expression = substr(Expression, 1, 30), SeverityLabel, Message = substr(Message, 1, 35))]
#> VariableName Expression SeverityLabel
#> <char> <char> <char>
#> 1: q6_oth self.Length>2 Error
#> 2: q9_oth self.Length>2 Error
#> 3: q9_flr_oth self > 6 && self <= 20\r\n Error
#> 4: refusal_others self.Length>2 Error
#> 5: q15 self.Length>=10 Error
#> Message
#> <char>
#> 1: Specification is too short. Please
#> 2: Specification is too short. Please
#> 3:
#> 4: Specification is very short. Please
#> 5: The reason is not detailed. Please5. Generating Codebooks (answers)
For categorical questions (single-select and multi-select), the
answers table captures all answer options:
dim(quest_struct$answers)
#> [1] 1373 8Each record contains: - VariableName:
Parent variable name. - AnswerValue:
Internal key. - AnswerCode: Numeric code
exported in datasets. - AnswerText: Label
shown to respondents and enumerators. -
CategoriesId &
CategoryName: Reusable category catalogue
reference if applicable.
# View codebook options for a sample question
sample_var <- quest_struct$answers[!is.na(AnswerText)][1, VariableName]
quest_struct$answers[VariableName == sample_var, .(VariableName, AnswerCode, AnswerText)]
#> VariableName AnswerCode AnswerText
#> <char> <num> <char>
#> 1: cover05 1 Sub-cell N°1
#> 2: cover05 2 Sub-cell N°2
#> 3: cover05 3 Sub-cell N°3
#> 4: cover05 4 Sub-cell N°46. Clean Flat Tables vs Raw JSON
By default, include_raw = FALSE produces pure atomic
tables with no list-columns. This ensures direct compatibility with file
writers like data.table::fwrite():
# Export directly to CSV without list-column serialization errors
data.table::fwrite(quest_struct$q, "questionnaire_metadata.csv")
data.table::fwrite(quest_struct$answers, "questionnaire_codebook.csv")If you require low-level access to the original JSON node definitions
(such as custom properties or raw translation tables), set
include_raw = TRUE:
# Retain raw ..JSON list column
raw_struct <- suso_getQuestDetails(
questID = "17a9fa22-1ef6-46d2-8c30-426aa876f273",
version = 1,
operation.type = "structure",
include_raw = TRUE
)
# Access raw properties of the 10th node
raw_node <- raw_struct$q$..JSON[[10]]7. Questionnaire Settings: Audio & Criticality
Audio Audit Recording
Survey Solutions supports background audio recording audits for quality assurance:
# Query current audio recording setting
audio_setting <- suso_questRecordAudio(
questID = "17a9fa22-1ef6-46d2-8c30-426aa876f273",
version = 1
)
# Enable background audio recording
suso_questRecordAudio(
questID = "17a9fa22-1ef6-46d2-8c30-426aa876f273",
version = 1,
enabled = TRUE
)Criticality Level
You can programmatically retrieve or enforce validation criticality:
# Get current criticality level
suso_questCriticalityLevel(
questID = "17a9fa22-1ef6-46d2-8c30-426aa876f273",
version = 1
)
# Set criticality level to Warn
suso_questCriticalityLevel(
questID = "17a9fa22-1ef6-46d2-8c30-426aa876f273",
version = 1,
level = "Warn"
)