Campaign Brain Public Website Plan¶
Developer Resources
CLAUDE.md - AI-assisted development guide
Executive Summary¶
A conversion-focused marketing site targeting grass-roots campaign managers who need fast, quick, and easy tools. The site combines a traditional marketing funnel with a unique lead-generation mechanism: dynamic district pages that show prospects relevant local data before they sign up.
1. Site Architecture¶
Primary Domain¶
- campaignbrain.ai or nominate.ai (main marketing site)
Wildcard District Domains¶
- {district}.nominate.ai → Dynamic district pages
- Examples:
ia03.nominate.ai,mi07.nominate.ai,ca45.nominate.ai
2. Site Map¶
nominate.ai (root)
│
├── / (Homepage)
│ └── Hero + Value prop + CTA
│
├── /features
│ └── Core capabilities overview
│
├── /pricing
│ └── Simple, transparent pricing
│
├── /demo
│ └── Interactive preview or video walkthrough
│
├── /start
│ └── Quick account setup flow (3 steps max)
│
├── /login
│ └── Redirect to tenant app
│
└── /districts/{code}
└── Fallback route for district pages
(also served via wildcard subdomains)
Wildcard Subdomains:
├── ia03.nominate.ai → Iowa CD-3
├── mi07.nominate.ai → Michigan CD-7
├── tx22.nominate.ai → Texas CD-22
└── [any].nominate.ai → Dynamic generation
3. Page-by-Page Content Plan¶
3.1 Homepage (/)¶
Purpose: Hook visitors in 5 seconds, get them to pricing or demo.
Hero Section:
Headline: "Win Your Campaign. Not a PhD in Software."
Subhead: "The CRM that grass-roots campaigns actually use.
Voter outreach, volunteer coordination, and AI-powered
follow-ups—all in one place."
CTA: [See Pricing] [Watch 2-Min Demo]
Problem/Solution Block: Three pain points, three solutions. No fluff.
| Pain Point | Solution |
|---|---|
| "I'm drowning in spreadsheets" | One unified voter database with smart search |
| "My volunteers forget to follow up" | Automated reminder sequences that actually work |
| "I don't know what's working" | Real-time dashboards showing outreach impact |
Social Proof: - Quote from a campaign manager (even fictional placeholder initially) - "Trusted by X campaigns across Y states" (update as you grow) - Logos if you have recognizable clients
Feature Highlights: Three cards, icon + headline + one sentence each: 1. Voter Database — Search 8M+ voter records by name, address, or turnout score 2. Multi-Channel Outreach — Phone, door, text, email, postcards from one screen 3. AI Follow-Ups — Claude-powered scheduling that adapts to responses
District Teaser:
"See your district right now"
[Enter district code: ______] [Go]
"Or visit ia03.nominate.ai to see Iowa CD-3"
Footer CTA:
3.2 Features Page (/features)¶
Purpose: Deeper dive for prospects who need convincing.
Structure: Single scrolling page with anchor links. NOT a features matrix.
Sections:
- Voter Database
- Smart search across millions of records
- Turnout scores, political profiles, contact history
- Import your own lists, export anytime
-
Screenshot: Search results table
-
Outreach Workflows
- Phone banking with built-in scripts
- Door-to-door canvassing with mobile check-in
- Text/SMS campaigns with compliance built in
- Email sequences that don't hit spam
- Postcard campaigns with print fulfillment
-
Screenshot: Workflow builder
-
Volunteer Management
- County captain coordination
- Shift scheduling and reminders
- Performance tracking (calls made, doors knocked)
-
Screenshot: Volunteer dashboard
-
AI-Powered Automation
- Smart follow-up timing based on response patterns
- Suggested talking points for each contact
- Automatic WHIP status updates from conversation notes
-
Screenshot: AI recommendation panel
-
Reporting & Analytics
- Real-time campaign dashboard
- Voter contact rates by channel
- Geographic heat maps
- Export everything to CSV
- Screenshot: Analytics dashboard
Bottom CTA:
3.3 Pricing Page (/pricing)¶
Purpose: Remove all friction. Transparent, simple, no "contact sales."
Pricing Philosophy: - Grass-roots campaigns are budget-conscious - They hate hidden fees and "enterprise" gates - Offer a free tier or trial to reduce risk
Suggested Tiers:
┌─────────────────┬─────────────────┬─────────────────┐
│ STARTER │ CAMPAIGN │ ORGANIZATION │
│ Free │ $99/month │ $299/month │
├─────────────────┼─────────────────┼─────────────────┤
│ 1 user │ 5 users │ Unlimited users │
│ 500 contacts │ 10,000 contacts │ 100,000 contacts│
│ Basic search │ Full database │ Full database │
│ Email only │ All channels │ All channels │
│ — │ AI follow-ups │ AI follow-ups │
│ — │ — │ API access │
│ — │ — │ Priority support│
├─────────────────┼─────────────────┼─────────────────┤
│ [Start Free] │ [Start Trial] │ [Start Trial] │
└─────────────────┴─────────────────┴─────────────────┘
All plans include: Voter data access, WHIP tracking, basic reporting
No contracts. Cancel anytime. Upgrade or downgrade instantly.
FAQ Section: - "Can I import my existing voter file?" → Yes, CSV upload supported - "Is my data secure?" → Yes, encrypted at rest and in transit - "Do you offer discounts for down-ballot races?" → Yes, contact us - "What if I need more contacts?" → Upgrade anytime, prorated
3.4 Demo Page (/demo)¶
Purpose: Let prospects see the product without signing up.
Options (pick one or both):
Option A: Video Walkthrough - 2-minute Loom-style video - Show: Login → Search voter → Add to workflow → See automation trigger - Embed with thumbnail showing the dashboard
Option B: Interactive Preview - Sandboxed version with fake data - Let them click around - Prompt to sign up when they try to "save" anything
Content:
"See Campaign Brain in Action"
[Video thumbnail with play button]
"This 2-minute walkthrough shows you how to:
✓ Find voters in your district
✓ Create an outreach workflow
✓ Let AI handle the follow-ups"
[Watch Demo] [Skip to Pricing]
3.5 Quick Start Flow (/start)¶
Purpose: Account creation in under 2 minutes.
Philosophy: - Absolute minimum fields - Show progress (Step 1 of 3) - Delay optional setup until after they're in
Step 1: Basic Info
"Let's get you started"
Campaign Name: [________________________]
Your Email: [________________________]
Password: [________________________]
[Continue →]
"Already have an account? [Log in]"
Step 2: Your District
"What race are you running?"
State: [Dropdown_________▼]
District: [Dropdown_________▼]
Race Type: ○ Congressional ○ State Senate
○ State House ○ County/Local
[Continue →]
Step 3: Confirmation
"You're in!"
Your campaign site: yourcampaign.nominate.ai
Dashboard: [Go to Dashboard →]
"We've loaded your district's voter data.
Start exploring, or check your email for a quick-start guide."
Post-Signup: - Auto-provision tenant - Pre-load relevant voter data - Send welcome email with 3 quick wins
3.6 Dynamic District Pages (/{district} or {district}.nominate.ai)¶
Purpose: Lead generation through relevant, personalized content.
URL Patterns:
- ia03.nominate.ai → Iowa Congressional District 3
- mi07.nominate.ai → Michigan Congressional District 7
- ny14.nominate.ai → New York Congressional District 14
Page Structure:
┌────────────────────────────────────────────────────────────┐
│ CAMPAIGN BRAIN [See Pricing] [Start Free] │
├────────────────────────────────────────────────────────────┤
│ │
│ Iowa Congressional District 3 │
│ ══════════════════════════════ │
│ │
│ Ready to win this seat? Here's what you're working with. │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Population │ │ Registered │ │ 2024 Margin │ │
│ │ 847,000 │ │ 612,000 │ │ R+4.2 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ District Overview │
│ ───────────────── │
│ [Wikipedia-sourced description of district geography, │
│ major cities, economic drivers, political history] │
│ │
│ Counties in This District │
│ ───────────────────────── │
│ • Pottawattamie County (Council Bluffs) │
│ • Mills County │
│ • Montgomery County │
│ • ... [expandable list] │
│ │
│ Recent Representatives │
│ ────────────────────── │
│ • 2023-present: Zach Nunn (R) │
│ • 2013-2023: David Young (R) │
│ • 2009-2013: Leonard Boswell (D) │
│ │
│ ════════════════════════════════════════════════════════ │
│ │
│ "Campaign Brain helped me track 50,000 voter contacts │
│ across 12 counties without losing my mind." │
│ — Campaign Manager, Similar Race │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Ready to run in Iowa CD-3? │ │
│ │ │ │
│ │ Get instant access to: │ │
│ │ ✓ 612,000 registered voter records │ │
│ │ ✓ Turnout scores and political profiles │ │
│ │ ✓ Multi-channel outreach tools │ │
│ │ ✓ AI-powered follow-up automation │ │
│ │ │ │
│ │ [Start Your Campaign — Free] │ │
│ │ │ │
│ │ No credit card required. Upgrade when you're ready. │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ Other Districts: [IA-01] [IA-02] [IA-04] [Browse All] │
│ │
└────────────────────────────────────────────────────────────┘
Data Sources:
- Wikipedia API (via wikipedia Python library)
- Census data for population
- FEC/state SoS for registered voters
- Cook PVI or similar for partisan lean
- Cache results for 48-72 hours
District Code Parsing:
# Pattern: {state_abbrev}{district_number}
# ia03 → Iowa, District 3
# mi07 → Michigan, District 7
# ca45 → California, District 45
# at-large states: ak00, vt00, wy00
def parse_district_code(code: str) -> tuple[str, int]:
"""Parse district code into state and district number."""
code = code.lower().strip()
state = code[:2]
district = int(code[2:])
return state, district
Fallback for Invalid Codes:
"We couldn't find district '{code}'"
Try one of these formats:
• ia03 — Iowa Congressional District 3
• mi07 — Michigan Congressional District 7
• ca45 — California Congressional District 45
[Browse All Districts] [Go to Homepage]
4. Navigation & Information Architecture¶
Primary Navigation (all pages)¶
┌────────────────────────────────────────────────────────────┐
│ [Logo] CAMPAIGN BRAIN Features Pricing Demo [Login] │
└────────────────────────────────────────────────────────────┘
- Logo: Links to homepage
- Features: Single page with anchor sections
- Pricing: The money page—always accessible
- Demo: Video or interactive preview
- Login: Top-right, secondary visual weight
- CTA Button: "Start Free" appears on hover/scroll or in hero
Footer (all pages)¶
┌────────────────────────────────────────────────────────────┐
│ CAMPAIGN BRAIN │
│ │
│ Product Company Legal │
│ Features About Privacy Policy │
│ Pricing Contact Terms of Service │
│ Demo Blog Cookie Policy │
│ │
│ © 2025 Campaign Brain. Made for campaigns that fight. │
│ │
│ [Twitter] [LinkedIn] │
└────────────────────────────────────────────────────────────┘
Mobile Navigation¶
- Hamburger menu (standard)
- "Start Free" button always visible
- District search prominent on homepage
5. Technical Implementation¶
Stack¶
| Component | Technology |
|---|---|
| Framework | FastHTML |
| Styling | Campaign Brain CSS (from style guide) |
| Icons | Lucide |
| District Data | wikipedia-python + caching |
| Hosting | Existing infrastructure |
| Forms | HTMX for progressive enhancement |
Key Routes¶
# routes.py
@app.get("/")
def homepage():
"""Main marketing page."""
return MarketingLayout(
Hero(),
PainPoints(),
Features(),
DistrictTeaser(),
FooterCTA(),
)
@app.get("/features")
def features():
"""Detailed feature breakdown."""
return MarketingLayout(FeaturesContent())
@app.get("/pricing")
def pricing():
"""Pricing tiers and FAQ."""
return MarketingLayout(PricingContent())
@app.get("/demo")
def demo():
"""Video walkthrough or interactive preview."""
return MarketingLayout(DemoContent())
@app.get("/start")
def start_flow():
"""Account creation wizard."""
return MarketingLayout(SignupWizard(step=1))
@app.post("/start/step/{step}")
def signup_step(step: int, data: SignupData):
"""Handle signup wizard steps."""
...
@app.get("/district/{code}")
def district_page(code: str):
"""Dynamic district page (path-based fallback)."""
return DistrictPage(code)
# Wildcard subdomain handler (configured at infrastructure level)
# {code}.nominate.ai → district_page(code)
District Data Service¶
# services/district_data.py
import wikipedia
from functools import lru_cache
from datetime import datetime, timedelta
CACHE_DURATION = timedelta(hours=48)
class DistrictDataService:
"""Fetch and cache district information."""
def __init__(self):
self.cache = {} # In production: Redis
def get_district_info(self, state: str, district: int) -> DistrictInfo:
"""Get district info, using cache if fresh."""
cache_key = f"{state}{district:02d}"
if self._is_cache_valid(cache_key):
return self.cache[cache_key]["data"]
info = self._fetch_district_info(state, district)
self._cache_result(cache_key, info)
return info
def _fetch_district_info(self, state: str, district: int) -> DistrictInfo:
"""Fetch from Wikipedia and other sources."""
state_name = STATE_NAMES[state]
# Wikipedia search
query = f"{state_name}'s {district}th congressional district"
try:
page = wikipedia.page(query)
summary = wikipedia.summary(query, sentences=3)
except wikipedia.DisambiguationError as e:
# Handle disambiguation
page = wikipedia.page(e.options[0])
summary = page.summary[:500]
except wikipedia.PageError:
summary = f"Congressional district in {state_name}."
return DistrictInfo(
state=state,
district=district,
state_name=state_name,
summary=summary,
# Add: population, registered_voters, partisan_lean
# from additional data sources
)
Signup Flow Handler¶
# services/signup.py
from pydantic import BaseModel, EmailStr
class SignupStep1(BaseModel):
campaign_name: str
email: EmailStr
password: str
class SignupStep2(BaseModel):
state: str
district: int
race_type: str
async def create_tenant(step1: SignupStep1, step2: SignupStep2) -> Tenant:
"""Create new tenant from signup flow."""
# Generate subdomain from campaign name
subdomain = slugify(step1.campaign_name)
# Create tenant via CBTENANT API
tenant = await tenant_service.create(
name=step1.campaign_name,
subdomain=subdomain,
admin_email=step1.email,
admin_password=hash_password(step1.password),
state=step2.state,
district=step2.district,
race_type=step2.race_type,
)
# Pre-load district voter data
await voter_service.load_district_data(tenant.id, step2.state, step2.district)
# Send welcome email
await email_service.send_welcome(step1.email, tenant)
return tenant
6. Content & Copy Guidelines¶
Voice & Tone¶
| Do | Don't |
|---|---|
| Direct, confident | Corporate jargon |
| "You" focused | "We" focused |
| Active voice | Passive voice |
| Specific numbers | Vague claims |
| Acknowledge pain points | Ignore reality |
Headlines Formula¶
[Benefit] without [Pain Point]
Examples:
• "Win Your Campaign. Not a PhD in Software."
• "Track 10,000 Voters. Not 10,000 Spreadsheets."
• "Automate Follow-Ups. Keep the Human Touch."
CTA Button Copy¶
| Context | Copy |
|---|---|
| Primary conversion | "Start Free" |
| Secondary conversion | "See Pricing" |
| Demo | "Watch 2-Min Demo" |
| District pages | "Start Your Campaign — Free" |
| Pricing page | "Start Free Trial" |
Microcopy¶
- Form labels: Clear, no asterisks (everything required is required)
- Error messages: Specific and helpful ("Email must include @")
- Success states: Celebratory but brief ("You're in!")
- Loading states: "Working..." or "Setting up your campaign..."
7. SEO & Marketing Integration¶
Target Keywords¶
| Primary | Secondary |
|---|---|
| campaign CRM | political campaign software |
| voter outreach software | campaign management tool |
| campaign management CRM | volunteer coordination app |
| grassroots campaign tools | voter database software |
District Page SEO¶
Each dynamic district page becomes a landing page for: - "{State} {District} campaign tools" - "Run for Congress {State}" - "{District} voter data"
Example meta tags:
<title>Iowa CD-3 Campaign Tools | Campaign Brain</title>
<meta name="description" content="Everything you need to run
a winning campaign in Iowa's 3rd Congressional District.
Access 612,000 voter records, outreach tools, and AI-powered
follow-ups.">
Conversion Tracking¶
Track these events: 1. Homepage visit 2. Pricing page view 3. Demo video start / complete 4. Signup wizard: Step 1 complete 5. Signup wizard: Step 2 complete 6. Account created (conversion) 7. District page view (with district code)
8. Launch Checklist¶
Phase 1: MVP (Week 1-2)¶
- Homepage with hero, pain points, basic features
- Pricing page with 3 tiers
- Signup flow (3 steps)
- Login redirect to tenant app
- Basic footer with legal links
Phase 2: District Pages (Week 2-3)¶
- District code parser
- Wikipedia integration
- District page template
- Wildcard subdomain routing
- Cache layer (Redis or file-based)
- Fallback for invalid codes
Phase 3: Polish (Week 3-4)¶
- Demo video or interactive preview
- Features page with screenshots
- Mobile responsive refinements
- SEO meta tags
- Analytics integration
- Social proof (testimonials)
Phase 4: Growth (Ongoing)¶
- Blog (content marketing)
- Email capture for non-converters
- A/B testing headlines
- District page backlinks
9. Success Metrics¶
| Metric | Target (Month 1) | Target (Month 3) |
|---|---|---|
| Homepage → Pricing | 25% | 35% |
| Pricing → Signup Start | 15% | 20% |
| Signup Start → Complete | 60% | 75% |
| District Page → Signup | 10% | 15% |
| Overall Conversion | 2% | 4% |
Appendix A: District Code Reference¶
At-Large States (use 00):
ak00, de00, mt00, nd00, sd00, vt00, wy00
Multi-District Examples:
ca01-ca52 (52 districts)
tx01-tx38 (38 districts)
fl01-fl28 (28 districts)
ny01-ny26 (26 districts)
State Abbreviations:
AL, AK, AZ, AR, CA, CO, CT, DE, FL, GA, HI, ID, IL, IN, IA, KS,
KY, LA, ME, MD, MA, MI, MN, MS, MO, MT, NE, NV, NH, NJ, NM, NY,
NC, ND, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VT, VA, WA, WV,
WI, WY
Appendix B: Sample District Data Response¶
{
"code": "ia03",
"state": "ia",
"state_name": "Iowa",
"district": 3,
"title": "Iowa's 3rd Congressional District",
"summary": "Iowa's 3rd congressional district is a congressional district in the U.S. state of Iowa. The district is anchored by Des Moines and includes the southwestern portion of the state.",
"population": 847234,
"registered_voters": 612000,
"partisan_lean": "R+4.2",
"counties": [
"Polk (partial)",
"Dallas",
"Madison",
"Warren",
"Pottawattamie",
"Mills"
],
"current_representative": {
"name": "Zach Nunn",
"party": "Republican",
"since": 2023
},
"cached_at": "2025-12-13T10:30:00Z",
"cache_expires": "2025-12-15T10:30:00Z"
}
Plan Version 1.0 — December 2025