Make a question optional and offer a comment
This example keeps the rating required, adds a place to explain it, and makes the final free-text question optional. Settings underquestions use the question names from the Survey:
humanize_schema to survey.humanize(...) when you publish. The rating and optional feedback remain answer columns; the accompanying explanation is recorded as comment.rating_comment. Use the field reference below for additional settings, or Custom CSS for colors and spacing.
Fields
dict
Map of question name (string) ->
HumanizeQuestionSchema.dict
Optional survey-level options (e.g. custom CSS).
HumanizeQuestionSchema (per question)
Eachquestions[question_name] value is a HumanizeQuestionSchema object.
boolean
default:false
Whether the question is optional. Default is
false when omitted.Supported question types: free_text, budget, checkbox, checkbox_with_other, dropdown, edit, email, file_upload, interview, likert_five, linear_scale, list, matrix, multiple_choice, multiple_choice_with_other, numerical, rank, top_k, url, yes_no.Note: optional currently has no effect for interview and rank.QuestionDropdown is a searchable combo box: respondents enter terms, choose from up to top_k ranked matches (5 by default), and the choice fills the input. Respondents must choose a listed option, and the answer is that option’s text.
In Humanize, QuestionDemand shows a demand curve: for each price, respondents set a quantity with a slider or by typing a number, and the curve redraws as they go. Quantities can’t be negative, and the answer is one quantity per price, in price order. demand doesn’t support optional.
In Humanize, QuestionDict shows one field per key in answer_keys, labelled with the key and its value type, with its entry from value_descriptions underneath. int and float keys take a number, bool keys take Yes or No, list keys (list, list[str], list[int], list[float], list[bool]) take one item per line, with list[bool] items written as true or false, and any other key takes text. The answer has exactly the question’s keys. dict doesn’t support optional.
In Humanize, QuestionURL is a one-line text box. Respondents can leave off the scheme: example.com is accepted and recorded as https://example.com, so the answer is always an absolute URL, as EDSL requires.
In Humanize, QuestionEmail is a one-line email box. Spaces around the address are dropped, and the answer must be a valid email address, as EDSL requires.
In Humanize, QuestionEdit shows text_to_edit in an editable text box, with a tracked-changes preview underneath: deleted text is struck through in red and inserted text is green. The answer is the full revised text.
dict
A limit on how long the respondent may spend answering the question. Omit or set to
null for no limit.While the limit runs, a countdown is shown above the question. When it reaches zero the answer locks: the respondent can no longer change it and clicks Next to continue. They are not moved on automatically. Whatever they had entered is submitted as their answer, and a question they had not answered is recorded as unanswered, even if it is not optional.A time limit applies only while the question is alone on its page. When survey.presentation is "group", every question’s time_limit is ignored, including a question that is the only one in its group. The countdown runs in the respondent’s browser, so reloading the page starts it again.Supported question types: free_text, budget, checkbox, checkbox_with_other, demand, dict, dropdown, edit, email, file_upload, likert_five, linear_scale, list, matrix, multiple_choice, multiple_choice_with_other, numerical, rank, top_k, url, yes_no.dict
Display format. Varies by question type:
- MC-style (
likert_five,linear_scale,multiple_choice,yes_no):"radio"(list of radio buttons) or"dropdown"(single<select>). Default is"radio". Use{"type": "radio"}or{"type": "dropdown"}. - Numerical (
numerical):"input"(number input field) or"slider"(range slider). Default is"input". Use{"type": "input"}or{"type": "slider", "min": 0, "max": 100, "step": 1}. For slider,minmust be less thanmax,stepmust be positive and not exceed(max - min). - Matrix (
matrix):"table"(the whole grid at once) or"carousel"(one item at a time). Default is"table". Use{"type": "table"}or{"type": "carousel"}.
dropdown questions always use their searchable option picker and do not support format. Other question types do not support format.dict
Matrix only (
matrix). Cells checked before the respondent touches the grid. Omit or set to null for an empty grid, which is what matrices render by default.Use preselection when respondents should review and change a supplied starting answer. A row they leave untouched is recorded as the preselected option, so the resulting answer alone does not distinguish accepting that value from leaving the row unexamined. Omit preselection when each row should require a fresh choice.dict
Multiple choice only (
multiple_choice). Optional custom validation rules.dict
Checkbox only (
checkbox; not checkbox_with_other, which shows no such box). The Select all box beneath the options: ticking it selects every option, unticking it clears them. Omit it to keep the box, which every checkbox question shows by default, or set it to null to remove it.Exclusive options are left out of “all”, since checking one clears every other selection.array
default:[]
Checkbox only (
checkbox, checkbox_with_other). Options that stand alone: checking one clears every other selection — including any other exclusive option, and for checkbox_with_other the respondent’s “other” entries — and selecting anything else clears it. Use for options like "None of the above" or "Prefer not to say".Each entry must be the exact text of an option in the question’s question_options — matching is literal, so surrounding whitespace is not trimmed for you. Entries must be non-empty and unique. Because an exclusive option is an ordinary member of the option list, the submitted answer looks like any other selection. Defaults to an empty list, meaning no option is exclusive.dict
default:{"type":"uniform"}
Distribution only (
distribution). What the chart shows before the respondent touches it. Respondents answer a distribution question by painting probability across its outcomes or bins; the percentages always add up to 100%.In the live survey, respondents can also choose Reset to spiked to put all probability on the first outcome, or Reset to uniform to spread it equally across outcomes. Reset to start returns to the configured initial_distribution. These are respondent controls, not additional schema settings.dict
Distribution only (
distribution). Statistics implied by the respondent’s distribution, shown beneath the chart and updated as they paint. Omit or set to null for no summary, which is the default.The statistics assume probability is spread evenly within each bin, and the chart says so. They appear only for finite numeric bins: categories have no values to average, and an open-ended bin such as [10,Inf) has no midpoint. They are a display aid and do not change the submitted answer.string
default:"text"
Interview only (
interview). Controls the input mode offered to respondents."text"— text-based interview (default)."voice"— voice-based interview."both"— respondent can choose between text and voice.
dict
Interview only (
interview). The intro screen shown to the respondent before the interview begins. The intro screen is always shown; this field customizes its text. Omit or set to null to use the default text ("This will be a conversation with an AI agent.").dict
Interview only (
interview). Optional configuration for voice-mode interviews. Ignored when interview_mode is "text".dict
Interview only (
interview). Optional configuration for text-mode interviews. Ignored when interview_mode is "voice".dict
Optional comment input shown with the question.
Submitted comment text appears in survey results under
comment.{question_name}_comment.Supported question types: free_text, budget, checkbox, checkbox_with_other, demand, dict, dropdown, edit, email, likert_five, linear_scale, list, matrix, multiple_choice, multiple_choice_with_other, numerical, rank, top_k, url, yes_no.dict
Optional indicator shown after the respondent clicks Next, while the following question runs. Omit or set to
null for no indicator.Supported question types: free_text, budget, checkbox, checkbox_with_other, demand, dict, dropdown, edit, email, file_upload, likert_five, linear_scale, list, matrix, multiple_choice, multiple_choice_with_other, numerical, rank, top_k, url, yes_no.Note: not supported for compute or image_generation (both run in the background and auto-advance, so neither is ever the question a respondent submits), or for interview.dict
Optional JavaScript that runs on the respondent’s page for this question. Omit or set to
null to run no script. See Custom JavaScript for how to write a hook, what a script may do, and how to retrieve the events it logs.Supported question types: free_text, budget, checkbox, checkbox_with_other, demand, dict, distribution, dropdown, edit, email, file_upload, interview, likert_five, linear_scale, list, matrix, multiple_choice, multiple_choice_with_other, numerical, rank, top_k, url, yes_no, survey_message.Note: not supported for compute or image_generation. Both run in the background and are dropped from the page, so there is no rendered question for a script to attach to.This feature is available on approved accounts only. Write to [email protected] to request approval; until your account is approved, a schema carrying a hook is rejected when you push it.Example
The fuller example below combines a rating with comments, a probability distribution over waiting times, optional feedback, and a lab logo. The logo upload requires a local image and account access; use the simpler example above if you only need question settings.Retrieving a deployed schema
To read back the schema stored on a survey you already deployed:None if the survey was created without one.
In Python, use Coop().patch_human_survey_humanize_schema(human_survey_uuid, partial_schema=changes) to update an existing survey. Nested dictionaries are merged by key; lists, scalars, and explicit None replace the existing value. The complete merged schema is validated. Review the changed fields before updating a live instrument.
From the CLI, ep humanize schema get <uuid> prints it, and --out schema.json
writes it to a file you can edit and send back with ep humanize schema patch.
Give --out a .json.gz suffix to write the schema gzipped; any other suffix
writes plain JSON. Both are readable by the commands that take --schema.
Validation
If the schema is invalid, Expected Parrot raisesHumanizeSchemaValidationError. Common causes:
- A key in
questionsis not a question name in the survey, or is an instruction. - A question’s type is not supported for humanize schema (e.g.
extract). - A question’s entry has the wrong shape for its type (e.g. wrong field types or extra fields that aren’t allowed).
- A
time_limithassecondsoutside 30–7200, or adurationwithout its"type": "fixed". - Top-level structure is invalid (e.g.
questionsnot a dict, or an entry not a dict).
survey.preview(humanize_schema=...) to get a preview URL.
Ensure your humanize schema matches the parameters above for each question type in your survey.