When and Why to Use
Use this to run a CBC study where each respondent picks one option from a small set of competing product concepts across a sequence of tasks. Ideal for:
- Measuring how attribute levels (brand, price, feature, packaging) drive choice
- Estimating individual-level utility scores via Hierarchical Bayes
- Comparing attribute importance and, with purchase follow-ups, marginal purchase lift
For background on the method, see Choice-Based Conjoint. For the model that produces utility scores and simulated share, see Utility and simulated share methodology.
How Task Sets Work
task_sets is a mapping of task-set id to an ordered list of tasks, where each task is a list of concept ids. Each respondent is assigned one task set using least-fill balancing, which keeps per-task-set exposure roughly even across the fielding. Each task in the assigned set is then presented as a structured comparison with one concept choice.
The simplest way to generate balanced concepts and task sets is the Conjoint Analysis Design Tool, which produces a code block you can paste straight into the survey alongside your screener.
Dict-Backed vs Media-Backed Concepts
Concepts can be defined in two shapes:
- Dict-backed concepts — Python dicts whose
concept_id_tagkey (defaultid) identifies the concept; attributes are displayed as ordered comparison rows.required_tagssets the displayed row order and identifies the fields required on every concept and retained for reporting. - Media-backed concepts —
MediaItemobjects rendered using the same labels, sizing, and media tags as other media-bearing questions. Useimage_label_field,show_image_label, andimage_sizeto configure rendering.
Configuration Options
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
question | str | yes | - | The question to ask for each conjoint task |
concepts | list[dict] or list[MediaItem] | yes | - | Concept dictionaries or media items to use in tasks |
task_sets | dict[str, list[list[str]]] | yes | - | Mapping of task-set id to tasks, where each task contains concept ids |
concept_id_tag | str | no | 'id' | Tag containing the concept id referenced by task_sets |
required_tags | list[str] or None | no | None | Concept tags to require and report with selected dict-backed concepts |
dont_know_option | str | no | '' | Optional uncertainty choice, separate from explicit none |
randomize | bool | no | False | Randomize option order within each task |
image_label_field | str or None | no | None | Media field to use as the display label for media concepts |
show_image_label | bool | no | True | Whether to show media labels |
image_size | tuple[int, int] or None | no | None | Bounding box size for media options |
number_seconds | int | no | 0 | Seconds to wait before allowing the respondent to continue |
tags | dict[str, Any] or None | no | None | Tags attached to each conjoint task question |
id | str or None | no | None | Optional stable identifier for this question |
none_option | str | no | '' | Completed no-purchase choice beneath the concepts; cannot be combined with anchor_question |
anchor_question | str or None | no | None | Yes/no purchase follow-up after each concept choice; supports {selected.field} piping |
anchor_labels | dict or None | no | None | Display labels with exactly the keys yes and no |
Respondent comparison
On a wide screen, concepts appear side by side with matching attribute rows. The None of these choice sits beneath the concepts when none_option is configured.

On mobile, the concepts stack vertically while retaining each attribute label and the separate None of these choice.

None, Don't Know, and Purchase Follow-ups
Choose the behavior that matches your study:
- Set
none_option="None of these"for an explicit no-purchase alternative beneath the concepts. - Set
anchor_questionto ask whether the respondent would buy the concept they just selected. The platform asks and saves a separate yes/no follow-up after every concept choice. - Use
dont_know_option="Don't know"only for uncertainty. It is separate from a completed no-purchase choice and skips the purchase follow-up.
Explicit none and purchase follow-ups are mutually exclusive. For a purchase follow-up, omit none_option and pass these arguments in your s.conjoint_question(...) call:
anchor_question="Would you buy {selected.brand} for {selected.price}?",
anchor_labels={"yes": "Yes, I would buy it", "no": "No, I would not"},
{selected.price} and other {selected.field} placeholders insert values from the selected concept dictionary or media tags. Every concept must contain the referenced field. Bare {selected} inserts the concept ID. Do not use a Python f-string: the platform substitutes these values when the respondent chooses a concept.
The answer applies to that choice in that task, even if the same concept appears again. Answering No preserves the forced concept choice and records a negative purchase follow-up; it does not turn the response into Don't know.
The follow-up can also use a simple prompt without placeholders, as in this example:

Example Code
Dict-backed concepts:
from survey import Survey
s = Survey(**globals())
concepts = [
{"id": "A", "brand": "Apple", "color": "Black", "network": "5G", "price": "$800"},
{"id": "B", "brand": "Apple", "color": "Blue", "network": "5G", "price": "$1000"},
{"id": "C", "brand": "Samsung", "color": "Black", "network": "4G", "price": "$600"},
{"id": "D", "brand": "Samsung", "color": "Silver", "network": "5G", "price": "$800"},
]
task_sets = {
"TS001": [["A", "C"], ["B", "D"], ["A", "D"], ["B", "C"]],
"TS002": [["A", "B"], ["C", "D"], ["A", "C"], ["B", "D"]],
}
s.conjoint_question(
question="Which product would you choose?",
concepts=concepts,
task_sets=task_sets,
required_tags=["brand", "color", "network", "price"],
none_option="None of these",
randomize=True,
tags={"study": "smartphone_cbc"},
)
s.complete()
Notes
- Each task response includes the selected concept and its reporting attributes.
- If
dont_know_optionis selected, it is treated as a fixed non-concept option (no concept tags are attached). - The Conjoint Analysis Design Tool produces both the
conceptsandtask_setsstructures; paste its output directly into the survey instead of writing them by hand. - See Choice-Based Conjoint for end-to-end study design and Utility and simulated share methodology for the reporting outputs.
Reporting conjoint results
The automatic Conjoint Analytics report starts with Part Worth Scores, an uncalibrated measure of relative preference for the tested attribute levels. Attribute Importance (%) summarizes each attribute's share of the total utility range. Neither requires an anchor, and neither is an absolute purchase-probability measure.
When the study includes None of these choices or yes/no purchase follow-ups, the available calculations also include Anchored Part Worth Scores and Anchored Attribute Importance (%). They use the calibrated model; keep them distinct from the uncalibrated versions when comparing or describing results.
Purchase Lift Analytics uses Marginal Purchase Lift and requires yes/no purchase-follow-up data. An explicit-none choice alone does not supply it. Marginal Purchase Lift describes a modeled change in purchase probability for an attribute level; it is separate from the Lift report that compares a target group with matched controls.
To change calculations, open the report's Edit dialog. Select the conjoint analytical question in Scope → Questions, then use Analysis → Questions → Calculation. Select multiple calculations when you need to compare them, and choose Cut by questions for demographic comparisons. The editor offers the calculations supported by the question and its data.
See Question aggregation types for the full calculation catalog. Attribute importance depends on the attribute levels and ranges tested, so comparisons between different designs need care.

