> ## Documentation Index
> Fetch the complete documentation index at: https://docs.expectedparrot.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Humanize

> EDSL comes with built-in methods for generating web versions of your surveys and collecting and analyzing responses from humans.

<Note>
  This page covers code methods for launching surveys, gathering human responses, and analyzing results. For interactive survey building, see [Survey Builder](/en/latest/survey_builder). For Prolific recruitment, see [Prolific studies](/en/latest/prolific). For email notifications and scheduled reminders, see [Survey notifications](/en/latest/humanize_notifications).
</Note>

## How it works

<Steps>
  <Step>
    **Create** [Surveys](/en/latest/surveys) with desired types of [Questions](/en/latest/questions).
  </Step>

  <Step>
    **Humanize** the survey to generate a web-hosted version on Expected Parrot with a respondent link and an admin dashboard.
  </Step>

  <Step>
    **Share** the respondent link with human participants (or recruit via [Prolific](/en/latest/prolific)).
  </Step>

  <Step>
    **Collect** responses back as a standard EDSL `Results` object.
  </Step>

  <Step>
    **Analyze** your human results alongside any LLM results.
  </Step>
</Steps>

***

## Basic usage

```python theme={null}
from edsl import Survey, QuestionMultipleChoice, QuestionFreeText, QuestionLinearScale

q1 = QuestionMultipleChoice(
    question_name="frequency",
    question_text="How often do you work from home?",
    question_options=["Never", "1-2 days a week", "3-4 days a week", "Every day"],
)
q2 = QuestionLinearScale(
    question_name="satisfaction",
    question_text="How satisfied are you with your current work arrangement?",
    question_options=[1, 2, 3, 4, 5],
    option_labels={1: "Very dissatisfied", 5: "Very satisfied"},
)
q3 = QuestionFreeText(
    question_name="improvement",
    question_text="What one change would most improve your day-to-day work experience?",
)

survey = Survey([q1, q2, q3])

info = survey.humanize(
    human_survey_name="Workplace Experience Survey",
    survey_description="A short survey about remote and in-office work preferences.",
    survey_visibility="unlisted",
)

print(info["respondent_url"])  # share with respondents
print(info["admin_url"])       # monitor responses
print(info["uuid"])            # save this to retrieve results later
```

### `.humanize()` parameters

| Parameter            | Type                | Default        | Description                                                                                   |
| -------------------- | ------------------- | -------------- | --------------------------------------------------------------------------------------------- |
| `human_survey_name`  | str                 | `"New survey"` | Display name on Coop                                                                          |
| `survey_description` | str \| None         | None           | Optional description                                                                          |
| `survey_alias`       | str \| None         | None           | URL-friendly alias                                                                            |
| `survey_visibility`  | str                 | `"private"`    | `"private"`, `"public"`, or `"unlisted"`                                                      |
| `humanize_schema`    | dict \| None        | None           | Controls question styling and optionality — see [Humanize schema](/en/latest/humanize_schema) |
| `delivery_map`       | DeliveryMap \| None | None           | Maps delivery channels to agent trait columns; required for email notifications               |

### Return value

`survey.humanize()` returns a `Scenario` (dict-like) with these keys:

| Key                  | Description                                         |
| -------------------- | --------------------------------------------------- |
| `uuid`               | Human survey UUID — needed to fetch responses later |
| `respondent_url`     | Public link for respondents                         |
| `admin_url`          | Admin dashboard link                                |
| `name`               | Survey name                                         |
| `n_responses`        | Response count (0 at creation)                      |
| `survey_uuid`        | UUID of the pushed survey object                    |
| `scenario_list_uuid` | UUID of the pushed scenario list (if any)           |

**Save the `uuid`** — you need it to retrieve responses.

***

## Previewing before deployment

Use `.preview()` to get a preview URL without creating a live survey:

```python theme={null}
preview_url = survey.preview()
print(preview_url)

# With schema customization
preview_url = survey.preview(humanize_schema=schema)
```

***

## With scenarios

When using scenarios, call `.humanize()` on a `Jobs` object (not directly on the survey). You must specify a `scenario_list_method`.

This example shows each respondent a different policy description and asks for their reaction:

```python theme={null}
from edsl import Survey, QuestionFreeText, QuestionLinearScale, Scenario, ScenarioList

scenarios = ScenarioList([
    Scenario({"policy": "Four-day workweek with no change in pay"}),
    Scenario({"policy": "Flexible start times between 7am and 11am"}),
    Scenario({"policy": "Monthly remote-work stipend of $100"}),
])

q1 = QuestionLinearScale(
    question_name="support",
    question_text="How much do you support this policy: '{{ scenario.policy }}'?",
    question_options=[1, 2, 3, 4, 5],
    option_labels={1: "Strongly oppose", 5: "Strongly support"},
)
q2 = QuestionFreeText(
    question_name="reasoning",
    question_text="What is the main reason for your rating?",
)

survey = Survey([q1, q2])

info = survey.by(scenarios).humanize(
    human_survey_name="Workplace Policy Reactions",
    scenario_list_method="randomize",
)
```

### Scenario list methods

| Method              | Behavior                                                                   |
| ------------------- | -------------------------------------------------------------------------- |
| `"randomize"`       | Each respondent gets a random scenario (with replacement)                  |
| `"ordered"`         | Scenarios are assigned sequentially to respondents                         |
| `"loop"`            | Survey is expanded — every question is repeated for every scenario         |
| `"single_scenario"` | Exactly one scenario is used for all respondents (list must have length 1) |

**Rules:**

* If you attach scenarios, you **must** specify `scenario_list_method`.
* If you specify a method, you **must** attach scenarios.
* Agents and models are **not supported** with humanize — the survey goes to real humans.

***

## With agent lists (for email notifications)

Attach an `AgentList` via `.by()` to associate respondents with email addresses. Pass a `DeliveryMap` to tell Coop which agent trait holds the email address.

```python theme={null}
from edsl import Survey, Agent, AgentList
from edsl.coop.coop_humanize_notifications import ChannelConfig, DeliveryMap

agents = AgentList([
    Agent(traits={"name": "Jordan", "email": "jordan@example.com"}),
    Agent(traits={"name": "Taylor", "email": "taylor@example.com"}),
    Agent(traits={"name": "Morgan", "email": "morgan@example.com"}),
])

info = survey.by(agents).humanize(
    human_survey_name="Panel Study — Wave 1",
    agent_list_description="Recruited panel participants",
    delivery_map=DeliveryMap(email=ChannelConfig(col_name="email")),
)
```

`col_name` must match the trait key that holds each respondent's email address. Once deployed, use [Survey notifications](/en/latest/humanize_notifications) to send invitations, schedule reminders, and track delivery status.

***

## Retrieving responses

```python theme={null}
from edsl import Coop

coop = Coop()

results = coop.get_human_survey_responses("your-human-survey-uuid")
results.select("answer.frequency", "answer.satisfaction", "answer.improvement").print()
```

### Checking response count

```python theme={null}
status = coop.get_human_survey("your-human-survey-uuid")
print(f"Responses received: {status['n_responses']}")
```

### Working with file upload responses

If your survey includes a `QuestionFileUpload` question, each response's answer for that question is a list of file-info dicts. Use `FileStore.from_file_upload_answer` (single file) or `FileStoreList.from_file_upload_answers` (all files at once) to download and wrap them:

```python theme={null}
from edsl import Coop
from edsl.scenarios import FileStore, FileStoreList

coop = Coop()

results = coop.get_human_survey_responses("your-human-survey-uuid")

# Each answer is a list of uploaded file dicts
uploaded_files = results[0]["answer"]["my_upload_question"]

# Download all files as a FileStoreList
fsl = FileStoreList.from_file_upload_answers(uploaded_files)

# Or download a single file
fs = FileStore.from_file_upload_answer(uploaded_files[0])
```

The returned `FileStore` and `FileStoreList` objects behave like any other — you can inspect, filter, or pass them into further EDSL workflows.

***

## QR code

Generate a QR code for the respondent link using `get_human_survey_qr_code()`. Requires the `qrcode` library (`pip install "edsl[full]"` or `pip install "qrcode[pil]"`).

```python theme={null}
from edsl import Coop

coop = Coop()

qr = coop.get_human_survey_qr_code("your-human-survey-uuid")
qr.save("qr_code.png")  # save to file
```

***

## Prolific integration

For paid recruitment via Prolific, see the [Prolific studies](/en/latest/prolific) page. The short version:

```python theme={null}
from edsl import Coop

coop = Coop()

info = survey.humanize(human_survey_name="Workplace Experience Survey")

study = coop.create_prolific_study(
    human_survey_uuid=info["uuid"],
    name="Workplace Experience Study",
    description="A short survey about remote and in-office work preferences. Takes about 3 minutes.",
    num_participants=200,
    estimated_completion_time_minutes=3,
    participant_payment_cents=75,
)

# create_prolific_study leaves the study in DRAFT mode — publish to make it live
coop.publish_prolific_study(human_survey_uuid=info["uuid"])
```
