Welcome to the LimeSurvey Community Forum

Ask the community, share ideas, and connect with other LimeSurvey users!

Modern Conjoint Experiment with Per-Respondent Profile Randomization

More
9 hours 14 minutes ago - 8 hours 9 minutes ago #273599 by baristurkdogan
Please help us help you and fill where relevant:
LimeSurvey version: 6.16.4
Own server or LimeSurvey Cloud: LimeSurvey Cloud
Survey theme/template: fruity_twentythree

==================
Hello Dear Community, 

Goal & Context
I'm trying to build a conjoint analysis / discrete choice survey for a social science experiment, where I'd like to measure preferences for student scholarship recipients.The survey needs to:
  • Present 10 sequential choice tasks
  • Each task shows 2 student profiles side-by-side in a table
  • Respondents select which profile they prefer
  • Each respondent sees different random profiles (full per-respondent randomization)
    • BUT Name Restriction: EITHER no profile with the same name appears more than once per respondent OR the profile with the same name appears with the same attribute levels if they appear more than once per respondent (whichever is more feasible)
  • Radio buttons embedded in the table cells for selection
 This is a modern conjoint design based on the seminal "Causal Inference in Conjoint Analysis: Understanding Multidimensional Choices via Stated Preference Experiments" article by Hainmueller et al. (2014) where I need independent randomization of attribute levels across respondents, not just fixed profile sets repeated for all respondents.
 ---
Profile Attributes & Levels: 5 attributes in total
Attribute: Levels // (Notes) 
1. Name: Leon Schmidt, Lukas Müller, Jan Fischer, Paul Wagner, Jannik Weber, Tom Becker, Jonas Meyer, Emil Lehmann, Niklas Scholz, Luca Hartmann, Arda Yılmaz, Emre Kaya, Can Demir, Baran Şimşek, Deniz Güneş, Mehmet Öztürk, Kaan Kılıç, Efe Kaplan, Ömer Çalışkan, Ali Yıldız // (10 German-sounding and 10 Turkish-sounding names, 20 names in total)  
2. Field of Study: Mechanical Engineering, Law, Psychology, Business Administration // (4 fields) 
3. Grade (GPA): 1.3 (Very Good), 2.0 (Good), 2.7 (Satisfactory) // (3 grades according to the German grading scale)
4. Extracurricular Activity: Student Parliament, Sports Club, Music Tutor, Food Bank Volunteer // (4 activities) 
5. Semester: 3rd semester (Bachelor), 5th semester (Bachelor), 3rd semester (Master) // (3 semesters) 

Design: Profiles are factorially designed combinations of all attributes (~2,880 unique profiles generated from these attribute levels). BUT the NAME RESTRICTION should be applied.

 --- Desired Table Display -> Should look something like the CAR example (see attached below) in Tutorial_Gimmicks Chapter 11  (second image in the chapter) but I couldn't somehow replicate it. ---

Key Challenges I've Encountered 
1. Per-Respondent Randomization
- Problem: I initially created 10 fixed HTML files with hardcoded profile pairs (run once, same for all respondents)
- Why It Failed for Conjoint: This violates the core principle of conjoint analysis—attribute levels need to vary independently across respondents so I can isolate individual attribute effects
- What I Need: Each respondent should see 10 different random profile pairs (profiles A and B drawn randomly from the pool of 2,880, applying the name restriction) 

2. Radio Button Placement in Table Cells
- Problem: Attempted to use "Tutorial_Gimmicks Chapter 11" method (JavaScript DOM manipulation) to move radio buttons into table cells
- Why It Failed: LimeSurvey 6.x appears to have security restrictions or structural issues that prevent reliable DOM access to radio button elements
- What I Need: Radio buttons should be clickable and positioned directly in the bottom row of the profile table (appear as if they're part of the table layout) 

3. JavaScript Execution in LimeSurvey 6.x
- Problem: JavaScript in question text (Source Mode) sometimes fails silently—no console errors, but functionality doesn't execute
- What I Need: Either a working JavaScript solution OR an alternative approach (e.g., custom question type, plugin, or alternative rendering method) 

--- 

Attempts Made (For Context)
I've tried:
1. ✗ JavaScript in question HTML with `document.addEventListener()` and `setTimeout()` to move LimeSurvey's auto-generated radio buttons
2. ✗ Static hardcoded profile pairs (worked visually, but not true conjoint randomization)
3. ✗ Embedding `<input type="radio">` elements directly in HTML and using JavaScript to trigger LimeSurvey's answer recording 

---


***QUESTIONS*** 

1. Randomization: What's the best approach to achieve per-respondent random profile selection in LimeSurvey 6.x?   
- Should profiles be stored in a hidden field or database?   
- Can LimeSurvey expressions or tokens generate random indices?   
- Is there a plugin or extension for this? 

2. Radio Button Placement: How can I reliably embed/position radio buttons inside table cells while maintaining LimeSurvey's answer recording?   
- Does the Chapter 11 method work in LimeSurvey 6.x, or has it changed?   
- Are there CSS-only solutions to reposition the radio buttons?   
- Should I use a custom question type? 

3. Alternative Approaches: If JavaScript/DOM manipulation isn't reliable, are there other ways to build a conjoint interface in LimeSurvey?   
- Custom question type development?   
- Integration with external JavaScript libraries?   
- Database-driven dynamic content? 

--- 

Any guidance on how to properly implement a modern conjoint analysis with full randomization and proper table layout in LimeSurvey 6.x would be greatly appreciated. Happy to provide more details, sample files, or clarifications.Thanks in advance!
Last edit: 8 hours 9 minutes ago by baristurkdogan. Reason: display issues

Please Log in to join the conversation.

More
7 hours 58 minutes ago - 7 hours 18 minutes ago #273604 by Joffm
Hi,
Some remarks.

Obviously you didn't use the "green apple - banana" example that is show here many times.
I admit your shown image uses this approach.

Now some answers.

Each respondent should see 10 different random profile pairs (profiles A and B drawn randomly from the pool of 2,880, applying the name restriction)

So thew profiles are there already and are not generated during the survey.
That's not to difficult with some ExpressionScript.

Should profiles be stored in a hidden field or database?

Depends, hidden field is easier, but you should show more details about it.
Database? Hm, I see, you use a Cloud version. Don't know if an ajax call is possible. But you could parse a csv file (Buzzword "Papaparse").

Conclusion:
You don't need more than
  • the layout with embedded radio buttons
  • the selection of 10x2 profiles out of 2880
Now it's your turn.

Send an example of some of the profiles (to get a feeling about the number of characters per profile) 
and the lss export of your survey (only this part)

Some examples (you are absolutely free how to create the table)
1. A question design without any javascript only built in features
 
2. Some kind of the mentioned "green apple - banana" example (to show that the buttons can be inserted anywhere)
 
The main part is to create the HTML table.
Then some lines of javascript to move the buttons and 
Code:
<script type="text/javascript" charset="utf-8">
  $(document).on('ready pjax:scriptcomplete',function(){
 
    // Identify this question
    var thisQuestion = $('#question{QID}');
 
    // Move the radios
    $('.question-text table:eq(0) tr:eq(3) td:eq(1)', thisQuestion).prepend($('.subquestion-list .answers-list:eq(0) .answer-item:eq(0) *', thisQuestion));
    $('.question-text table:eq(0) tr:eq(3) td:eq(2)', thisQuestion).prepend($('.subquestion-list .answers-list:eq(0) .answer-item:eq(1) *', thisQuestion));
// and so on
 
    // Some classes for presentation
    $('.question-text table:eq(0) input:radio', thisQuestion).closest('td').addClass('answer-item radio-item text-center radio');
    $('.question-text table:eq(0) .radio-item label', thisQuestion).show();
    // Click event on the table cells
    $('.question-text table:eq(0) .radio-item', thisQuestion).on('click', function(e) {
      $('input:radio', this).trigger('click');
    });
    $('.question-text table:eq(0) input:radio', thisQuestion).on('click', function(e) {
      e.stopPropagation();
    });
 
// Followed by some cleaning


Joffm

P.S. Da Du ja offensichtlich mein deutsches Tutorial gelesen hast, hättest Du besser auch im deutschen Teil Fragen dazu gestellt.
Und hättest auch die dort befindliche Beispieldatei herunterladen und installieren können. Das hätte viele Fragen beantwortet.
Warum muss ich immer ohne Not Englisch schreiben?

 

Volunteers are not paid.
Not because they are worthless, but because they are priceless
Last edit: 7 hours 18 minutes ago by Joffm.

Please Log in to join the conversation.

More
4 hours 12 minutes ago #273608 by baristurkdogan
Hello again Jofm, 

Thanks for the guidance! I'm preparing to implement your solution.

Please see attached:
1. Sample profiles (first 5 rows + header) - shows format and ~150 characters per profile
2. LSG export of my ConjointTasks group (currently just a hidden field placeholder)

How would you suggest I proceed?

Thanks again!

P.S. I'm just an international student studying in Germany, I don't speak German. You cited your Tutorials so many times here that I decided to auto-translate them   Falls es Ihnen auf Deutsch leichter fällt, kann ich den Forumtext auch automatisch übersetzen, so wie ich es hier getan habe. Kein Problem.

Please Log in to join the conversation.

More
1 hour 59 minutes ago #273610 by Joffm
Hi,
in the meantime I thought about the selection.
You only need (or better, what I used):
1. A pool - a question of type long text.
In the default answers all 144 possible combinations of your attributes with a autoincrement number, like
001:1111
002:1112
003:1113
004:1121
...
142:4341
143:4342
144:4343

2. A question of type multiple short text. Here we do the randomisation by javascript
a. Names: create an array of numbers '01','02',...'19','20' representing the 29 names. You could use characters 'A', 'B', 'C',... as well.
Shuffle this array
b. Profiles: create an array of numbers '001','002',...'143','144' representing the profiles.
Shuffle this array and use the first 20 elements.
You will get something like this


3. I like to use an array(text) (6 rows, 2 columns) as container for intermediate results. This way you save questions.

4. Equations to grab the values from the "pool", (functions "strpos", "substr")
to "translate" the numbers to the text

Finally you get this array
 
which you use to pipe the text into the tables of the 10 questions

Now it is only necessary to copy the equations and adapt the "substr" indices.

I will send an example of this my idea tomorrow.

Joffm

P.S.
Neither send lsq nor lsg exports; only lss.


 

Volunteers are not paid.
Not because they are worthless, but because they are priceless

Please Log in to join the conversation.

Moderators: tpartnerholch

Lime-years ahead

Online-surveys for every purse and purpose