Skip to main content
The question component (canvas.question) shows a multiple-choice question card during a conversation. The user taps an option (or types a free-text answer, when allowed) and the structured result goes to the PAL and your conversation webhook.

Triggering

The PAL shows the card by invoking canvas_show_question when the user should answer a structured question. Steer the timing in the PAL’s system prompt.
  • Renders in the safe-area-right slot by default.
  • A repeat canvas_show_question invocation replaces the card currently on screen with a new instance and a new tool_call_id; in-progress input is lost and interactions arrive under the new id.
  • Only one canvas card is on screen at a time. A new canvas_show_question invocation always replaces the current card, even when it targets a different side slot (e.g. layout.preferred_slot: "safe-area-left"); two cards never appear at once.
  • Every Canvas PAL also gets an update_component control action that patches the existing card without replacing it.
question has no component-specific settings beyond enabled. See Enabling and configuring components.

Arguments

The PAL passes these to canvas_show_question:
FieldTypeRequiredDescription
questionstringThe question text shown on the card. Must be non-empty.
optionsarrayThe selectable options. 2–10 items. Option ids must be unique.
options[].idstringStable identifier, echoed back verbatim in selected_option_ids.
options[].labelstringHuman-readable option text shown to the user.
options[].allow_free_textbooleanWhen true, selecting this option reveals a text input for extra detail on that specific choice. Independent of allow_other.
options[].free_text_placeholderstringPlaceholder for that option’s detail input.
allow_skipbooleanWhether the user may skip the question. Default false.
multi_selectbooleanWhether the user may select more than one option. Default false.
allow_otherbooleanAdds an “Other” affordance the user can expand to type a free-text answer. Single-select: mutually exclusive with the preset options. Multi-select: submitted alongside them. Default false.
other_labelstringLabel for the “Other” affordance (e.g. “None of the above”). A generic label is used when omitted.
other_placeholderstringPlaceholder for the “Other” text input.
correct_answerstringOption id of the correct answer for quiz-style questions. When set, the card briefly reveals the correct option against the user’s choice after they submit, then clears. Must match one of options[].id. Omit for surveys, preferences, and open-ended questions; use only when there is one objectively correct option.
Tavus injects two runtime controls on every Canvas action:
FieldTypeValues
layout.preferred_slotenumsafe-area-right, safe-area-left
display_modeenuminline

Example invocation

Quiz example with answer reveal:

Interactions

question is a submit-capable component emitting six interaction types: submit, skip, dismiss, clear, error, and heartbeat. Only submit and skip carry an answer value; the rest are lifecycle signals with no question payload. Each interaction reaches your conversation webhook as a canvas.interaction event with the answer in properties.value.

Value Shape (submit and skip)

FieldTypeRequiredDescription
selected_option_idsstring[]The chosen option ids, echoed exactly as the PAL set them. Empty on skip, or when the user answered only via “Other”.
skippedbooleantrue only on skip.
custom_textstringThe free-text answer from the “Other” affordance. Non-empty, at most 4000 characters.
option_textsobjectPer-option detail text, keyed by option id. Keys must be a subset of selected_option_ids. Each value is non-empty, at most 2000 characters.
Tavus rejects values with any other keys and enforces these rules before delivery:
  • skip: always skipped: true, with no selections, custom_text, or option_texts.
  • submit: always skipped: false, with at least one selected id or a non-empty custom_text; never an empty answer.
The hosted card offers Skip only when allow_skip is true. Tavus does not re-check an incoming skip against the original action arguments, so a custom renderer could post one regardless.

Example Payload

properties always carries the same nine keys. interaction_id uniquely identifies the interaction; tool_call_id ties it to the originating canvas_show_question call. created_at is a naive ISO-8601 timestamp with microseconds and no timezone suffix (no trailing Z); treat it as UTC.
Submit

Webhook Handling

Branch on type first, then read the value:
Key your logic on option ids, not labels. Labels may vary between conversations; ids are required to be unique and are echoed back verbatim.