Skip to main content
A Survey is your research instrument: it groups questions and defines their order, branching, and dependencies. It can collect a rating and explanation, apply several codes to a document, or guide a longer interview. The survey holds the questions and rules; completed answers belong to a Results object. You can reuse the same survey with different scenarios, agent profiles, or models, or publish it for human participants. These choices determine who answers and what material they see without requiring you to rewrite the instrument. To transform a survey into structured population-level response estimates, see Meta-surveys. This converts supported question types, preserves simple skip conditions in the generated prompts, and optionally uses a fixed theme codebook for free-text items. For data labeling, a survey might ask about each item’s topic, sentiment, and urgency; the answers become its labels. An exploratory survey can also help you discover useful categories before you construct a structured labeling survey.

Assemble questions

Construct questions before passing them to Survey([...]). Each question must have a unique name. See Questions for choosing types; the survey controls how those questions work together.

Logic, piping, and memory

This example stops after the first question for respondents who have not used a feature. Otherwise, it pipes their description into a follow-up and supplies the earlier answer as memory. Constructing the survey makes no model calls.
A stop rule is evaluated after its question. A skip rule can bypass an individual question before it is asked. Write expressions using named answers, and test each possible route. Piping inserts an answer in question text; memory includes a previous question and answer in the context supplied to the model. See Survey logic and piping for testing routes and Survey messages for instructions shown between questions.

Prepare a run

Combine a survey with scenarios, agents, and models using by() to construct a Jobs object. For example, survey.by(messages).by(model) prepares one interview per message scenario; calling .run() collects the answers. Use survey.run() when you want to ask it once with the default model and no custom profiles or scenarios. See Model access for connecting a model. For human participants, use Human studies. A web survey requires an Expected Parrot account.

Create a visual review survey

Use create_review_survey() when reviewers need to inspect how every question looks before an instrument is fielded. It renders each source question as an HTML card, captures the card as an image, and creates a second survey containing:
  • an optional reviewer-name question;
  • an approval question for every source question; and
  • a conditional text question when the reviewer reports an issue.
The method returns a review Survey and one Scenario containing all screenshots. Keep them together when previewing, running, or publishing the review:
single_scenario is important: the review instrument uses one scenario containing every image, rather than one respondent assignment per source question. The image is included in both the approval and feedback questions so the reviewer retains visual context after selecting the issue option. Automatic screenshots require Playwright and Chromium:
In a build system that captures screenshots separately, pass the paths in source question order. This path does not require Playwright:

Customize the review instrument

The first value in approval_options means approval and causes the associated feedback question to be skipped. The second value means an issue was found. Custom text templates may use {question_name}, {question_number}, and {screenshot}. Always include {screenshot} when the image should be visible.
Use prefixes when combining generated review questions with another survey or when the default names would collide. The generated survey remains an ordinary Survey: you can edit questions, add instructions, change routing, apply a Humanize schema, or run it with agents before asking people to review it. Set reviewer_question_name when identity should be collected under a field name other than reviewer_name.

Edit and inspect a survey

Access a question by name with survey.get("feedback") or survey["feedback"]. Use survey.question_names to inspect the order. To revise wording while keeping the original survey:
with_renamed_question() also updates references to the question. survey.rename({"old_name": "new_name", ...}) renames multiple questions. codebook() returns a dictionary of names and question text. For grouped human survey pages, use survey.add_question_group(start_question, end_question, group_name); get_question_group(question) reports a question’s group. See Question groups for grouping constraints.

Import, save, and reuse

Use the Importing data guide to load data for questions and respondent profiles. Review imported questionnaire text, answer types, and branching before fielding it. See the Builder guide for visual questionnaire import; use the installed CLI’s ep surveys --help for available survey operations. Save a survey as an .ep package and reopen it in another session. See Saving and sharing objects and Survey package format for the basic workflow and format details.

Common methods

Rule and memory methods accept question names or question objects. They return the survey so you can chain calls. For example, this constructs a two-question survey with a stop rule:
For model runs, call run() on the configured job; see Jobs for execution options. For a participant link, follow Human surveys.