Recommendations data

Every recommendation, for every contest and measure

A recommendation is an organization or official telling voters how to vote on one contest: a candidate, a ranked slate, or Yes or No on a measure. We collect them from published slates, voter guides and endorsement pages, link each one to the exact choice on the printed ballot, and keep the source.

Pricing

Yearly. Daily updates in the format you choose are included, and most changes reach you within the hour.

Delivered how you want it

Filter any delivery to the kinds of endorsers you care about: Voter guides & editorial boards, Labor, Environment & transportation, Housing & business, Political parties, Political clubs, Community & advocacy, Elected officials. Need a different format? Just ask.

CSV: one row per recommendation

The CSV is fully denormalized, so it opens straight into Excel, Google Sheets or pandas: each row carries the election, contest, district, choice and endorser it belongs to. The first line holds the column names.

All 40 columns
recommendation_id
election_id
election_name
election_date
election_type
state
contest_id
contest_title
contest_type
measure_code
district_id
district_name
district_level
district_type
ocd_id
census_geoid
vote_method
seats
ranks_allowed
party_ballot
choice_id
choice
candidate_id
candidate_name
ballot_designation
choice_party
measure_position
withdrawn
incumbent
endorser_id
endorser_slug
endorser_name
endorser_type
endorser_state
endorser_party
endorser_website
rank
source_url
published_on
retrieved_at

JSON: the ballot’s own structure

The JSON keeps the shape of the ballot: elections hold contests, contests hold choices in ballot order, and each choice lists its recommendations. Endorsers appear once, by id.

{
  "format": "ballotdata.recommendations/1",
  "generated_at": "2026-10-16T13:00:00.000Z",
  "coverage": { "national": false, "states": ["CA"], "contests": [], "endorser_types": [] },
  "counts": { "contests": 412, "choices": 1290, "recommendations": 5120, "endorsers": 380 },
  "endorser_types": [{ "slug": "labor", "name": "Labor" }, …],
  "endorsers": [{ "id": 77, "slug": "…", "name": "…", "type": { "slug": "advocacy", "name": "Advocacy" }, "state": "CA", … }],
  "elections": [{
    "id": 12, "slug": "ca-2026-11-03", "name": "November 3, 2026 General", "date": "2026-11-03", "type": "general",
    "contests": [{
      "id": 9031, "title": "Proposition 5", "type": "measure", "measure_code": "5", "vote_method": "plurality",
      "district": { "id": 6, "name": "California", "level": "state", "ocd_id": "ocd-division/country:us/state:ca", … },
      "endorser_count": 41,
      "choices": [{
        "id": 51001, "label": "Yes", "measure_position": "yes", "ballot_order": 1,
        "recommendations": [{
          "id": 880412, "endorser": { "id": 77, "name": "…", "type": "advocacy" },
          "rank": null, "source_url": "https://…", "published_on": "2026-09-30", "retrieved_at": "…"
        }]
      }, …]
    }, …]
  }]
}

The full field list is in the documentation.