Scripting
Overview
Scripting lets you compute a final value for a Profile question using code instead of a manual selection.
Use this when you need advanced logic (for example: score computation, segmentation, status labels, or dynamic classification based on previous answers).
Prerequisites
To use scripting, configure your question with all of the following:
- Question type: Profile question
- Mode: Automatic
- Automatic type: Scripting (
Compute a value with a script)
When this setup is enabled, a dedicated text area appears (editor-like input) where you can write the script that calculates the respondent's final value.
Scripts run in a secure sandbox with no access to the file system, network, or Java classes, and are limited to 500ms of execution time. Keep scripts short and avoid repeated calculations to stay well under this limit.
Referencing previous answers
Variables follow a structured naming pattern based on the question type:
[Question ref].[Element ref].[Property]
Profile / adaptive questions
| Variable | Description | Example value |
|---|---|---|
Q1.ANSWER | Full answer(s), comma separated | "Yes" or "Option A,Option B" |
Q1.COUNT | Number of selected answers | 1 or 3 |
Q1.A001, Q1.A002, ... | Nth selected answer (1-based index) | "Option A" |
Battery of items
I1, I2, ... refer to the item refs in the battery.
| Variable | Description | Example value |
|---|---|---|
Q2.I1.ANSWER | Answer(s) for item I1 | "Satisfied" |
Q2.I1.COUNT | Number of answers for item I1 | 1 |
Q2.I1.A001 | First answer of item I1 | "Satisfied" |
Hotspot
Z1, Z2, ... refer to the zone refs in the hotspot.
| Variable | Description | Example value |
|---|---|---|
Q3.Z1.ANSWER | Answer for zone Z1 | "Selected" |
Q3.Z1.COUNT | Number of answers for zone Z1 | 1 or 0 |
Open questions
F1, F2, ... refer to the field refs in the open question.
| Variable | Description | Example value |
|---|---|---|
Q4.F1.ANSWER | Answer of field F1 | "John Smith" |
Q4.F2.ANSWER | Answer of field F2 | "john@email.com" |
R3M questions (3 words / Experience)
| Variable | Description | Example value |
|---|---|---|
Q5.WORD1.ANSWER | First word | "Innovation" |
Q5.WORD2.ANSWER | Second word | "Quality" |
Q5.WORD3.ANSWER | Third word | "Service" |
Loop iterations
When a question is repeated inside a loop, each iteration exposes its own set of variables using the LOOPn notation (0-based):
Q1.LOOP0.ANSWER // first iteration
Q1.LOOP1.ANSWER // second iteration
Q1.LOOP2.ANSWER // third iteration
Data-access functions
Instead of reading raw variables, use the dedicated access functions below. They are recommended: they are more readable, and they resolve missing answers or invalid refs to null (or 0 for counts) instead of failing.
| Question type | Function | Equivalent to |
|---|---|---|
| Profile / adaptive | getAnswer(questionRef) | Q1.ANSWER |
| Profile / adaptive | getAnswer(questionRef, index) | Q1.A001 |
| Profile / adaptive | getAnswerCount(questionRef) | Q1.COUNT |
| Battery | getItemAnswer(questionRef, itemRef) | Q2.I1.ANSWER |
| Battery | getItemAnswer(questionRef, itemRef, index) | Q2.I1.A001 |
| Battery | getItemAnswerCount(questionRef, itemRef) | Q2.I1.COUNT |
| Hotspot | getZoneAnswer(questionRef, zoneRef) | Q3.Z1.ANSWER |
| Hotspot | getZoneAnswer(questionRef, zoneRef, index) | - |
| Hotspot | getZoneAnswerCount(questionRef, zoneRef) | Q3.Z1.COUNT |
| Open question | getFieldAnswer(questionRef, fieldRef) | Q4.F1.ANSWER |
| Open question | getFieldAnswer(questionRef, fieldIndex) | Q4.F1.ANSWER (by position) |
| R3M (3 words) | getWord1(questionRef) / getWord2(...) / getWord3(...) | Q5.WORD1.ANSWER, etc. |
| R3M (3 words) | getWord(questionRef, wordRef) | Q5.WORD1.ANSWER |
getAnswer('Q1') // → "Yes"
getAnswer('Q1', 1) // → "Option A"
getAnswerCount('Q1') // → 3
getItemAnswer('Q2', 'I1') // → "Satisfied"
getItemAnswerCount('Q2', 'I1') // → 2
getZoneAnswer('Q3', 'Z1') // → "Selected"
getZoneAnswerCount('Q3', 'Z1') // → 1
getFieldAnswer('Q4', 'F1') // → "John Smith"
getFieldAnswer('Q4', 1) // → "John Smith"
getWord1('Q5') // → "Innovation"
getWord('Q5', 'WORD2') // → "Quality"
An invalid or out-of-range ref (for example getItemAnswer('Q2', 'I999')) returns null rather than raising an error. Always guard against null before using a value in a comparison or calculation.
JexlScript syntax basics
Scripting is based on JexlScript. If you are familiar with JavaScript-like control flow, you will quickly recognize the syntax.
Key syntax rules:
- End each instruction with
; - Use
varto declare variables - Use
if (...) { ... }for conditions - Use
else { ... }for alternative logic - Use
==,!=,>,<,>=,<=,&&,||,!for comparisons and logical tests - The script's result is the value of the last evaluated expression — no explicit
returnis required, thoughreturn ...;is also supported
Example script
var gender = text(getAnswer('Q1'));
var age = integer(getAnswer('Q2'), 0);
var value = 'N/A';
if (gender == 'Male' || gender == 'Female') {
value = gender;
if (age > 45) {
value = value + ' - out of target';
} else {
value = value + ' - in target';
}
}
value
What this example does:
- Reads gender from
Q1as text - Reads age from
Q2as an integer, defaulting to0if missing or invalid - Builds a label only for expected gender values
- Returns
N/Awhen no valid classification can be computed
Conversion functions
| Function | French alias | Description |
|---|---|---|
number(value) | nombre(value) | Converts a value to a decimal number |
number(value, default) | nombre(value, default) | Same, using default if the conversion fails |
integer(value) | entier(value) | Converts a value to an integer (truncates decimals) |
integer(value, default) | entier(value, default) | Same, using default if the conversion fails |
text(value) | texte(value) | Converts a value to text |
number('42') // → 42.0
number('abc', 0) // → 0 (fallback, 'abc' is not a number)
integer('3.14') // → 3
text(42) // → "42"
Math functions
| Function | French alias | Description |
|---|---|---|
round(number) | arrondi(number) | Rounds to the nearest integer |
max(a, b) | - | Returns the greater of two numbers |
min(a, b) | - | Returns the lesser of two numbers |
abs(number) | - | Returns the absolute value |
modulo(a, b) | - | Returns the remainder of a divided by b |
exp(number) | exponential(number) / exponentielle(number) | Computes the exponential (e^x) |
round(3.7) // → 4
max(10, 20) // → 20
min(10, 20) // → 10
abs(-42) // → 42
modulo(10, 3) // → 1
exp(1) // → 2.718281828...
Text functions
| Function | French alias | Description |
|---|---|---|
length(text) | longueur(text) | Returns the length of a text value |
trim(text) | - | Removes leading and trailing whitespace |
length('Hello') // → 5
trim(' Hello ') // → "Hello"
Additional examples
Numeric score with rounding
var scoreA = number(getItemAnswer('Q3', 'I1'));
var scoreB = number(getItemAnswer('Q3', 'I2'));
var total = scoreA + scoreB;
var avg = round(total / 2);
avg
Keep the highest value from multiple inputs
var v1 = number(getAnswer('Q4'));
var v2 = number(getAnswer('Q5'));
var v3 = number(getAnswer('Q6'));
max(max(v1, v2), v3)
Weighted score
var note1 = number(getAnswer('Q_NOTE1'), 0);
var note2 = number(getAnswer('Q_NOTE2'), 0);
var note3 = number(getAnswer('Q_NOTE3'), 0);
// Weighting: 50% note1, 30% note2, 20% note3
var score = (note1 * 0.5) + (note2 * 0.3) + (note3 * 0.2);
round(score)
Message based on a threshold
var score = number(getAnswer('Q_SCORE'), 0);
if (score >= 80) {
'Excellent - ' + text(score) + '%';
} else if (score >= 60) {
'Good - ' + text(score) + '%';
} else {
'Below target - ' + text(score) + '%';
}
Concatenation of several fields
var firstName = getFieldAnswer('Q_IDENTITY', 'F1');
var lastName = getFieldAnswer('Q_IDENTITY', 'F2');
var city = getFieldAnswer('Q_IDENTITY', 'F3');
firstName + ' ' + lastName + ', ' + city
// → "John Smith, Paris"
Rules and limitations
Allowed:
if/elseconditions- Comparison operators (
==,!=,<,>,<=,>=) - Logical operators (
&&,||,!) - Arithmetic operators (
+,-,*,/,%) - Local variables (
var x = ...) - Function calls
- Text concatenation (
+) - Property access (
.) - Literals (arrays, objects)
Not allowed:
while/forloops- Lambdas / anonymous functions
- Object creation with
new - Access to Java classes
- Library imports
- Modification of global variables
Scripts are limited to 500ms of execution time and run in an isolated sandbox with no access to the file system or network. Only the documented functions and question variables are available.
Best practices
- Initialize a default fallback value first (for example
"N/A") - Convert values explicitly (
text(...),number(...),integer(...)) before comparisons, using the default-value overload to guard against missing answers - Check for
nullbefore using a value, especially withgetItemAnswer,getZoneAnswer, andgetFieldAnswer, which returnnullfor missing or invalid refs - Store repeated calculations in a variable instead of recomputing them in every branch
- Keep scripts short and readable to stay within the 500ms timeout
- Test edge cases (empty answers, unexpected values, missing responses)
- Always verify that the script returns a value in every branch