Scraping election data with DownBallotR
Source:vignettes/articles/scraping-data.Rmd
scraping-data.RmdPrerequisites
Before scraping data you need a working Python environment. If you have not done so yet, follow the steps in the Python setup vignette:
# One-time setup (downloads ~100-200 MB the first time)
downballot_install_python()At the start of each R session:
The single entry point: scrape_elections()
All data retrieval flows through one function:
scrape_elections(state, ...)The scraper is selected automatically based on
state — you never need to specify a backend by name:
| Priority | Condition | Scraper used |
|---|---|---|
| 1 |
state is North Carolina |
NC State Board of Elections scraper (2000–present) |
| 2 |
state is Connecticut |
Connecticut CTEMS scraper (2016–present) |
| 3 |
state is Georgia |
Georgia Secretary of State scraper (2000–present) |
| 4 |
state is Utah |
Utah election results scraper (2023–present) |
| 5 |
state is Indiana |
Indiana voters portal scraper (2019–present) |
| 6 |
state is Louisiana |
Louisiana SOS scraper (1982–present) |
| 7 | All other states | ElectionStats multi-state scraper |
Data availability
Use db_available_years() to check available year ranges
programmatically:
# All sources
db_available_years()
# Filter to one state
db_available_years(state = "Virginia")| Source | State | Start year | End year |
|---|---|---|---|
| ElectionStats | Vermont | 1789 | 2024 |
| ElectionStats | Virginia | 1789 | 2025 |
| ElectionStats | Colorado | 1902 | 2024 |
| ElectionStats | Massachusetts | 1970 | 2026 |
| ElectionStats | New Hampshire | 1970 | 2024 |
| ElectionStats | Idaho | 1990 | 2024 |
| ElectionStats | New York | 1994 | 2024 |
| ElectionStats | New Mexico | 2000 | 2024 |
| ElectionStats | South Carolina | 2008 | 2025 |
| NC State Board | North Carolina | 2000 | present |
| CT CTEMS | Connecticut | 2016 | present |
| GA Secretary of State | Georgia | 2000 | present |
| Utah elections site | Utah | 2023 | present |
| Indiana voters portal | Indiana | 2019 | present |
| Louisiana SOS | Louisiana | 1982 | present |
To see which states are supported by the ElectionStats scraper:
db_list_states("election_stats")
#> [1] "Colorado" "Idaho" "Massachusetts" "New Hampshire"
#> [5] "New Mexico" "New York" "South Carolina" "Vermont"
#> [9] "Virginia"Choosing the right scraper
| Goal | Call |
|---|---|
| Candidate + vote totals for CO, MA, NH, ID, VT (classic) | scrape_elections(state = "virginia", ...) |
| Precinct-level results for CO, MA, ID (classic) | scrape_elections(state = "colorado", year_from = 2022, year_to = 2022, level = "precinct") |
| Candidate + vote totals for SC, NM, VA, NY (Playwright) | scrape_elections(state = "south_carolina", ...) |
| Precinct-level results for SC, NM, VA (v2 CSV API) | scrape_elections(state = "new_mexico", year_from = 2024, year_to = 2024, level = "precinct") |
| NC precinct-level local results | scrape_elections(state = "NC", year_from = 2025, year_to = 2025) |
| CT statewide + town results | scrape_elections(state = "CT", year_from = 2024, year_to = 2024) |
| CT statewide totals only (faster) | scrape_elections(state = "CT", year_from = 2024, year_to = 2024, level = "state") |
| GA statewide + county + precinct results | scrape_elections(state = "GA", year_from = 2024, year_to = 2024) |
| GA statewide + county only (faster) | scrape_elections(state = "GA", year_from = 2024, year_to = 2024, level = "county") |
| GA with vote-method breakdown | scrape_elections(state = "GA", year_from = 2024, year_to = 2024, include_vote_methods = TRUE) |
| GA precinct-level only | scrape_elections(state = "GA", year_from = 2024, year_to = 2024, level = "precinct") |
| UT statewide + county + precinct results | scrape_elections(state = "UT", year_from = 2024, year_to = 2024) |
| UT statewide + county only (faster) | scrape_elections(state = "UT", year_from = 2024, year_to = 2024, level = "county") |
| UT statewide only (fastest) | scrape_elections(state = "UT", year_from = 2024, year_to = 2024, level = "state") |
| UT precinct-level only | scrape_elections(state = "UT", year_from = 2024, year_to = 2024, level = "precinct") |
| IN statewide + county General Election results | scrape_elections(state = "IN", year_from = 2024, year_to = 2024) |
| IN statewide only (faster) | scrape_elections(state = "IN", year_from = 2022, year_to = 2022, level = "state") |
| LA statewide + parish results | scrape_elections(state = "LA", year_from = 2024, year_to = 2024) |
| LA statewide only (faster; skips parish scraping) | scrape_elections(state = "LA", year_from = 2023, year_to = 2023, level = "state") |
Detailed articles
Each scraper has its own article with full argument documentation, worked examples, and column descriptions (available on the package website):
- ElectionStats states — VA, MA, CO, NH, ID, VT (classic) + SC, NM, NY (Playwright); candidate + county + precinct results
- North Carolina — NC State Board of Elections; precinct-level results
- Connecticut — CT CTEMS; statewide + town results, 2016–present
- Georgia — GA Secretary of State; statewide + county + precinct results, 2000–present
- Utah — Utah elections site; statewide + county + precinct results, 2023–present
- Indiana — Indiana voters portal; statewide + county General Election results, 2019–present
- Louisiana — Louisiana Secretary of State; statewide + parish results, 1982–present
Performance tips
- Start small — test with a single year and state before requesting large date ranges.
- Playwright states are slower — South Carolina, New Mexico, and New York launch a headless browser for each scrape. Expect several seconds per year.
-
Parallel scraping is on by default for classic
(requests-based) ElectionStats states. Pass
parallel = FALSEto disable. - Be polite — built-in delays are intentional. Do not reduce or disable them; excessive requests may result in temporary IP blocks.