Skip to contents

What it covers

The Ballotpedia municipal elections scraper collects city, county, and mayoral election data from two Ballotpedia index pages. Use office = "municipal_elections" to activate it.

Two index pages are available via the race_type argument:

race_type Ballotpedia page Coverage
"all" (default) United_States_municipal_elections,_{year} City council, county, and mayoral races; 2014–present
"mayoral" United_States_mayoral_elections,_{year} Mayoral races only; 2020–present

Arguments

Argument Default Description
office Must be "municipal_elections"
state NULL State name (title-case, e.g. "Texas"), or NULL for all states
year NULL Single election year; use with mode = "links" or "results"
race_type "all" Which index page to use — see above
mode "links" What to return — see below
start_year 2014 Earliest year for a multi-year scrape when year is NULL
end_year NULL Latest year (default: current calendar year)

The mode parameter

Value Returns Speed
"links" (default) One row per election sub-URL with location metadata; no vote data Fast — 1–2 requests per year
"results" Full candidate data with vote counts and winner flags Slower — 1 extra request per election page

Examples

links <- scrape_elections(
  office = "municipal_elections",
  year   = 2022,
  state  = "Texas"
)

links %>%
  select(location, state, location_type, url) %>%
  arrange(location_type, location)

All states, one year

links_all <- scrape_elections(
  office = "municipal_elections",
  year   = 2022
)

# Breakdown by location type
links_all %>%
  count(location_type, sort = TRUE)

Use race_type = "mayoral" to pull only from the dedicated mayoral index page (available 2020–present):

mayoral_links <- scrape_elections(
  office    = "municipal_elections",
  year      = 2024,
  race_type = "mayoral"
)

mayoral_links %>%
  select(location, state, url) %>%
  arrange(state, location)

Full candidate results for one year + state

mode = "results" follows each sub-URL — slower but returns candidate names, vote counts, and winner flags:

results <- scrape_elections(
  office = "municipal_elections",
  year   = 2022,
  state  = "Texas",
  mode   = "results"
)

results %>%
  filter(is_winner) %>%
  select(location, office, election_type, candidate, party, pct, votes) %>%
  arrange(location, office)

Mayoral results only — one year, all states

scrape_elections(
  office    = "municipal_elections",
  year      = 2022,
  race_type = "mayoral",
  mode      = "results"
) %>%
  filter(is_winner, office == "Mayor") %>%
  select(location, state, candidate, party, pct, votes) %>%
  arrange(state, location)

Mayoral results for a single state

scrape_elections(
  office    = "municipal_elections",
  year      = 2024,
  state     = "California",
  race_type = "mayoral",
  mode      = "results"
) %>%
  filter(office == "Mayor") %>%
  select(location, candidate, party, is_winner, pct, votes) %>%
  arrange(location)

Multi-year mayoral results

scrape_elections(
  office     = "municipal_elections",
  race_type  = "mayoral",
  mode       = "results",
  start_year = 2020,
  end_year   = 2022
) %>%
  filter(is_winner, office == "Mayor") %>%
  select(year, location, state, candidate, party, pct, votes) %>%
  arrange(year, state, location)
scrape_elections(
  office     = "municipal_elections",
  start_year = 2020,
  end_year   = 2022,
  race_type  = "all"
) %>%
  group_by(year, location_type) %>%
  summarise(n_elections = n(), .groups = "drop")

Columns returned

  • year, location (city or county name), state
  • location_type"mayoral", "city", "county", or "other"
  • url — full Ballotpedia URL of the individual election page

mode = "results"

All link columns plus:

  • election_url — URL of the individual election page
  • office — e.g. "Mayor", "City Council", "Public Defender"
  • election_type"General", "Primary", "Primary Runoff", "General (RCV)", or "Other"
  • candidate, ballotpedia_url, party
  • is_winner, is_incumbent
  • pct — vote percentage (e.g. "62.3%") or ""
  • votes — vote count (e.g. "12,345") or ""