LUIDA Docs

Within-subjects vs between-subjects variables

The factorial design of an experiment, with the Stroop task as a worked example.

LUIDA's variable system is built around one distinction from experimental design: within-subjects versus between-subjects variables. If you're not sure when to use which, start here. The rest of the system — trial counts, condition maps, condition balancing — follows from this choice.

The two kinds, in one paragraph each

A within-subjects variable has values that every participant sees, in some order. If your variable is "stimulus color: red or blue," every participant does some red trials and some blue trials. Within-subjects variables are economical (every participant generates data for every cell) and they remove between-participant variance, but they introduce concerns about order effects and fatigue.

A between-subjects variable has values that each participant sees only one of. If your variable is "headset condition: HMD or no-HMD," each participant is assigned to one or the other. Between-subjects variables avoid order effects entirely but require more participants to get the same statistical power, and they introduce concerns about between-group comparability.

Why LUIDA cares

The distinction maps directly onto two things LUIDA does for you:

ConcernWithin-subjectsBetween-subjects
Trial schedulingLUIDA cycles through every combination of within-subjects values, repeating for the trial count you set. The order is shuffled per random factor.LUIDA picks one value per participant when their session starts. They never see the others.
Condition balancingNot applicable — every participant sees every cell.LUIDA balances assignments across previous sessions so the cells fill up roughly evenly, even if participants drop out.
CONDITION at runtimeThe value swaps each trial.The value is fixed for the entire session.

The Stroop example

LUIDA's Tutorial 2 builds a Stroop-effect experiment. The variables are:

within-subjects:
  responseTarget: ["color", "meaning"]   (random)
  fontColor:       ["red", "blue"]        (random)
  textMeaning:     ["RED", "BLUE"]        (random)

between-subjects:
  depth: ["near", "far"]

trialsCountPerCondition: 2

How LUIDA reads this:

  • Within-subjects combinations: 2 (responseTarget) × 2 (fontColor) × 2 (textMeaning) = 8 unique within-subjects cells.
  • Each cell is repeated trialsCountPerCondition = 2 times → 16 trials total per participant.
  • Order: shuffled, because all three within-subjects variables are marked random=true. (If you'd set random=false, trials would run in the variable-listing order.)
  • Between-subjects: each participant is assigned either depth=near or depth=far for their entire session. They will run all 16 within-subjects trials at one fixed depth.

So for a participant assigned depth=near, the experiment runs 16 trials. Each trial sees a unique (responseTarget, fontColor, textMeaning) combo, repeated twice across the run. That participant never experiences depth=far.

How CONDITION reflects this at runtime

Inside any state-listening action or Data Collector script, the global CONDITION object exposes the current values:

// During Trial 5 of a near-depth participant:
CONDITION["responseTarget"]  // "color"
CONDITION["fontColor"]       // "blue"
CONDITION["textMeaning"]     // "RED"
CONDITION["depth"]           // "near" (same for all 16 trials)

The within-subjects values change at the boundary between Trial - Rest and the next Trial - Start. The between-subjects value is set at session start and never changes during the session.

How to choose between within- and between-

Use within-subjects when:

  • You can plausibly expose every participant to every cell without contamination.
  • Your DV is a per-trial measurement (reaction time, accuracy, judgment).
  • You want more statistical power per recruited participant.
  • Order effects are manageable (you can shuffle, or counterbalance the few orderings).

Use between-subjects when:

  • The conditions involve persistent state that can't be undone within a participant. ("Was given a $5 reward up front" vs "given $0 up front" — the prior monetary frame can't be reset.)
  • The manipulation is identity-laden. (Different avatars, different roles, different stories about what the experiment is.)
  • A within-subjects design would expose participants to demand characteristics — they'd guess your hypothesis if they saw both conditions.
  • The DV is a per-session measurement (one questionnaire score, one final choice).

The choice can be tricky. Pre-register if you're not sure — LUIDA doesn't help you with that part.

Random vs ordered

Both within- and between-subjects variables have a random flag in the editor. What it means depends on the variable type:

  • Within-subjects, random=true: trial order is shuffled per participant. Each participant sees a different sequence.
  • Within-subjects, random=false: every participant sees the same fixed order — the variable's listed values, in listing order, then repeating.
  • Between-subjects, random=true (currently the only supported value): the assignment is balanced across prior sessions for that experiment. LUIDA queries the Web Console for what previous participants got and assigns the least-filled cell, with random tie-breaking.

If you genuinely want a fixed within-subjects order — for example, the practice trial always comes first — model that as a separate state in the state machine, not as a variable value.

What about counterbalancing?

LUIDA does not currently provide automatic counterbalancing of within-subjects orders (e.g., Latin-square designs). With isRandom=true on within-subjects variables, every participant gets a different shuffle — for most designs this is sufficient; for designs sensitive to order this is not, and there is no v1 workaround on the LUIDA side. If your design requires strict counterbalancing today, the practical option is to recruit in waves and assign sequences out-of-band (e.g., use a between-subjects variable to encode which fixed order the session should follow, then enforce the participant-to-order mapping outside LUIDA).

Counterbalancing isn't a v1 feature, but it's on the roadmap.

Where to go next