Skip to contents

What it covers

The ElectionStats scraper pulls candidate-level and county-level election results from state-hosted ElectionStats sites.

State Backend Start year End year
Vermont Classic (requests) 1789 2024
Virginia Classic (requests) 1789 2025
Colorado Classic (requests) 1902 2024
Massachusetts Classic (requests) 1970 2026
New Hampshire Classic (requests) 1970 2024
Idaho Classic (requests) 1990 2024
New York v2 (Playwright) 1994 2024
New Mexico v2 (Playwright) 2000 2024
South Carolina v2 (Playwright) 2008 2025

Classic states use simple HTTP requests and are fast. Playwright states (NY, NM, SC) launch a headless Chromium browser to render JavaScript — they are slower but fully automated.


Arguments

Argument Default Description
state required State name, snake_case (e.g. "virginia")
year_from NULL (earliest) Start year, inclusive
year_to NULL (current year) End year, inclusive
level "all" What to return — see below
parallel TRUE Parallel county scraping (classic states only)

The level parameter

Value Returns
"all" (default) Named list with $state, $county, and (where available) $precinct data frames
"state" Candidate-level results data frame
"county" County vote breakdown data frame
"precinct" Precinct-level vote breakdown data frame (CO, MA, ID, SC, NM, VA)

Examples

Candidate-level results for a single year

state_df <- scrape_elections(
  state     = "virginia",
  year_from = 2023,
  year_to   = 2023,
  level     = "state"
)

state_df %>%
  filter(winner == TRUE) %>%
  arrange(desc(votes)) %>%
  select(office, district, candidate, party, votes)

County-level vote counts

county_df <- scrape_elections(
  state     = "virginia",
  year_from = 2023,
  year_to   = 2023,
  level     = "county"
)

county_df %>%
  arrange(desc(votes)) %>%
  select(county_or_city, candidate, votes)

Both levels at once (default)

level = "all" returns a named list with $state, $county, and (for precinct-capable states) $precinct elements:

res <- scrape_elections(
  state     = "virginia",
  year_from = 2023,
  year_to   = 2023
)

res$state   # candidate-level data frame
res$county  # county breakdown data frame

Multi-year range

ma_results <- scrape_elections(
  state     = "massachusetts",
  year_from = 2018,
  year_to   = 2022,
  level     = "state"
)

ma_results %>%
  filter(election_type == "General") %>%
  select(election_year, office, district, candidate, party, votes)

Playwright state (South Carolina)

sc_results <- scrape_elections(
  state     = "south_carolina",
  year_from = 2024,
  year_to   = 2024,
  level     = "state"
)

sc_results %>%
  filter(winner == TRUE) %>%
  select(office, district, candidate, party, vote_pct)

Precinct-level results

Available for CO, MA, ID (classic/requests-based) and SC, NM, VA (v2 — fetched via CSV download API). Not available for NH, VT, or NY.

# Classic state
precinct_df <- scrape_elections(
  state     = "colorado",
  year_from = 2022,
  year_to   = 2022,
  level     = "precinct"
)

precinct_df %>%
  arrange(county, precinct) %>%
  select(county, precinct, candidate, votes)
# v2 state — same interface, data fetched via CSV API
precinct_df <- scrape_elections(
  state     = "new_mexico",
  year_from = 2024,
  year_to   = 2024,
  level     = "precinct"
)

Or retrieve all levels at once and access $precinct:

res <- scrape_elections(
  state     = "south_carolina",
  year_from = 2024,
  year_to   = 2024
)

res$precinct  # precinct-level data frame (NULL for NH, VT, NY)

Disable parallel scraping

res_seq <- scrape_elections(
  state     = "virginia",
  year_from = 2023,
  year_to   = 2023,
  parallel  = FALSE
)

Columns returned

level = "state" (candidate-level)

  • state, election_year, election_id, election_type
  • office_level, office, district
  • candidate_id, candidate, party
  • votes, vote_pct, winner
  • url

level = "county"

  • state, election_year, election_id, election_type
  • office_level, office, district, county_or_city
  • candidate_id, candidate, party
  • votes, vote_pct
  • county_winnerTRUE for the top vote-getter within each county/city
  • url

level = "precinct" (CO, MA, ID, SC, NM, VA)

  • state, election_year, election_id, election_type
  • office_level, office, district, county, precinct
  • candidate_id, candidate, party
  • votes, vote_pct
  • precinct_winnerTRUE for the top vote-getter within each precinct
  • url