congress
The congress
package provides access to the Congress.gov API. It allows
political scientists, journalists, and policy analysts to gather
legislative data programmatically. This includes bills, amendments,
member activity, nominations, committee outputs, reports, and more. All
requests can optionally be returned in tidy format.
This vignette introduces core workflows using congress
:
how to authenticate, handle pagination, and query the API.
The Congress.gov API requires an access key. After requesting a key
from api.congress.gov, use the
set_congress_key()
helper to authenticate:
This saves the key to your .Renviron
, making it
available in future sessions.
If you prefer to keep the key temporary, use:
Once set, congress
handles key usage internally. No
manual headers or tokens are needed.
It is recommended that you authenticate by placing your key in your
.Renviron
file to avoid accidentally sharing your person,
private key.
By default, the API returns 20 items per request, following the
upstream defaults. The limit can be increased by setting
limit = 250
, where 250 is the most items that can be
returned in a single request. To ease larger requests,
cong_request_next()
can be used to obtain later paginations
of results.
first <- cong_bill(congress = 118, type = 'hr', limit = 250)
more <- first |>
cong_request_next(max_req = 4)
This retrieves up to 1,250 House bills from the 118th Congress.
max_req
controls how many pages are requested. Results are
combined into one tibble
.
As of writing this vignette, you can make 5,000 requests per hour.
When requesting large datasets, be mindful of the API limits and use
limit = 250
to avoid inefficient calls.
All endpoints accept from_date
and to_date
.
This is often misleading, so beware. It does not filter by the date of
the action, but rather the date of the last update. As such, this is
most useful if you are scraping over time. For example, if you run an
analysis monthly, then you can use the from_date
and
to_date
arguments to limit the results to the time since
your last scrape.
cong_bill(congress = 118, from_date = '2025-04-01', to_date = '2025-05-23')
#> # A tibble: 20 × 12
#> congress latest_action_action_date latest_action_action_…¹ latest_action_text
#> <chr> <date> <chr> <chr>
#> 1 118 2024-12-24 10:13:00 Held at the desk.
#> 2 118 2024-12-20 <NA> Referred to the C…
#> 3 118 2024-12-19 18:06:21 Held at the desk.
#> 4 118 2024-12-19 <NA> Read twice and re…
#> 5 118 2024-12-19 <NA> Read twice and re…
#> 6 118 2024-12-18 18:26:07 Held at the desk.
#> 7 118 2024-12-18 <NA> Read twice and re…
#> 8 118 2024-12-17 <NA> Referred to the C…
#> 9 118 2024-12-16 <NA> Read twice and re…
#> 10 118 2024-12-12 <NA> Read twice and re…
#> 11 118 2024-12-12 <NA> Read twice and re…
#> 12 118 2024-12-11 16:55:14 Held at the desk.
#> 13 118 2024-12-05 <NA> Resolution agreed…
#> 14 118 2024-11-21 <NA> Placed on Senate …
#> 15 118 2024-11-21 <NA> Referred to the C…
#> 16 118 2024-11-21 <NA> Placed on Senate …
#> 17 118 2024-11-21 <NA> Placed on Senate …
#> 18 118 2024-11-21 <NA> Placed on Senate …
#> 19 118 2024-11-21 <NA> Placed on Senate …
#> 20 118 2024-11-21 <NA> Placed on Senate …
#> # ℹ abbreviated name: ¹latest_action_action_time
#> # ℹ 8 more variables: number <chr>, origin_chamber <chr>,
#> # origin_chamber_code <chr>, title <chr>, type <chr>, update_date <date>,
#> # update_date_including_text <date>, url <chr>
cong_bill()
retrieves bills, sorted by their most recent
action date.
bills <- cong_bill()
bills
#> # A tibble: 20 × 11
#> congress latest_action_action_date latest_action_text number origin_chamber
#> <chr> <date> <chr> <chr> <chr>
#> 1 119 2025-08-29 Referred to the Hou… 665 House
#> 2 119 2025-08-29 Referred to the Hou… 5064 House
#> 3 119 2025-08-29 Referred to the Com… 5061 House
#> 4 119 2025-08-29 Referred to the Hou… 5067 House
#> 5 119 2025-08-29 Referred to the Com… 667 House
#> 6 119 2025-08-29 Referred to the Hou… 666 House
#> 7 119 2025-08-29 Referred to the Hou… 5071 House
#> 8 119 2025-08-29 Referred to the Hou… 117 House
#> 9 119 2025-08-29 Referred to the Hou… 5072 House
#> 10 119 2025-08-29 Referred to the Hou… 5077 House
#> 11 119 2025-08-29 Referred to the Hou… 5070 House
#> 12 119 2025-08-29 Referred to the Com… 5076 House
#> 13 119 2025-08-29 Referred to the Hou… 5065 House
#> 14 119 2025-08-29 Referred to the Hou… 5074 House
#> 15 119 2025-08-29 Referred to the Hou… 5075 House
#> 16 119 2025-08-29 Referred to the Hou… 5062 House
#> 17 119 2025-08-29 Referred to the Com… 5060 House
#> 18 119 2025-08-29 Referred to the Hou… 5073 House
#> 19 119 2025-08-29 Referred to the Hou… 5063 House
#> 20 119 2025-08-29 Referred to the Hou… 5069 House
#> # ℹ 6 more variables: origin_chamber_code <chr>, title <chr>, type <chr>,
#> # update_date <date>, update_date_including_text <date>, url <chr>
By default, this returns the 20 most recently updated bills across
all chambers and types. Narrow the scope with the congress
and type
arguments:
bills_118 <- cong_bill(congress = 118, type = 'hr', limit = 5)
bills_118
#> # A tibble: 5 × 11
#> congress latest_action_action_date latest_action_text number origin_chamber
#> <chr> <date> <chr> <chr> <chr>
#> 1 118 2025-01-06 Became Public Law No… 4984 House
#> 2 118 2025-01-05 Became Public Law No… 82 House
#> 3 118 2025-01-04 Became Public Law No… 9775 House
#> 4 118 2025-01-04 Became Public Law No… 9600 House
#> 5 118 2025-01-04 Became Public Law No… 9592 House
#> # ℹ 6 more variables: origin_chamber_code <chr>, title <chr>, type <chr>,
#> # update_date <date>, update_date_including_text <date>, url <chr>
The result is a tibble
with sponsor, title, dates,
latest action, and other details. Each row represents a single bill,
with a summary of its most recent action.
To inspect a specific bill by number:
hr1 <- cong_bill(congress = 118, type = 'hr', number = 1)
hr1
#> # A tibble: 1 × 36
#> actions_count actions_url amendments_count amendments_url cbo_cost_estimates
#> <int> <chr> <int> <chr> <list>
#> 1 93 https://api.… 37 https://api.c… <list [2]>
#> # ℹ 31 more variables: committees_count <int>, committees_url <chr>,
#> # congress <int>, constitutional_authority_statement_text <chr>,
#> # cosponsors_count <int>,
#> # cosponsors_count_including_withdrawn_cosponsors <int>,
#> # cosponsors_url <chr>, introduced_date <date>,
#> # latest_action_action_date <date>, latest_action_action_time <chr>,
#> # latest_action_text <chr>, legislation_url <chr>, number <chr>, …
Each bill can have multiple related pieces of information, including
actions, amendments, committees, cosponsors, related bills, subjects,
summaries, text (for the full text), and titles. Access each of these
with the item
argument:
actions <- cong_bill(congress = 118, type = 'hr', number = 1, item = 'actions')
actions
#> # A tibble: 20 × 16
#> action_code action_date action_time source_system_code source_system_name
#> <chr> <date> <chr> <chr> <chr>
#> 1 H38900 2023-03-30 11:47:06 2 House floor actions
#> 2 H38310 2023-03-30 11:47:05 2 House floor actions
#> 3 H37100 2023-03-30 11:47:03 2 House floor actions
#> 4 8000 2023-03-30 11:47:03 9 Library of Congress
#> 5 H36210 2023-03-30 11:40:22 2 House floor actions
#> 6 H8A000 2023-03-30 11:34:01 2 House floor actions
#> 7 H36200 2023-03-30 11:33:36 2 House floor actions
#> 8 H34400 2023-03-30 11:32:43 2 House floor actions
#> 9 H35000 2023-03-30 11:32:27 2 House floor actions
#> 10 H32600 2023-03-30 11:32:12 2 House floor actions
#> 11 H8D000 2023-03-30 10:18:08 2 House floor actions
#> 12 H8D000 2023-03-30 10:15:32 2 House floor actions
#> 13 H8D000 2023-03-30 10:07:33 2 House floor actions
#> 14 H8D000 2023-03-30 10:05:22 2 House floor actions
#> 15 H8D000 2023-03-30 09:58:46 2 House floor actions
#> 16 H8D000 2023-03-30 09:57:25 2 House floor actions
#> 17 H8D000 2023-03-30 09:49:16 2 House floor actions
#> 18 H8D000 2023-03-30 09:40:31 2 House floor actions
#> 19 H8D000 2023-03-30 09:34:18 2 House floor actions
#> 20 H8D000 2023-03-30 09:31:51 2 House floor actions
#> # ℹ 11 more variables: text <chr>, type <chr>, recorded_votes_chamber <chr>,
#> # recorded_votes_congress <chr>, recorded_votes_date <dttm>,
#> # recorded_votes_roll_number <chr>, recorded_votes_session_number <chr>,
#> # recorded_votes_url <chr>, committees_name <chr>,
#> # committees_system_code <chr>, committees_url <chr>
This returns a tibble
of all actions taken on the bill,
including dates and descriptions.
cosponsors <- cong_bill(congress = 118, type = 'hr', number = 1, item = 'cosponsors')
cosponsors
#> # A tibble: 20 × 11
#> bioguide_id district first_name full_name is_original_cosponsor last_name
#> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 M001159 5 Cathy "Rep. McMorr… TRUE Rodgers
#> 2 W000821 4 Bruce "Rep. Wester… TRUE Westerman
#> 3 G000546 6 SAM "Rep. Graves… TRUE GRAVES
#> 4 S001196 21 Elise "Rep. Stefan… FALSE Stefanik
#> 5 G000577 6 Garret "Rep. Graves… FALSE Graves
#> 6 M001204 9 Daniel "Rep. Meuser… FALSE Meuser
#> 7 M001177 5 Tom "Rep. McClin… FALSE McClinto…
#> 8 F000465 3 A. "Rep. Fergus… FALSE Ferguson
#> 9 B000825 3 Lauren "Rep. Boeber… FALSE Boebert
#> 10 J000302 13 John "Rep. Joyce,… FALSE Joyce
#> 11 C001114 3 John "Rep. Curtis… FALSE Curtis
#> 12 A000377 0 Kelly "Rep. Armstr… FALSE Armstrong
#> 13 L000566 5 Robert "Rep. Latta,… FALSE Latta
#> 14 A000372 12 Rick "Rep. Allen,… FALSE Allen
#> 15 P000048 11 August "Rep. Pfluge… FALSE Pfluger
#> 16 D000628 2 Neal "Rep. Dunn, … FALSE Dunn
#> 17 C001103 1 Earl "Rep. Carter… FALSE Carter
#> 18 C001120 2 Dan "Rep. Crensh… FALSE Crenshaw
#> 19 B001306 12 Troy "Rep. Balder… FALSE Balderson
#> 20 B001248 26 Michael "Rep. Burges… FALSE Burgess
#> # ℹ 5 more variables: middle_name <chr>, party <chr>, sponsorship_date <date>,
#> # state <chr>, url <chr>
Other types of actions taken by Congress can be accessed through
other endpoints. For example, to focus on amendments, use
cong_amendment()
.
amendments <- cong_amendment(congress = 118, limit = 50)
amendments
#> # A tibble: 50 × 10
#> congress description latest_action_action…¹ latest_action_action…²
#> <chr> <chr> <date> <chr>
#> 1 118 "An amendment numbere… 2023-01-26 14:00:19
#> 2 118 "An amendment numbere… 2023-01-26 17:39:08
#> 3 118 "An amendment numbere… 2023-01-26 17:42:24
#> 4 118 "An amendment numbere… 2023-01-26 17:35:50
#> 5 118 "An amendment numbere… 2023-01-26 17:46:05
#> 6 118 "An amendment numbere… 2023-01-26 17:31:18
#> 7 118 "An amendment numbere… 2023-01-26 14:37:00
#> 8 118 "An amendment numbere… 2023-01-26 14:40:15
#> 9 118 "An amendment numbere… 2023-01-26 14:42:47
#> 10 118 "An amendment numbere… 2023-01-26 14:46:58
#> # ℹ 40 more rows
#> # ℹ abbreviated names: ¹latest_action_action_date, ²latest_action_action_time
#> # ℹ 6 more variables: latest_action_text <chr>, number <chr>, type <chr>,
#> # update_date <dttm>, url <chr>, purpose <chr>
Or target a specific one. We do this by specifying that we want the Senate Amendment 2137 from the 117th Congress:
amend_detail <- cong_amendment(congress = 117, type = 'samdt', number = 2137)
amend_detail
#> # A tibble: 1 × 27
#> actions_count actions_url amended_bill_congress amended_bill_number
#> <int> <chr> <int> <chr>
#> 1 18 https://api.congress.… 117 3684
#> # ℹ 23 more variables: amended_bill_origin_chamber <chr>,
#> # amended_bill_origin_chamber_code <chr>, amended_bill_title <chr>,
#> # amended_bill_type <chr>, amended_bill_update_date_including_text <date>,
#> # amended_bill_url <chr>, amendments_to_amendment_count <int>,
#> # amendments_to_amendment_url <chr>, chamber <chr>, congress <int>,
#> # cosponsors_count <int>,
#> # cosponsors_count_including_withdrawn_cosponsors <int>, …
cong_member()
helps link individual lawmakers to
legislative behavior. Use the bioguide
argument to target a
specific member.
sponsored <- cong_member(bioguide = 'W000817', item = 'sponsored-legislation')
sponsored
#> # A tibble: 20 × 10
#> amendment_number congress introduced_date url latest_action_action…¹
#> <chr> <chr> <date> <chr> <date>
#> 1 3544 119 2025-08-01 https://api… NA
#> 2 3526 119 2025-08-01 https://api… NA
#> 3 3527 119 2025-08-01 https://api… NA
#> 4 3524 119 2025-08-01 https://api… NA
#> 5 3525 119 2025-08-01 https://api… NA
#> 6 <NA> 119 2025-07-28 https://api… 2025-07-28
#> 7 <NA> 119 2025-07-17 https://api… 2025-07-17
#> 8 2895 119 2025-07-16 https://api… NA
#> 9 <NA> 119 2025-07-16 https://api… 2025-07-16
#> 10 <NA> 119 2025-07-08 https://api… 2025-07-08
#> 11 2414 119 2025-06-29 https://api… 2025-06-30
#> 12 <NA> 119 2025-06-26 https://api… 2025-06-26
#> 13 2396 119 2025-06-29 https://api… NA
#> 14 2400 119 2025-06-29 https://api… NA
#> 15 2399 119 2025-06-29 https://api… NA
#> 16 2398 119 2025-06-29 https://api… NA
#> 17 2395 119 2025-06-29 https://api… NA
#> 18 2397 119 2025-06-29 https://api… NA
#> 19 2392 119 2025-06-29 https://api… NA
#> 20 2393 119 2025-06-29 https://api… NA
#> # ℹ abbreviated name: ¹latest_action_action_date
#> # ℹ 5 more variables: latest_action_text <chr>, number <chr>, title <chr>,
#> # type <chr>, policy_area_name <chr>
This returns all legislation introduced by Senator Elizabeth Warren
in the 118th Congress. The endpoint tracks various components of a
member of Congress’s work, such as
cosponsored-legislation
.
To look up bioguide information, there is an official site: https://bioguide.congress.gov/.
Responses from cong_member()
also include bioguide IDs, so
you can use them to cross-reference with other datasets.
A significant portion of work in Congress is conducted by committee.
We can use cong_committee()
to access committee
information:
committees <- cong_committee(congress = 118)
committees
#> # A tibble: 20 × 10
#> chamber committee_type_code name system_code update_date url
#> <chr> <chr> <chr> <chr> <dttm> <chr>
#> 1 Joint Joint Joint Eco… jhje00 2025-05-16 20:39:59 http…
#> 2 Joint Commission or Caucus Congressi… jcpk00 2025-02-24 16:33:20 http…
#> 3 House Select Select Su… hlfd00 2025-01-04 11:54:09 http…
#> 4 House Subcommittee Select Su… hlvc00 2025-01-04 11:53:18 http…
#> 5 House Task Force Task Forc… htzt00 2025-01-04 11:38:24 http…
#> 6 Senate Standing Veterans'… ssva00 2025-01-03 20:48:25 http…
#> 7 Senate Standing Rules and… ssra00 2025-01-03 20:48:25 http…
#> 8 Senate Standing Small Bus… sssb00 2025-01-03 20:48:25 http…
#> 9 Senate Subcommittee Governmen… ssga22 2025-01-03 20:48:24 http…
#> 10 Senate Subcommittee Criminal … ssju22 2025-01-03 20:48:24 http…
#> 11 Senate Subcommittee Privacy, … ssju28 2025-01-03 20:48:24 http…
#> 12 Senate Subcommittee Competiti… ssju01 2025-01-03 20:48:24 http…
#> 13 Senate Subcommittee Primary H… sshr12 2025-01-03 20:48:24 http…
#> 14 Senate Subcommittee Immigrati… ssju04 2025-01-03 20:48:24 http…
#> 15 Senate Subcommittee Intellect… ssju26 2025-01-03 20:48:24 http…
#> 16 Senate Standing Health, E… sshr00 2025-01-03 20:48:24 http…
#> 17 Senate Subcommittee Constitut… ssju21 2025-01-03 20:48:24 http…
#> 18 Senate Subcommittee Human Rig… ssju27 2025-01-03 20:48:24 http…
#> 19 Senate Subcommittee Employmen… sshr11 2025-01-03 20:48:24 http…
#> 20 Senate Subcommittee Children … sshr09 2025-01-03 20:48:24 http…
#> # ℹ 4 more variables: parent_name <chr>, parent_system_code <chr>,
#> # parent_url <chr>, subcommittees <list>
To get reports or prints from a committee, use the corresponding functions:
reports <- cong_committee_report(congress = 118, limit = 5)
reports
#> # A tibble: 5 × 8
#> chamber citation congress number part type update_date url
#> <chr> <chr> <chr> <chr> <chr> <chr> <dttm> <chr>
#> 1 House H. Rept. 118-578 118 578 1 HRPT 2025-07-31 16:27:30 http…
#> 2 House H. Rept. 118-555 118 555 1 HRPT 2025-07-31 16:27:30 http…
#> 3 House H. Rept. 118-553 118 553 1 HRPT 2025-07-09 16:27:30 http…
#> 4 House H. Rept. 118-6 118 6 1 HRPT 2025-05-27 14:16:55 http…
#> 5 House H. Rept. 118-203 118 203 1 HRPT 2025-05-27 14:16:54 http…
prints <- cong_committee_print(congress = 118, limit = 5)
prints
#> # A tibble: 5 × 5
#> chamber congress jacket_number update_date url
#> <chr> <chr> <chr> <dttm> <chr>
#> 1 Senate 118 56851 2025-08-19 13:58:18 https://api.congress.gov/v…
#> 2 Senate 118 58130 2025-08-13 13:43:16 https://api.congress.gov/v…
#> 3 Senate 118 57824 2025-08-01 15:28:19 https://api.congress.gov/v…
#> 4 Senate 118 57664 2025-06-23 14:28:19 https://api.congress.gov/v…
#> 5 House 118 50700 2025-06-11 21:58:14 https://api.congress.gov/v…
To gather hearing metadata, use cong_hearing()
:
hearings <- cong_hearing(congress = 118, limit = 5)
hearings
#> # A tibble: 5 × 6
#> chamber congress jacket_number number update_date url
#> <chr> <chr> <chr> <chr> <dttm> <chr>
#> 1 Senate 118 58988 582 2025-08-30 01:21:17 https://api.congres…
#> 2 Senate 118 60121 626 2025-08-29 01:34:15 https://api.congres…
#> 3 Senate 118 57774 524 2025-08-29 01:21:16 https://api.congres…
#> 4 Senate 118 55897 335 2025-08-28 01:21:16 https://api.congres…
#> 5 House 118 50897 <NA> 2025-08-27 01:36:18 https://api.congres…
The results can be refined by chamber or hearing number.
Track presidential nominations with
cong_nomination()
:
noms <- cong_nomination(congress = 118, limit = 50)
noms
#> # A tibble: 50 × 12
#> citation congress description latest_action_action…¹ latest_action_text
#> <chr> <chr> <chr> <date> <chr>
#> 1 PN112 118 Samuel H. Slater… 2025-01-03 Returned to the P…
#> 2 PN870 118 J. Todd Inman, o… 2024-03-08 Confirmed by the …
#> 3 PN113 118 Samuel H. Slater… 2025-01-03 Returned to the P…
#> 4 PN9 118 Phillip A. Washi… 2023-03-30 Received message …
#> 5 PN672 118 Brendan Carr, of… 2023-09-30 Confirmed by the …
#> 6 PN799 118 Andrew N. Fergus… 2024-03-07 Confirmed by the …
#> 7 PN482 118 Douglas Dziak, o… 2024-03-07 Confirmed by the …
#> 8 PN304 118 Rebecca Kelly Sl… 2024-03-07 Confirmed by the …
#> 9 PN673 118 Anna M. Gomez, o… 2023-09-07 Confirmed by the …
#> 10 PN800 118 Andrew N. Fergus… 2024-03-07 Confirmed by the …
#> # ℹ 40 more rows
#> # ℹ abbreviated name: ¹latest_action_action_date
#> # ℹ 7 more variables: nomination_type_is_civilian <chr>, number <chr>,
#> # organization <chr>, part_number <chr>, received_date <date>,
#> # update_date <dttm>, url <chr>
Each row includes name, post, and status (e.g., confirmed, withdrawn).
To go deeper into an individual nomination, such as Val Deming’s nomination to the Postal Service Board of Governors, use:
nom_details <- cong_nomination(congress = 118, number = 2005)
nom_details
#> # A tibble: 1 × 18
#> actions_count actions_url authority_date citation committees_count
#> <int> <chr> <date> <chr> <int>
#> 1 6 https://api.congress.g… 2025-05-12 PN2005 1
#> # ℹ 13 more variables: committees_url <chr>, congress <int>, description <chr>,
#> # hearings_count <int>, hearings_url <chr>, latest_action_action_date <date>,
#> # latest_action_text <chr>, nomination_type_is_civilian <lgl>,
#> # nominees <list>, number <int>, part_number <chr>, received_date <date>,
#> # update_date <dttm>
Use cong_daily_record()
to access floor proceedings:
record <- cong_daily_record(volume = 169, issue = 1)
record
#> # A tibble: 1 × 8
#> congress full_issue issue_date issue_number session_number
#> <int> <list> <dttm> <chr> <int>
#> 1 118 <tibble [6 × 8]> 2023-01-03 05:00:00 1 1
#> # ℹ 3 more variables: update_date <dttm>, url <chr>, volume_number <int>
To view specific speeches or statements:
congress
provides programmatic access to a rich set of
legislative data. This package aims to enable reproducible workflows for
research on Congress. The functions in this package offer a structured
and consistent interface to the Congress.gov API.
For more detail, consult the function reference at https://christophertkenny.com/congress/. If you encounter edge cases or undocumented behavior, consider opening an issue.
DISCLAIMER: This vignette has been written with help from ChatGPT 4o. It has been reviewed for correctness and edited for clarity by the package author. Please note any issues at https://github.com/christopherkenny/congress/issues.