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) |
Examples
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 frameMulti-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