Inspiration

Even in presidential elections, only around 60% of eligible voters come to the polls. In local and state elections, turnout drops even further despite the fact that these legislators often have a more direct impact on a person's daily life. A large part of this gap is voter education. Potential voters have to understand legalese on referendums and measures as well as study up potential candidates and their profiles. Studies have shown that when voters understand what's at stake, they are significantly more likely to show up. We wanted to close that gap not by telling people how to vote, but by making sure they understand what they're voting on.

What it does

Ballot Bridge is an all-in-one civic engagement web app that brings the ballot closer to the voter and makes it approachable. Users enter their location and demographic profile, and the app personalizes everything around them:

  • Ballot Explainer: Every race and measure on your upcoming ballot is displayed with AI-generated plain-language summaries — including what a "Yes" or "No" vote actually means, and how it could specifically affect you based on your age, income, and interests.
  • Congress Tracker: Browse bills currently circulating through the House and Senate. Each bill is summarized by AI and tagged with interest areas (Healthcare, Taxes, Housing, etc.) so you can quickly find what matters to you. Full bill text is pulled directly from Congress.gov.
  • Polling & Deadlines: Find your nearest polling places, early voting sites, and drop-off locations. See registration deadlines, absentee ballot deadlines, and ID requirements — all in one place.
  • AI Civic Assistant: Ask any question about your ballot, your candidates, or the election process. Get source-cited answers grounded in real civic data, with built-in fact-checking that rates claims as Supported, Contradicted, Mixed, or Not Enough Evidence.
  • Multi-language Support: All AI explanations can be delivered in English, Spanish, Chinese, Tagalog, or Vietnamese.

How we built it

Frontend: React 19 with TypeScript, styled with Tailwind CSS 4, and bundled with Vite. Each screen is a standalone component with its own data-fetching and state management.

Backend: A FastAPI server in Python serving a REST API with 20+ endpoints. We used HTTPX for async HTTP calls to external APIs, Pydantic for request/response validation, and flat JSON files for rapid prototyping without database setup overhead.

AI Layer: Google Gemini (gemini-2.5-pro) powers all summarization, chat, fact-checking, and tagging. We built a structured output pipeline using Pydantic models. For fact-checking, we use Gemini's Google Search grounding to cross-reference claims against live web results.

Data Sources: The Congress.gov API provides real-time bill listings and full bill text (fetched in parallel with asyncio.gather for speed). We generate stable public Congress.gov links so users can always access the original source without needing an API key. All election data was pulled from Google Civic Information API, which included ballot information as well as polling locations, dates, and times

Personalization: User profiles capture age, income, location, ethnicity, and interests. This context is injected into every AI prompt so summaries explain impact in terms of your life.

Challenges we ran into

The Congress.gov API's bill list endpoint returns only titles and metadata so we had to chain two additional API calls per bill: first to the /text endpoint to find available text versions, then to the actual HTML document URL hosted on govinfo.gov. We then strip the HTML to plain text, truncate to 15,000 characters, and cache the result. Similarly, the hearing list endpoint returns "Untitled Hearing" for every entry — we had to fetch individual hearing details in parallel to get real titles, committees, and dates.

Getting Gemini to reliably return valid JSON matching our Pydantic schemas required careful prompt engineering and multiple fallback layers. We built a generic _call_gemini_structured function that handles retries, JSON extraction from markdown code blocks, and graceful degradation to fallback responses when the model doesn't cooperate. The Gemini model also does not reliably return AI summaries which could be due to a weakness of the model.

Accomplishments that we're proud of

  • A user can go from entering their address to reading a plain-English explanation of every item on their ballot in under a minute with no prior civic knowledge required.
  • The Congress tab pulls full bill text directly from Congress.gov and generates AI summaries so that the fog covering Congress is removed. Interest tags let users quickly filter to what matters to them.
  • Every AI response includes source citations and uncertainty markers. We prevent hallucinate of election dates or fabricated policy effects by putting guard rails around the AI responses.

What we learned

  • We learned to parallelize fetching items from APIs to prevent stalling when the app loads.
  • There is no single API for "everything a voter needs to know." Building Ballot Bridge meant stitching together Congress.gov, geocoding services, state election boards, and LLM synthesis into one coherent experience.
  • We learned front-end webapp development and web design to try and create a cleaner user experience.

What's next for Ballot Bridge

  • Live election integration with state and county election board APIs to automatically populate ballots based on a user's exact precinct
  • Candidate comparison engine — we've built the backend but haven't wired it into the frontend yet. Candidate profiles are also difficult to find reliable sources for. Ballotpedia is the most comprehensive but contains a paid API.
  • Push notifications for registration deadlines, early voting windows, and Election Day reminders — the notification service and subscription model are already built

Built With

Share this project:

Updates