The Decipher integration produces Decipher-compatible XML that you can upload directly through the Decipher platform. It translates Questra’s JavaScript expressions into idiomatic Python, uses native Decipher shorthand where possible, and handles bidirectional import/export.
Question types
| Questra block | Decipher element | Notes |
|---|
| Text | <html> | Static informational content. Markdown is converted to HTML. |
| Text input | <text>, <number>, <textarea> | Mapped by content type. Email validation uses verify="email". |
| Multiple choice (single) | <radio> | Supports optional attribute when not required. |
| Multiple choice (multi) | <checkbox> | Supports atleast attribute when required. |
| Multiple choice (dropdown) | <select> | Rendered as a dropdown selector. |
| Matrix | <radio> or <checkbox> | Uses <row>, <col>, and <group> elements with axis attributes. |
| Card sort | <radio> or <checkbox> | Cards as rows, categories as columns. |
| Rank order | <select uses="ranksort.7"> | Includes <choice> elements and minRanks, unique, values attributes. |
| Input list | <text> | Exported as a single text input. |
| Loop | <loop> | Expanded using sample data. Requires survey context at export time. |
Option groups
Option groups are only emitted as <group> elements when a question has multiple groups. Single-group questions place options directly inside the question element without a wrapper.
Dynamic option groups
When a question’s options depend on another question’s answers (e.g., “Which of the brands you selected do you prefer?”), the adapter expands the dynamic group at export time using sample data from the source question. Each materialized option gets a cond attribute with a shorthand expression referencing the source.
Dynamic option groups that reference a question on the same page cannot be resolved — Decipher evaluates conditions page-by-page and cannot read forward within a page.
Expressions and logic
Questra JavaScript expressions are converted to Python through a two-stage pipeline: JS → ESTree AST → Python AST → Python code. The adapter uses native Decipher shorthands wherever possible to produce readable, idiomatic output.
Shorthand syntax
For multiple choice questions, the adapter uses Decipher’s property-access shorthand instead of verbose Python generators:
| Questra JS | Decipher Python | Meaning |
|---|
q1.some(o => o.value == "x") | q1.x | Is option x selected? |
q1.some(o => o.value == "x" || o.value == "y") | q1.x or q1.y | Is x or y selected? |
!q1.some(o => o.value == "x") | (not q1.x) | Is option x not selected? |
q1.value == "x" | q1.x | Single-select: is x the chosen value? |
Complex callbacks that go beyond simple value checks fall back to full Python generator expressions.
Supported expression patterns
| JavaScript pattern | Python equivalent |
|---|
q.value == "x" | q.x (MC) or q.val == 'x' (other types) |
q.some(o => ...) | q.x shorthand or any(...) generator |
q.every(o => ...) | all(...) generator |
q.filter(o => ...) | List comprehension [i for i in ...] |
q.map(o => ...) | List comprehension [fn(i) for i in ...] |
q.find(o => ...) | next((i for i in ... if ...), None) |
q.findIndex(o => ...) | next((idx for idx, i in enumerate(...) if ...), -1) |
q.reduce(fn, init) | reduce(...) or inline loop |
q.includes(x) | x in q |
q.length | len(q) |
Object.keys(matrix) | Row label iteration |
typeof x | Type-checking helper |
x ?? y | x if x is not None else y |
cond ? a : b | a if cond else b |
&&, ||, ! | and, or, not |
Variable references
Variables are exported as hidden <text> elements with where="execute,survey,report". Computed variable expressions are placed in <exec> blocks that set the .val property.
Device type detection
Questra’s questra.device_type checks are translated to Decipher’s native device detection API:
| Questra expression | Decipher equivalent |
|---|
questra.device_type == "mobile" | gv.request.device.isSmartphone() |
questra.device_type == "tablet" | gv.request.device.isTablet() |
questra.device_type == "desktop" | not (gv.request.device.isSmartphone() or gv.request.device.isTablet()) |
Navigation
| Feature | Support |
|---|
| Conditional skip | ✅ <goto> with cond attribute |
| Unconditional skip | ✅ <goto> without cond (non-adjacent targets only) |
| Disqualification | ✅ <term> element |
| Survey completion | ✅ <finish> element |
| Option show/hide | ✅ cond attribute on <row> elements |
Navigation elements are placed inline after the <suspend/> tag that follows the source page’s questions.
Import
The Decipher adapter can import existing surveys by parsing the XML and reconstructing the Questra survey model. During import:
- Question elements are mapped back to Questra block types based on their XML tag
- Python shorthand expressions (
q.x) and verbose patterns (any(...)) are both recognized and converted to JavaScript
- Value mappings are reversed so that platform-normalized labels map back to original Questra identifiers
- Loop elements are reconstructed into Questra Loop blocks with
loopOver, loopKey, and nested block configs
Warnings
The adapter emits warnings for situations that need your attention:
| Condition | Severity | Message |
|---|
| Question has no label | Warning | The question name is used as the <title> |
| Name is a reserved Decipher keyword | Warning | The name is automatically renamed |
| Option values start with a number | Warning | An o prefix is added to the label |
| Loop block without survey context | Warning | Block is skipped |
| Dynamic group references same-page question | Warning | Group is skipped |
| Unsupported block type | Error | Block is exported as a placeholder |