For Claude Code agents and AI coding assistants. This guide documents how to create effective research groups for Ditto synthetic research studies. It covers demographic filtering, industry proxy mapping, the over-recruit-and-curate methodology, and every known pitfall from 50+ production studies.
curl -s -X POST "https://app.askditto.io/v1/research-groups/recruit" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "US Adults 28-45 Product Feedback",
"description": "American adults for product concept testing",
"group_size": 10,
"filters": {
"country": "USA",
"age_min": 28,
"age_max": 45
},
"sampling_method": "random",
"deduplicate": true
}'
{
"group": {
"id": 184,
"uuid": "60a157f6620b43f6b0b9dbbe98eb2420",
"name": "US Adults 28-45 Product Feedback",
"agent_count": 10
}
}
uuid value. You need the UUID (not the numeric ID) when creating studies. Using group_id instead of research_group_uuid when creating a study will result in an empty study with no participants.
{
"name": "string (required) - descriptive name for the group",
"description": "string (optional) - what these participants represent",
"group_size": "integer (required, 1-20) - MUST use group_size, NOT size",
"filters": {
"country": "string (required) - USA, UK, Germany, or Canada",
"state": "string (optional) - 2-LETTER CODE ONLY for US states",
"age_min": "integer (optional) - minimum age",
"age_max": "integer (optional) - maximum age",
"gender": "string (optional) - male, female, non_binary",
"is_parent": "boolean (optional) - true or false",
"education": "string (optional) - high_school, bachelors, masters, phd",
"employment": "string (optional) - employed, self_employed, unemployed, retired",
"industry": "array of strings (optional) - industry categories"
},
"sampling_method": "string (optional, default: random)",
"deduplicate": "boolean (optional, default: true)"
}
| Filter | Type | Values | Required | Notes |
|---|---|---|---|---|
country | string | "USA", "UK", "Germany", "Canada" | Yes | Only these 4 countries. See Section 3 for aliases. |
state | string | "TX", "CA", "MI", "NY" | No | 2-LETTER CODES ONLY. Full names return 0 agents. See Section 4. |
age_min | integer | 18, 25, 30 | No | Recommended for all studies. Improves relevance. |
age_max | integer | 45, 55, 65 | No | Recommended for all studies. |
gender | string | "male", "female", "non_binary" | No | Only use when gender is critical to the research (e.g., women's health). |
is_parent | boolean | true, false | No | Useful for family/children/education research. |
education | string | "high_school", "bachelors", "masters", "phd" | No | Use for professional/academic research. |
employment | string | "employed", "self_employed", "unemployed", "retired" | No | Use for B2B research or retirement studies. |
industry | array of strings | See Section 5 | No | For niche audience targeting. See proxy mapping for workarounds. |
income - Not supported. The API rejects it. Use education/employment as proxies.size - Not a filter. Use group_size in the request body.location - Not a filter. Use country + state.city - Not supported. Use state filtering as the most granular geographic option.ethnicity - Not a filter.political_affiliation - Not a filter. Use state + age for political research.Ditto supports 4 countries for research groups. The API accepts multiple name variants:
| Country | Primary Value | Also Accepted |
|---|---|---|
| United States | "USA" | "United States", "US", "U.S.A." |
| United Kingdom | "UK" | "United Kingdom", "Great Britain", "England", "Scotland", "Wales" |
| Germany | "Germany" | (primary only) |
| Canada | "Canada" | (primary only) |
"USA", "UK", "Germany", "Canada") for consistency. The aliases work but the primary values are most reliable.
Ditto covers 15+ countries total representing 65% of global GDP, but these 4 are the most extensively calibrated and available via the API.
"Michigan" returns 0 agents. "MI" returns agents correctly. The API does NOT return an error - it silently returns an empty group.
| State | Correct | Wrong (Returns 0) |
|---|---|---|
| Michigan | "MI" | "Michigan" |
| Texas | "TX" | "Texas" |
| California | "CA" | "California" |
| Pennsylvania | "PA" | "Pennsylvania" |
| New York | "NY" | "New York" |
| Florida | "FL" | "Florida" |
| Ohio | "OH" | "Ohio" |
| Arizona | "AZ" | "Arizona" |
| Wisconsin | "WI" | "Wisconsin" |
| Georgia | "GA" | "Georgia" |
| Nevada | "NV" | "Nevada" |
| New Hampshire | "NH" | "New Hampshire" |
| North Carolina | "NC" | "North Carolina" |
| Minnesota | "MN" | "Minnesota" |
# CORRECT - uses 2-letter code
curl -s -X POST "https://app.askditto.io/v1/research-groups/recruit" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "MI State Voters",
"group_size": 10,
"filters": {
"country": "USA",
"state": "MI",
"age_min": 25,
"age_max": 70
}
}'
# WRONG - full name, will return 0 agents silently
# "state": "Michigan" <-- DO NOT DO THIS
Use the format "{StateCode} State Voters" to enable group reuse:
"MI State Voters""TX State Voters""PA State Voters"Before creating a new state group, check if one already exists:
curl -s "https://app.askditto.io/v1/research-groups" \
-H "Authorization: Bearer YOUR_API_KEY"
Look for groups with names matching the "{StateCode} State Voters" pattern. If one exists and was created with the correct state filter, reuse it.
Ditto's industry filters cover broad categories. When your target audience does not have an exact match, use these validated proxy mappings:
| If You Need... | Use This Industry Filter | Why It Works | Validated In |
|---|---|---|---|
| Auto mechanics / repair shops | "Automotive Manufacturing" |
Includes service advisors, technicians, and parts specialists | MotorMinds study (10 participants) |
| Pet owners | Age 30-60 + USA filter (no industry) | General population screen. Use Q1 to filter: "Do you have a pet?" | VetVivo study (20 participants) |
| Parents of young children | Age 25-40 + is_parent: true |
Direct filter available. Do NOT use "Education" (gets teachers) | Feel Good Games study (20 participants) |
| Healthcare workers | ["Healthcare", "Home Healthcare"] |
Combine both to get wider coverage. "Healthcare" alone may miss home care staff. | PatientCompanion, TimeSmart studies |
| Nurses / elder care staff | "Healthcare" + age 25-55 |
Healthcare filter covers clinical roles. Age range narrows to working staff. | PatientCompanion study (20 participants) |
| Civil engineers | "Civil Engineering" or "Construction" |
"Civil Engineering" is exact match. "Construction" is broader alternative. | Sidian study (10 participants) |
| Construction trades | ["Construction", "Commercial Construction", "Residential Construction"] |
Multiple construction categories cover different specialisations. | (validated via filter testing) |
| Security professionals | "Cybersecurity" |
Exact match. Do NOT use "IT" (too broad, includes helpdesk and sysadmin). | NexRisx study (8 participants) |
| Frequent travellers | Age 25-55 + USA + employment: "employed" |
Working professionals travel most. No "Travel" industry exists. Screen in Q1. | Airfairness study (20 participants) |
| Retail workers | "Grocery Retail" and various retail categories |
Multiple retail categories exist. Check API for current options. | (validated via filter testing) |
| Office workers / knowledge workers | ["Information Services", "Government Administration"] |
Broad categories that capture desk-based professionals. | (validated via filter testing) |
| Logistics / supply chain | ["Freight & Logistics", "Transportation"] |
Combined covers warehouse, transport, and supply chain roles. | (validated via filter testing) |
| Eye care practitioners | "Healthcare" + specific Q1 screen |
No "Optometry" filter. Use Healthcare and screen with: "What is your role in eye care?" | Mandel Diagnostics study (15 participants) |
When exact industry filters do not exist, use broad demographic filters and make Question 1 a relevance screen:
This strategy was used successfully for:
For niche audiences where demographic filters cannot perfectly target the desired participants, use the over-recruit and curate strategy.
Ditto's population is broad. An "Automotive Manufacturing" filter might return a mix of service advisors, assembly line workers, and supply chain managers. For a study about auto parts sourcing, service advisors are ideal, assembly line workers are somewhat relevant, and supply chain managers may not be useful. Over-recruiting lets you select the best participants instead of hoping the random sample is good enough.
# Step 1: Over-recruit (15-20 participants)
curl -s -X POST "https://app.askditto.io/v1/research-groups/recruit" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "MotorMinds - Auto Service Professionals",
"group_size": 15,
"filters": {
"industry": ["Automotive Manufacturing"],
"age_min": 25,
"age_max": 60
}
}'
# Step 2: Review profiles
curl -s "https://app.askditto.io/v1/research-groups/{group_id}" \
-H "Authorization: Bearer YOUR_API_KEY"
# Step 3: Create study (use uuid, not id)
curl -s -X POST "https://app.askditto.io/v1/research-studies" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Auto Parts Sourcing Study",
"objective": "Understand parts sourcing pain points for auto repair shops",
"research_group_uuid": "uuid-from-step-1"
}'
# Step 4: Remove irrelevant agents from the STUDY
curl -s -X POST "https://app.askditto.io/v1/research-studies/{study_id}/agents/remove" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agent_ids": [irrelevant_id_1, irrelevant_id_2, irrelevant_id_3]}'
# Step 5: Now ask questions to the curated group
When reviewing participant profiles after over-recruiting, score each persona using this framework:
| Score | Level | Criteria | Action |
|---|---|---|---|
| 10 | High | Job title directly matches target. Summary confirms relevant experience. | Keep in study. |
| 5 | Medium | Related role or industry experience mentioned in summary. Not exact match but useful perspective. | Keep in study if you need more participants. |
| 1 | Low | Tangentially related. May have occasional exposure to the task. | Remove unless you are short on participants. |
| 0 | None | Completely unrelated role. No relevant experience visible in profile. | Always remove from study. |
The participant profile from GET /v1/research-groups/{group_id} includes:
name - The persona's nameoccupation - Job title (primary relevance indicator)summary - Brief bio describing background, interests, and experience (secondary relevance indicator)age - Current agelocation - Geographic locationGroup of 10 from "Automotive Manufacturing" filter:
| Name | Occupation | Score | Why |
|---|---|---|---|
| James Neri | Maintenance Technician | 10 (High) | Summary: "Spanish-speaking mechanic" - direct match |
| Michael Mclimans | Maintenance Technician | 10 (High) | Summary: "automotive tech" - direct match |
| Sonny Carrizales | Unemployed | 10 (High) | Summary: "former auto parts salesman" - deep relevant experience |
| Jaime Tejada | Sales Manager | 5 (Medium) | Summary: "auto sales specialist" - sells cars, not parts, but knows industry |
| Joseph Akin | Facilities Manager | 5 (Medium) | Equipment maintenance experience, orders parts |
| Others | Production/QA/Data | 1-0 (Low/None) | Manufacturing-adjacent but not parts sourcing |
In this case, the full group of 10 was used because even the lower-scoring participants had tangential automotive experience. For a more niche topic, the low-scoring participants would be removed.
curl -s -X POST "https://app.askditto.io/v1/research-studies/{study_id}/agents/remove" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agent_ids": [123, 456, 789]}'
Agents remain in the research group. Only their participation in this specific study is removed.
curl -s -X POST "https://app.askditto.io/v1/research-groups/{group_id}/agents/remove" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agent_ids": [123, 456]}'
This permanently removes agents from the group. Use sparingly.
Add more participants to an existing group with different or additional filters:
curl -s -X POST "https://app.askditto.io/v1/research-groups/{group_uuid}/append" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filters": {"country": "USA", "state": "GA", "age_min": 40, "age_max": 60},
"group_size": 5
}'
append endpoint uses group_uuid (the UUID string), NOT the numeric group_id.
To build a panel that represents a broad population (e.g., "representative US adults"), use iterative recruitment:
The ESPN pricing study used 64 US personas from Ditto's "100 Americans" dataset. This pre-built panel was designed to be nationally representative across age, gender, geography, income, and media consumption patterns. For studies requiring this level of representativeness, ask about pre-built panels.
Groups persist in Ditto and can be reused across multiple studies. This is valuable when:
research_study_link on the company record)curl -s "https://app.askditto.io/v1/research-groups" \
-H "Authorization: Bearer YOUR_API_KEY"
Look for groups with descriptive names that match your target:
"MI State Voters", "TX State Voters""Cybersecurity Professionals", "Healthcare Eye Care Providers""US Adults 28-45 Product Feedback"| Study Type | Recommended Group Size | Rationale |
|---|---|---|
| Standard research (CPG, B2C, political) | 10 | Enough diversity for pattern identification. Sweet spot validated across 50+ studies. |
| Quick validation / focused test | 6-8 | Sufficient for directional insights when time is constrained. |
| Due diligence (over-recruit) | 15-20 | Recruit more, curate down to 10-12 after profile review. |
| Pricing study | 10-20 | More participants = higher confidence on price sensitivity ranges. |
| Cultural research | 6-10 | Smaller groups with specific demographic focus produce deeper cultural insights. |
| Competitive intelligence | 10 | Standard size. Ensure diverse competitive experiences. |
| Product Category | Recommended Filters |
|---|---|
| Premium beverages | Age 25-55, country matching brand market |
| Alcoholic drinks | Age 25-55 (legal drinking age +), country matching |
| Children's products | Age 25-40, is_parent: true |
| Health/wellness supplements | Age 25-55, country matching |
| Personal care / beauty | Age 22-50, optionally gender-filtered |
| Snacks / convenience food | Age 18-55, broad demographics |
| Product Type | Recommended Filters |
|---|---|
| Productivity SaaS | Age 25-45, employment: "employed" |
| Consumer app | Age 18-45, broad |
| Prosumer / creative tools | Age 25-40 |
| Finance / budgeting | Age 25-55 |
| Health / wellness app | Age 25-50 |
| Research Type | Recommended Filters |
|---|---|
| State-specific voter sentiment | country: "USA", state: "{2-letter}", age_min: 18, age_max: 65 |
| National sentiment | country: "USA", age_min: 18, age_max: 70 |
| Suburban voter focus | State + age 30-60 (suburban demographics) |
| Error | Cause | Solution |
|---|---|---|
| 0 agents returned | State filter uses full name | Use 2-letter code: "MI" not "Michigan" |
| 0 agents returned | Unavailable country | Only USA, UK, Germany, Canada available |
| 0 agents returned | Too-narrow filter combination | Broaden filters. Try removing industry or education. Use Q1 to screen instead. |
"size is not supported" | Used "size" instead of "group_size" | Change to "group_size" |
"unknown filter field" | Used income filter (not supported) | Remove income filter. Use education/employment as proxy. |
| Empty study (no participants) | Used group_id instead of research_group_uuid | Pass the UUID string from group creation, not the numeric ID |
| 401 Unauthorized | Missing or incorrect API key | Check Authorization: Bearer header |
| Irrelevant participants | Industry filter too broad | Use over-recruit-and-curate strategy (Section 6) |
Research groups from real production studies, showing the exact filters and group sizes used:
| Study | Group Name | Size | Filters | Strategy |
|---|---|---|---|---|
| MotorMinds | Auto Service Professionals | 10 | industry: ["Automotive Manufacturing"], age: 28-58 |
Direct industry filter. Full group used (all had some relevance). |
| VetVivo | Pet Owner Candidates | 20 | age: 30-60, country: USA |
Broad filter + Q1 screen. No industry filter (pet owners are general population). |
| Feel Good Games | Parents of Young Children | 20 | age: 25-40, is_parent: true |
Direct demographic filter. is_parent filter worked well. |
| PatientCompanion | Elder Care Healthcare Workers | 20 | industry: ["Healthcare"], elder care focus |
Healthcare filter + Q1 screen for elder care role. |
| NexRisx | Cybersecurity Professionals | 8 | industry: ["Cybersecurity"] |
Exact industry match. Smaller group (niche audience, high relevance). |
| Airfairness | Working Professional Travelers | 20 | age: 25-55, country: USA, employment: "employed" |
Broad filter + Q1 screen ("How often do you fly?"). No travel industry filter exists. |
| Michigan Voters | MI State Voters | 10 | country: "USA", state: "MI", age: 25-70 |
State-filtered. 2-letter code critical. |
| CareQuarter Phase 1 | US Adults 45-65 Managing Parents | 12 | age: 45-65, country: USA |
Age-focused. Target: adult children of aging parents. |
| German Bread Study | German Adults 30-65 | 6 | country: "Germany", age: 30-65 |
Country-specific cultural research. Small group for depth. |
20 per API call. If you need more than 20 participants, use the append endpoint to add more to an existing group, or create multiple groups and run separate studies.
Yes. Pass an array: "industry": ["Healthcare", "Home Healthcare"]. This returns personas from either industry, not only those matching both.
The Ditto API does not currently provide a list of all available industry values. The validated values from production studies are documented in the Industry Proxy Mapping section. If you try an industry value that does not exist, the API will return 0 agents (not an error).
No. Industry filters are useful for professional/B2B research but unnecessary for consumer research. For CPG, use age + country. For political, use state + age. Only use industry filters when you need participants with specific professional experience. When in doubt, use broad filters and let Q1 screen for relevance.
The API returns a group with 0 agents. There is no error message. This usually means: (1) wrong state code format (full name vs 2-letter), (2) unsupported country, or (3) too-narrow filter combination. Try broadening filters and retrying. For state-specific groups, wait 30 seconds and retry before giving up.
Yes. Groups persist and can be used for multiple studies. However, personas do not carry context between different studies. Each study starts fresh. This is useful for running follow-up or multi-phase research on the same topic with the same demographic profile.
Indefinitely. Once created, a group remains available for future studies. You can list all your groups with GET /v1/research-groups.