| name | ditto-political-polling |
| description | Run voter research, campaign messaging tests, and candidate perception studies using Ditto's synthetic persona platform (300K+ AI personas, 92% overlap with real focus groups). Covers state-specific voter sentiment, campaign messaging validation, competitive candidate framing, persuasion lever identification, and constituent concern surfacing. Every study uses mandatory state-filtered groups. Designed for campaign managers, political consultants, campaign strategists, and communications directors. Use when the user mentions voter research, campaign polling, candidate perception, election research, voter sentiment, campaign messaging, or political strategy.
|
| allowed-tools | Bash(curl *), Bash(python3 *), Read, Grep, WebFetch |
| argument-hint | [candidate name, state, or research brief] |
Ditto for Political Polling & Voter Research
Run state-specific voter research, campaign messaging tests, and candidate
perception studies using Ditto's 300,000+ synthetic personas โ directly
from the terminal.
Full documentation: https://askditto.io/claude-code-guide
What Ditto Does
Ditto maintains 300,000+ AI-powered synthetic personas calibrated to census
data. You ask them open-ended questions and get qualitative responses with
the specificity of real voter interviews.
- 92% overlap with traditional focus groups (EY Americas validation)
- 95% correlation with traditional research
- Harvard/Cambridge/Stanford/Oxford peer-reviewed methodology
- A 10-persona voter study completes in 10-12 minutes
- Traditional voter research: 2-4 weeks, $15,000-50,000
The Non-Negotiable Rule
Every political study MUST use a state-filtered research group.
- NEVER use generic groups like "American Voters" or "Suburban Voters"
- Group name format:
{StateCode} State Voters (e.g., "MI State Voters")
- State filter: 2-letter codes ONLY (MI, TX, PA, OH, AZ)
- Full state names ("Michigan") return 0 agents
political_affiliation is NOT a supported filter
State-specific groups produce dramatically more relevant responses than
generic national groups. This has been validated across 50+ studies.
Quick Start (Free Tier)
Get a free API key โ no credit card, no sales call:
curl -sL https://app.askditto.io/scripts/free-tier-auth.sh | bash
Free keys (rk_free_): ~12 shared personas, no state filtering.
Paid keys (rk_live_): state-specific groups, demographic filtering, unlimited studies.
API Essentials
Base URL: https://app.askditto.io
Auth header: Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
The Voter Research Workflow (7 Steps)
Step 1: Research the Candidate
Before touching the API, research:
- Candidate background (career, previous offices, accomplishments)
- Party affiliation (Democrat/Republican/Independent)
- Key issues they are running on
- Opponent(s) โ incumbent or challenger?
- Race dynamics (competitive? safe seat? toss-up?)
- Recent news (controversies, endorsements, polling numbers)
- Current campaign messaging and slogans
This research directly informs Q3 (candidate briefing) and Q6 (messaging test).
Step 2: Check for Existing State Group
Before creating a new group, check if one already exists:
curl -s "https://app.askditto.io/v1/research-groups?limit=50" \
-H "Authorization: Bearer $DITTO_API_KEY"
Look for groups named {StateCode} State Voters. Reuse existing
state groups for multiple races in the same state.
Step 3: Recruit State-Specific Panel
curl -s -X POST "https://app.askditto.io/v1/research-groups/recruit" \
-H "Authorization: Bearer $DITTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "MI State Voters",
"group_size": 10,
"filters": {
"country": "USA",
"state": "MI",
"age_min": 18,
"age_max": 65
}
}'
Save the uuid. Use group_size (not size), group uuid (not id).
If recruitment returns 0 agents: wait 30 seconds and retry. If still 0,
the study cannot proceed. NEVER fall back to a generic non-state group.
Step 4: Create Study
curl -s -X POST "https://app.askditto.io/v1/research-studies" \
-H "Authorization: Bearer $DITTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "John Smith Voter Research - Michigan",
"objective": "Understand MI voter priorities and perception of John Smith in the congressional race",
"research_group_uuid": "UUID_FROM_STEP_3"
}'
Save the study id. Response nests under data.study โ access via
response["study"]["id"], NOT response["id"].
Naming convention:
- Title:
[Candidate Name] Voter Research - [State]
- Objective:
Understand [State] voter priorities and perception of [Candidate] in the [race type] race
Step 5: Ask Questions (One at a Time)
curl -s -X POST "https://app.askditto.io/v1/research-studies/STUDY_ID/questions" \
-H "Authorization: Bearer $DITTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"question": "What are the top 2-3 issues that affect your daily life in Michigan? Walk me through what that looks like."}'
Returns job_ids. Poll until complete before asking the next question.
Step 6: Poll Until Complete
curl -s "https://app.askditto.io/v1/jobs/JOB_ID" \
-H "Authorization: Bearer $DITTO_API_KEY"
Polling strategy:
- Wait 45-50 seconds before first poll
- Then poll every 20 seconds
- Poll ONE job_id as proxy โ all jobs finish together
- Status:
queued โ started โ finished (or failed)
Step 7: Complete and Extract Insights
curl -s -X POST "https://app.askditto.io/v1/research-studies/STUDY_ID/complete" \
-H "Authorization: Bearer $DITTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"force": false}'
Use "force": true to re-run analysis on an already-completed study (avoids 409).
Get share link:
curl -s -X POST "https://app.askditto.io/v1/research-studies/STUDY_ID/share" \
-H "Authorization: Bearer $DITTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'
Use share_link field (preferred over share_url).
The Political Question Framework (7 Questions)
These questions are designed to surface real voter dynamics, not predictable
partisan responses. The candidate is introduced at Q3 โ never Q1.
Q1 โ Ground in Local Reality
"What are the top 2-3 issues that affect your daily life in [state/district]?
Walk me through what that looks like."
Purpose: Establishes what voters actually care about before any candidate context.
Q2 โ Decision Drivers
"When you're deciding who to vote for, what matters most?
What's an instant dealbreaker for a candidate?"
Purpose: Reveals decision criteria and red lines.
Q3 โ Candidate Briefing + Reaction
"Let me tell you about [Candidate]. [Background, party, key positions,
endorsements, campaign focus โ 6-8 concrete details].
What's your honest first reaction?"
Purpose: Tests candidate perception. Include 6-8 specific details:
party affiliation, career background, key policy positions, endorsements,
recent actions, campaign slogans. Generic briefings get generic responses.
ANCHORING RULE: Introduce the candidate at Q3, NOT Q1. Establishing
voter priorities first (Q1-Q2) produces unbiased baseline data.
Q4 โ Competitive Frame
"How does [Candidate] compare to [opponent(s)]?
Who feels more trustworthy on the issues you care about?"
Purpose: Reveals competitive positioning and trust dynamics.
Q5 โ Persuasion Levers
"What would [Candidate] need to say or do to earn your vote? Be specific."
Purpose: Identifies what persuades undecided or soft-opposition voters.
This is the most actionable question for campaign strategists.
Q6 โ Messaging Test
"Here's their main campaign message: '[quote/slogan]'.
Does this resonate? What's missing?"
Purpose: Tests whether the campaign's actual messaging lands or falls flat.
Use the real campaign slogan or tagline.
Q7 โ Constituent Advice
"If [Candidate] sat down with you for 5 minutes, what would you tell them?
Don't hold back."
Purpose: Surfaces unfiltered voter concerns, fears, and advice.
Best source of quotable insights for reports and content.
Question Framework Variants
Mix these into the standard 7 questions or use standalone:
| Variant | Question Template | Measures |
|---|
| Name Recognition | "What's your gut reaction when you hear [Name]?" | Awareness + first impressions |
| Issue Ownership | "Who do you trust more on [issue]: [A] or [B]?" | Competitive positioning per issue |
| Messaging Test | "[Candidate] says '[message]'. Your reaction?" | Message effectiveness |
| Switching Trigger | "What would make you change your mind about [Candidate]?" | Persuadable voter dynamics |
| Enthusiasm Gap | "How excited are you to vote for [Candidate]? 1-10." | Turnout likelihood proxy |
| Concern Surfacing | "What's your biggest concern about [Candidate]?" | Attack vulnerability mapping |
Insight Extraction for Political Research
Good political insight: Specific voter concern with a direct quote,
surprising perception gap, actionable messaging feedback, competitive vulnerability.
Weak political insight: Generic sentiment, expected partisan response,
abstract observation, confirmation of already-known positions.
Extraction Template
For each study, structure findings as:
Key Finding 1: [Voter perception or concern]
- Best quote: "[direct quote from persona]"
- Campaign implication: [what the campaign should do]
Key Finding 2: [Issue priority or messaging reaction]
- Best quote: "[direct quote]"
- Actionable takeaway: [specific next step]
Key Finding 3: [Competitive dynamic or persuasion opportunity]
- Best quote: "[direct quote]"
- Strategic insight: [what this means for the race]
Overall Narrative: What story do these findings tell about the race?
Trust Patterns in Political Research
From cross-study analysis of 50+ voter studies:
- Voters reward local presence and track record over national endorsements
- "Show up at community events, not just campaign rallies" is a recurring theme
- Incumbents have a natural advantage on "knowing local issues"
- Challengers can win on "fresh perspective" and "not part of the problem"
- Voters are more persuaded by specific local actions than party platform
Multi-Race Studies
Run the same state group across multiple races:
Group: MI State Voters (10 personas)
Study 1: Governor's race (7 questions)
Study 2: Senate race (7 questions)
Study 3: Congressional race (7 questions)
Same panel, different candidate briefings. Produces cross-race comparison
showing which candidates resonate with the same voters and where messaging
conflicts exist. Reuse the group โ create new studies for each race.
Cross-State Comparison
Run the same questions across different state groups:
Group A: PA State Voters โ Senate messaging test
Group B: OH State Voters โ Senate messaging test
Group C: MI State Voters โ Senate messaging test
Same 7 questions, different state panels. Reveals how the same messaging
lands differently in different states.
Complete API Reference
Research Groups
| Method | Endpoint | Purpose |
|---|
POST | /v1/research-groups/recruit | Recruit state-specific group |
POST | /v1/research-groups/create | Create group from explicit agent IDs |
POST | /v1/research-groups/interview | AI-assisted recruitment from objective |
GET | /v1/research-groups | List all groups (check for existing state groups) |
GET | /v1/research-groups/{id} | Get group details + voter profiles |
POST | /v1/research-groups/{id}/update | Update name/description |
DELETE | /v1/research-groups/{id} | Archive group |
POST | /v1/research-groups/{id}/agents/add | Add agents by ID |
POST | /v1/research-groups/{id}/agents/remove | Remove agents from group |
POST | /v1/research-groups/{uuid}/append | Recruit more agents into existing group |
โ ๏ธ Note: append uses group_uuid (not group_id).
Research Studies
| Method | Endpoint | Purpose |
|---|
POST | /v1/research-studies | Create voter study (research_group_uuid required) |
GET | /v1/research-studies | List studies |
GET | /v1/research-studies/{id} | Get study details |
POST | /v1/research-studies/{id}/complete | Trigger AI analysis |
POST | /v1/research-studies/{id}/agents/remove | Remove agents from study |
Questions
| Method | Endpoint | Purpose |
|---|
POST | /v1/research-studies/{id}/questions | Ask question in study (returns job_ids) |
GET | /v1/research-studies/{id}/questions | Get all Q&A data + voter profiles |
POST | /v1/research-agents/{id}/questions | Quick question to one voter persona |
POST | /v1/research-groups/{id}/questions | Quick question to entire state group |
Jobs, Sharing, Media
| Method | Endpoint | Purpose |
|---|
GET | /v1/jobs/{job_id} | Poll async job status |
POST | /v1/research-studies/{id}/share | Enable/disable sharing |
GET | /v1/research-studies/{id}/share | Check current share state |
POST | /v1/media-assets | Upload image/PDF (ad creative, mailers) |
Agents
| Method | Endpoint | Purpose |
|---|
GET | /v1/agents/find | Find one matching persona |
GET | /v1/agents/search | Search personas by demographics |
Natural Language Requests
| Method | Endpoint | Purpose |
|---|
POST | /v1/research-study-requests | Create study from plain-text brief |
POST | /v1/research-group-requests | Create group from description |
GET | /v1/research-group-requests/{id} | Get group request status |
Zeitgeist Surveys
| Method | Endpoint | Purpose |
|---|
POST | /v1/zeitgeist/surveys/create | Quick single-question voter poll |
GET | /v1/zeitgeist/surveys/{id}/results | Get survey results |
DELETE | /v1/zeitgeist/surveys/{id} | Delete survey |
Free Tier
| Method | Endpoint | Purpose |
|---|
POST | /v1/free/questions | Ask question to shared free-tier group |
Demographic Filters
Filters go inside the filters dict when recruiting:
| Filter | Type | Examples | Notes |
|---|
country | string | "USA" | Always "USA" for political research |
state | string | "MI", "TX", "PA" | 2-letter codes ONLY. Mandatory for political. |
city | string | "Detroit", "Houston" | Optional โ narrows pool |
age_min | integer | 18 | Voting age minimum |
age_max | integer | 65 | Typical voter range |
gender | string | "male", "female", "non_binary" | Optional |
is_parent | boolean | true, false | Good for family voter segments |
education | string | "high_school", "bachelors" | Optional |
NOT supported: income, employment, ethnicity, political_affiliation.
All political segmentation (party, ideology, voter type) must happen
through question design and response analysis โ not recruitment filters.
Polling Strategy
| Study size | First poll delay | Subsequent interval | Strategy |
|---|
| 10 personas | 45-50 seconds | 20 seconds | Poll ONE job_id as proxy |
| 12-15 personas | 50-60 seconds | 20 seconds | Poll ONE job_id as proxy |
Response Structure
Study creation: response["study"]["id"] (nested under study key)
Question responses (from GET /v1/research-studies/{id}/questions):
response_text โ the voter's answer (may contain HTML)
agent_name, agent_age, agent_city, agent_state, agent_country
agent_occupation, agent_summary
Use demographics to segment: urban vs suburban, younger vs older, occupation-based.
Share link: Prefer share_link field. If absent, use share_url.
Zeitgeist: Quick Voter Polls
For rapid single-question polls with predefined options:
curl -s -X POST "https://app.askditto.io/v1/zeitgeist/surveys/create" \
-H "Authorization: Bearer $DITTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "MI Governor Issue Priority",
"question": "Which issue matters most to you in the governor race?",
"research_group_uuid": "STATE_GROUP_UUID",
"answer_options": ["Economy & Jobs", "Healthcare", "Education", "Infrastructure", "Public Safety"]
}'
Get results: GET /v1/zeitgeist/surveys/SURVEY_ID/results
Media Attachments
Upload campaign mailers, ad creative, or debate screenshots:
curl -s -X POST "https://app.askditto.io/v1/media-assets" \
-H "Authorization: Bearer $DITTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"data_url": "https://example.com/campaign-mailer.png",
"filename": "mailer-draft.png",
"mime": "image/png"
}'
Then reference in a question:
curl -s -X POST "https://app.askditto.io/v1/research-studies/STUDY_ID/questions" \
-H "Authorization: Bearer $DITTO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"question": "Look at this campaign mailer. What message does it communicate? Does it make you more or less likely to support this candidate?",
"attachments": [MEDIA_ASSET_ID]
}'
Common Mistakes
- Using generic groups ("American Voters") instead of state-filtered groups
- Using full state names ("Michigan") instead of 2-letter codes ("MI")
- Filtering by
political_affiliation (not supported)
- Introducing the candidate in Q1 instead of Q3 (anchoring bias)
- Asking leading partisan questions ("Would you vote for a Democrat?")
- Generic candidate briefings in Q3 (include 6-8 concrete details)
- Using
size instead of group_size in recruitment
- Using
response["id"] instead of response["study"]["id"]
- Passing
agent_ids as strings instead of list[int]
- Polling every 10-15s (too aggressive โ use 45-50s first, then 20s)
- Skipping the
complete step (miss AI-generated voter analysis)
- Falling back to non-state groups when recruitment returns 0 agents
- Assuming voter alignment from demographics alone
What NOT to Ask
These produce predictable, useless responses:
- "Would you vote for a Democrat/Republican?" (partisan reflex)
- "Do you care about the economy?" (everyone says yes)
- "Is honesty important in a politician?" (obviously)
- "Do you support lower taxes?" (leading)
Instead, ask: "What are the top 2-3 issues that affect your daily
life?" โ let them tell you what matters without prompting.
Error Handling
| Error | Cause | Fix |
|---|
| 0 agents returned | Full state name used | Use 2-letter code |
| 0 agents returned | Very small state | Try city filter instead, or widen age |
| 409 Conflict | Study already completed | Retry with "force": true |
| 429 Too Many Requests | Rate limited | Wait 30-60s |
Job failed | Persona error | Report partial failure, don't auto-retry |
Limitations
- Political affiliation cannot be filtered โ segment via responses only
- Only USA, UK, Germany, Canada available (no state-level outside USA)
- Personas reflect general voter sentiment, not predictions of actual results
- For legally defensible polling โ use certified human pollsters
- For get-out-the-vote targeting โ use voter file data
Recommended hybrid: Ditto for rapid campaign intelligence (messaging tests,
perception studies, issue discovery). Human polling for final pre-election
numbers and legally reportable results.
Further Reading