if
Experiments Surveys & forms
if holds one or more conditions evaluated against the participant’s last response after the trial completes. When a condition is true, the trial jumps to the destination in the paired then column instead of advancing sequentially. Use it for branching, screening, repeat-until-correct loops, and performance gates.
An if without a then on the same row never runs.
Syntax
Section titled “Syntax”Put one condition in the cell, and the place the participant should go to in the paired then cell of the same row. When the trial ends, the condition is checked against the last response; if it is true, the experiment jumps to that destination instead of continuing to the next row.
Several conditions can share one row. Separate them with ; and give then the same number of ;-separated destinations: condition 1 goes with destination 1, condition 2 with destination 2, and so on. The first condition that is true wins.
Within a single condition, & means AND and | means OR, so correct & RT<600 is true only when both hold.
The forms a single condition can take are listed under Options. They are tried in the order shown there, and the first form that fits decides how the condition is read.
Options
Section titled “Options”| Form | Example | Meaning |
|---|---|---|
responseCode= prefix | responseCode=1,2 | True when the response codes recorded for the trial are exactly those, in any order. List several with , |
responseCode!= prefix | responseCode!=1,2 | True when they are not those. List several with ,; a ; would split the cell into separate conditions instead |
| stimX reference | stim2 | True when the clicked or selected position corresponds to that stimulus, even when the stimulus positions were shuffled |
correct | correct | Last trial scored correct |
incorrect | incorrect | Last trial scored incorrect |
has(x) / !has(x) | has(yes) | True when the response contains (or does not contain) that text; with the responseCode prefix it tests the response codes instead |
%var% variables | %correct.sum[2_0]%>=10, %rt-2%<500, %response[lab1]%==1 | The variable is replaced by its recorded value and compared as a number; the rest of the condition is taken exactly as written |
old-style variables (no %) | response[-1]==1 | The same replacement in the older spelling. Always use ==; a single = breaks the experiment when it starts |
| participant details | %age%>=18 | Compares against a stored participant detail. Available keys: id, age, gender, sex_assigned_at_birth, education, handedness, sexual orientation, ethnicity, nationality, participant_other1_label..participant_other5_label |
bare [label] | response[lab1] | Reads the value recorded on the row carrying that label |
!value | !3 | True when the response is not that value. Only numeric values negate correctly |
<= >= < > | RT<500 | Numeric comparison. It compares the reaction time when the condition mentions RT, the response codes when it mentions responseCode, and otherwise the response |
range A_B | 1_5, RT100_500 | True when the value falls between the two bounds, inclusive. Not read as a range when the condition contains x, which is reserved for grid positions |
| plain value (fallback) | yes, a | True when the response is exactly that value |
| unreadable | ??? | A condition that cannot be read at all is always true |
Variable syntax accepted inside %...%: base response|responseCode|rt|correct|%custom_var%, optional relative index (%response-2%), optional aggregate .avg|.mean|.sum|.max|.min|.modal|.perc|.count, optional bracket index [N], [a,b,c], [from_to], or [label] — the bracket index goes after the aggregate (%correct.perc[2_0]%; %correct[2_0].perc% is not recognised). Indexes of 0 or less are relative to the most recent value ([0] is the last one, [-1] the one before it), positive indexes are trial-file row numbers (header row = 1, so first trial = [2]), _ makes an inclusive range, , picks individual values, and a label resolves to that labeled row’s value.
Defaults & missing values
Section titled “Defaults & missing values”Leave the cell empty on every row that should simply carry on to the next trial. The column can be left out of the file entirely if no trial branches.
- Cell empty but
thenfilled in: the firstthendestination is taken every time, with nothing to check. - Cell filled in but
thenleft empty: nothing happens, because the conditions are never checked. - More conditions than
thendestinations: the extra conditions have nowhere to go, so when one of them matches the participant simply continues with the next trial.
Works with
Section titled “Works with”- then: conditions and destinations pair up in order. See the
thenpage for what a destination can be. - key:
keyscoring uses the same condition grammar, so anything you learn here also applies to writing scoring rules. - label:
%response[mylabel]%reads the response recorded on a labeled row, andthendestinations can be labels instead of row numbers. - Break trials: a break row’s conditions are checked when the break ends.
- Setup screens: consent, calibration and participant-details screens never branch. A condition only takes effect after a regular trial; test and form trials branch normally.
Examples
Section titled “Examples”Repeat a practice block until 80% accuracy (row numbers include the header row):
| type | stimFormat | stim1 | key | if | then | label |
|---|---|---|---|---|---|---|
| practice | .png | dog | 1 | practice_start | ||
| practice | .png | cat | 2 | %correct.perc[-1_0]%>=80;%correct.perc[-1_0]%<80 | 4;practice_start | |
| test | .png | bird | 1 |
type,stimFormat,stim1,key,if,then,label practice,.png,dog,1,,,practice_start practice,.png,cat,2,"%correct.perc[-1_0]%>=80;%correct.perc[-1_0]%<80","4;practice_start", test,.png,bird,1,,,
([-1_0] = the last two responses, i.e. this practice block; 4 = the trial-file row of the first test trial.)
Branch on the response with a fallback destination (the extra then acts as else):
| type | trialText | keyboard | if | then | label |
|---|---|---|---|---|---|
| test | Do you smoke? (y/n) | y n | y | smoker_q;main_start | |
| test | How many per day? | 0 1 2 3 | smoker_q | ||
| test | x.png | main_start |
type,trialText,keyboard,if,then,label test,Do you smoke? (y/n),y n,y,smoker_q;main_start, test,How many per day?,0 1 2 3,,,smoker_q test,x.png,,,,main_start
Fast-and-correct gate combining AND:
| type | stimFormat | stim1 | key | if | then |
|---|---|---|---|---|---|
| test | .png | target | 1 | correct & RT<600 | +2 |
type,stimFormat,stim1,key,if,then test,.png,target,1,correct & RT<600,+2
Tips & gotchas
Section titled “Tips & gotchas”!negation only works on numbers:!yesdoes not test the textyes, it tests “not 0”.- There are no parentheses: in a mixed condition every
&binds tighter than every|, not left to right. - A condition that cannot be read at all is always true, but an unreadable part inside an
&or|combination is worse: the experiment fails to start rather than failing quietly. - Aggregates need a bracket index: a bare
%correct.perc%or%correct.sum%is never filled in, so the condition is silently false. Always write an index or a range, for example%correct.perc[2_0]%,%correct.perc[-9_0]%, or a labeled range. - Which value gets compared is decided by the text of the condition, case-sensitively. Any condition containing uppercase
RTcompares the reaction time, which can surprise you if a response value itself contains “RT”; lowercasert<500compares the response instead.
Common combinations
Section titled “Common combinations”if appears in these worked recipes:
- Skip on response: Ask one question and jump participants who answer yes straight past the practice block.
- Accuracy-gated progression: Let participants advance to the test block only once their practice accuracy clears a threshold.
- Branching questionnaire: Route participants to different questionnaire pages depending on their answer to an earlier question.
- Screener then branch: Ask one eligibility question up front and end the session for participants who do not qualify.