electedBR answers two different questions about Brazilian politics and keeps them apart:
-
Who was elected?
get_elected()reads the candidates elected in a given year from yearly files consolidated from the open data of the Superior Electoral Court (TSE). -
Who is serving now?
get_deputies()andget_senators()query the open data APIs of the Chamber of Deputies and the Federal Senate for the members currently in service, andget_service_history()returns the official records of one member.
Every function returns a tibble with English column names, and every
function has a Portuguese alias (consultar_eleitos(),
consultar_senadores(), …).
Election results
The yearly files are listed in elected_years. The first
query for a year downloads its file (1 to 25 MB) into the cache
directory, which by default is a folder under tempdir();
set the electedBR.cache_dir option or the
ELECTEDBR_CACHE_DIR environment variable to keep the files
between sessions (see ?elected_cache_dir). Here we use an
explicit temporary directory.
elected_years[, c("year", "kind", "rows", "built")]
#> year kind rows built
#> 1 2018 general 20226 2026-09-25
#> 2 2020 municipal 381334 2026-09-25
#> 3 2022 general 16324 2026-09-25
#> 4 2024 municipal 306023 2026-09-25
cache <- tempdir()Mayors elected in two municipalities of Pernambuco in 2024:
get_mayors(state = "PE", municipality = c("Recife", "Caruaru"), cache_dir = cache)
#> Downloading elected_2024.parquet from https://huggingface.co/datasets/mlkwy/electedBR/resolve/main/elected_2024.parquet
#> # A tibble: 2 × 15
#> year election_id round state municipality_tse_id municipality office
#> <int> <chr> <int> <chr> <chr> <chr> <chr>
#> 1 2024 619 1 PE 23817 CARUARU mayor
#> 2 2024 619 1 PE 25313 RECIFE mayor
#> # ℹ 8 more variables: candidate_id <chr>, ticket_candidate_id <chr>,
#> # name <chr>, ballot_name <chr>, party_at_election <chr>,
#> # election_status <chr>, votes <dbl>, reference <chr>Municipalities are matched by name (ignoring accents and case) or by their TSE code. Councilors of a municipality, by party, with the alternates classified by the TSE:
recife <- get_councilors(state = "PE", municipality = "Recife",
include_alternates = TRUE, cache_dir = cache)
table(recife$election_status)
#>
#> ELEITO POR MÉDIA ELEITO POR QP SUPLENTE
#> 6 31 356General elections (2018, 2022) hold the statewide and nationwide
offices; votes are summed over every municipality (and, for president,
every state) and the municipal columns are NA. Running
mates have no votes of their own and are linked to the head of their
ticket by ticket_candidate_id:
pe22 <- get_elected(2022, state = "PE", office = c("governor", "vice_governor"),
cache_dir = cache)
#> Downloading elected_2022.parquet from https://huggingface.co/datasets/mlkwy/electedBR/resolve/main/elected_2022.parquet
pe22[, c("office", "candidate_id", "ticket_candidate_id", "ballot_name",
"party_at_election", "votes")]
#> # A tibble: 2 × 6
#> office candidate_id ticket_candidate_id ballot_name party_at_election votes
#> <chr> <chr> <chr> <chr> <chr> <dbl>
#> 1 govern… 170001604087 <NA> RAQUEL LYRA PSDB 3113415
#> 2 vice_g… 170001728608 170001604087 PRISCILA K… CIDADANIA NA
get_elected(2022, state = "PE", office = "senator", cache_dir = cache)
#> # A tibble: 1 × 15
#> year election_id round state municipality_tse_id municipality office
#> <int> <chr> <int> <chr> <chr> <chr> <chr>
#> 1 2022 546 1 PE <NA> <NA> senator
#> # ℹ 8 more variables: candidate_id <chr>, ticket_candidate_id <chr>,
#> # name <chr>, ballot_name <chr>, party_at_election <chr>,
#> # election_status <chr>, votes <dbl>, reference <chr>The Portuguese aliases accept the Portuguese office labels and return exactly the same tibble:
identical(
consultar_eleitos(2022, uf = "PE", cargo = "SENADOR", cache_dir = cache),
get_elected(2022, state = "PE", office = "senator", cache_dir = cache)
)
#> [1] TRUEResults describe the poll: party_at_election is the
party at the time of the election, and a candidate elected in 2022 is
not necessarily in office today.
Who holds the office on a given date?
Mayors and governors have no official API of sitting members. The
package keeps a small curated table of office-holding events
(resignations, deaths, removals, leaves and successions), each row
citing its source, served next to the yearly files and updated on
demand. as_of applies it. In Recife, the mayor elected in
2024 resigned on 2026-04-02 to run for governor and the vice mayor took
office on 2026-04-06:
recife_ticket <- get_elected(state = "PE", municipality = "Recife",
office = c("mayor", "vice_mayor"),
as_of = "2026-06-01", cache_dir = cache)
recife_ticket[, c("office", "ballot_name", "status_as_of", "status_date",
"office_as_of")]
#> # A tibble: 2 × 5
#> office ballot_name status_as_of status_date office_as_of
#> <chr> <chr> <chr> <date> <chr>
#> 1 mayor JOÃO CAMPOS resignation 2026-04-02 mayor
#> 2 vice_mayor VICTOR MARQUES succession 2026-04-06 mayorno_change_recorded means exactly that: nothing has been
recorded for the official, which is not evidence of being in office. The
table itself:
get_officeholding_events(cache_dir = cache)[, c("name", "office", "event", "date",
"successor_name", "successor_date")]
#> # A tibble: 1 × 6
#> name office event date successor_name successor_date
#> <chr> <chr> <chr> <date> <chr> <date>
#> 1 JOÃO HENRIQUE DE ANDRAD… mayor resi… 2026-04-02 VICTOR MARQUE… 2026-04-06Sitting members of Congress
The current composition comes from the official APIs and is cached
for six hours. mandate_role (principal or alternate) is
kept separate from exercise_status, so alternates currently
serving are listed.
pe <- get_senators(state = "PE", cache_dir = cache)
pe[, c("person_id", "name", "current_party", "mandate_role", "exercise_start")]
#> # A tibble: 3 × 5
#> person_id name current_party mandate_role exercise_start
#> <chr> <chr> <chr> <chr> <date>
#> 1 senado:5917 Fernando Dueire PSD alternate 2023-09-04
#> 2 senado:5008 Humberto Costa PT principal 2019-02-01
#> 3 senado:6338 Teresa Leitão PT principal 2023-02-01person_id is namespaced by house (senado:,
camara:) and is the key for the service history. The Senate
publishes service periods; the Chamber publishes status records, and the
package does not turn one into the other.
h <- get_service_history(pe$person_id[[1]], cache_dir = cache)
h[, c("mandate_id", "record_type", "exercise_start", "exercise_end", "description")]
#> # A tibble: 2 × 5
#> mandate_id record_type exercise_start exercise_end description
#> <chr> <chr> <date> <date> <chr>
#> 1 526 service_period 2022-12-07 2023-09-04 Retorno do titular
#> 2 526 service_period 2023-09-04 NA <NA>get_deputies() works the same way; without
state it issues one detail request per deputy, so the first
national call takes a few minutes.
Provenance and caching
- Every tibble from
get_elected()carries asourceattribute with the TSE dataset page, and the parliamentary tables carry the API URL insourceand the collection time inretrieved_at(UTC). - Yearly files are verified against the size and MD5 in
elected_years.refresh = TRUEdownloads again;elected_clear_cache()empties the cache. - Parliamentary queries keep an immutable snapshot of every completed
collection under
cache_dir/snapshots/; a network failure raises an error instead of returning expired data.
#> Built on 2026-09-25