GovInfo Scraper: Bills, Laws & Congressional Records
Pricing
from $0.56 / 1,000 document scrapeds
GovInfo Scraper: Bills, Laws & Congressional Records
Scrape GovInfo for bills, public laws, congressional reports, hearings and the Federal Register archive. Package metadata plus direct PDF and text links.
Pricing
from $0.56 / 1,000 document scrapeds
Rating
0.0
(0)
Developer
Arman Hossain
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
20 days ago
Last modified
Categories
Share

GovInfo Scraper searches the U.S. Government Publishing Office's official repository and returns one structured row per document, congressional bills, enacted public laws, the daily Congressional Record, committee hearings and reports, the Federal Register, and federal court opinions.
Every row carries the package metadata plus direct, public links to the PDF and the full text, so you can pipe results straight into a document ingestion pipeline. Plain HTTP: no browser, no proxies, no login.
Agent skill: SKILL.md
https://api.apify.com/v2/key-value-stores/t7YoTxpZEJOWvw4Ug/records/govinfo-documents-scraper.md
What you get
| Output field | Meaning |
|---|---|
packageId | GovInfo's stable identifier, e.g. BILLS-119s5239is |
collection | Collection code the document came from (BILLS, PLAW, CREC, …) |
title | Document title, the popular short title for bills |
congress | Congress number, e.g. 119 |
billNumber, billType, docVersion | 5239, s (senate bill), is (introduced in senate) |
dateIssued, lastModified | Publication date, and when GovInfo last revised the package |
governmentAuthor | Issuing bodies, e.g. ["Congress", "Senate"] |
pdfUrl | Direct PDF on www.govinfo.gov |
textUrl | Direct full-text HTML on www.govinfo.gov |
detailsUrl | Human-readable GovInfo page for the package |
summary | The official long title, when includeDetails is on |
scrapedAt | Run timestamp |
A RUN_SUMMARY record in the key-value store holds per-collection counts, remaining API budget, the filters used, and any collection that failed.
Which source this uses, and why
GovInfo exposes more than one search surface. Two of them are undocumented routes behind the website's own navigation: one returns only facet counts with no document records, the other is internal, undocumented and rejects anything it does not expect. This Actor uses neither.
It reads the documented public API published by the Government Publishing Office,
which returns real document records with package IDs, titles, dates and download
links. That route needs an API key, which is free and arrives by email in seconds,
and it carries a far higher request budget than the undocumented ones. DEMO_KEY
works out of the box so the Run button does something useful immediately.
Common use cases
Legislative tracking for policy teams. Watch bills and enacted laws in the current Congress and diff on packageId between runs.
{"collections": ["BILLS", "PLAW"],"congress": 119,"fromDate": "2026-07-01","maxResults": 2000,"apiKey": "YOUR_FREE_KEY"}
Build a bill-monitoring alert product. Keyword-scoped, newest first, cheap enough to run hourly.
{"collections": ["BILLS"],"searchTerms": ["artificial intelligence", "algorithmic", "machine learning"],"fromDate": "2026-01-01","maxResults": 500,"apiKey": "YOUR_FREE_KEY"}
Legal research corpora. Federal court opinions and committee hearings with direct text links, ready for a downstream ingest step.
{"collections": ["USCOURTS", "CHRG"],"searchTerms": ["antitrust"],"fromDate": "2024-01-01","maxResults": 20000,"apiKey": "YOUR_FREE_KEY"}
Input
| Field | Type | Default | Notes |
|---|---|---|---|
collections | array | [] | GovInfo collection codes. Each is a separate sweep. |
congress | integer | 0 | Single Congress number. 119 = 2025-2026. 0 = all. |
searchTerms | array | [] | Full-text terms, OR-combined. Multi-word entries become exact phrases. |
fromDate | string | "" | YYYY-MM-DD lower bound on publication date. |
maxResults | integer | 500 | Global cap across collections. 0 = no cap. |
apiKey | string | DEMO_KEY | Free key from api.data.gov/signup. Stored as a secret. |
includeDetails | boolean | false | Adds summary (official long title). +1 request per document. |
You need at least one of collections, searchTerms or congress. GovInfo holds over three million documents; an entirely unfiltered search is never what anyone wants, so the Actor refuses it with a clear message rather than starting one.
Which combinations make sense. collections + fromDate is the workhorse for scheduled monitoring, results come back newest first, so maxResults gives you the most recent N. searchTerms narrows within that, and terms are OR'd, so more terms means more results, not fewer. congress only applies to congressionally-numbered collections (BILLS, PLAW, CHRG, CRPT, CDOC); date-keyed ones like FR and USCOURTS will simply return nothing if you set it. includeDetails is the one expensive option, see the note under Limits.
Output example
{"packageId": "BILLS-119s5239is","collection": "BILLS","title": "American Glove Act of 2026","congress": 119,"billNumber": "5239","billType": "s","docVersion": "is","dateIssued": "2026-08-04","lastModified": "2026-08-05T13:37:47Z","governmentAuthor": ["Congress", "Senate"],"pdfUrl": "https://www.govinfo.gov/content/pkg/BILLS-119s5239is/pdf/BILLS-119s5239is.pdf","textUrl": "https://www.govinfo.gov/content/pkg/BILLS-119s5239is/html/BILLS-119s5239is.htm","detailsUrl": "https://www.govinfo.gov/app/details/BILLS-119s5239is","summary": "To ensure that nitrile glove procurements comply with the requirements of the Make PPE in America Act, and for other purposes.","scrapedAt": "2026-08-06T12:00:00.000Z"}
Note the split between title and summary: GovInfo's search index returns the popular short title (American Glove Act of 2026), while the package record holds the official long title. With includeDetails: false you get the short title and summary is null.
RUN_SUMMARY in the key-value store:
{"sweepsRequested": 2,"sweepsFailed": 0,"failures": [],"documentsSaved": 500,"requestsUsed": 2,"rateLimited": false,"rateLimit": { "limit": 1000, "remaining": 998, "usingDemoKey": false },"filters": {"collections": ["BILLS", "PLAW"],"congress": 119,"searchTerms": ["climate"],"fromDate": "2026-01-01","maxResults": 500,"includeDetails": false},"finishedAt": "2026-08-06T12:00:06.114Z"}
Limits and behaviour
DEMO_KEYis capped at 10 requests per hour. That is enough to see the Actor work and not much else. A free key from api.data.gov/signup raises it to 1000 requests/hour, arrives by email immediately, and asks for nothing but an address. Get one before your first real run.- Documents page at 1000 per request. So on a free key, one hour of budget is roughly a million documents, as long as
includeDetailsis off. includeDetailscosts one request per document. 500 documents with details on is 500 requests, half your hourly budget, for a field you may not need. It is off by default for exactly that reason.- Congress, bill type and bill number come free. GovInfo encodes them in the package ID (
BILLS-119s5239is→ 119th Congress, senate bill 5239, introduced-in-senate version), so the Actor parses them out rather than spending a request. Date-keyed collections such asCREC-2026-08-05have no congress in the ID and reportnull. - The budget is read from every response. rate-limit headers and rate-limit headers are logged after each collection and written into
RUN_SUMMARY.rateLimit. GovInfo does not send a reset timestamp; the window is hourly. - Exhaustion stops the run cleanly. On a 429 the Actor stops, keeps everything already saved, sets
RUN_SUMMARY.rateLimited: true, and tells you where to get a bigger key. - A bad key fails fast. A 401/403 stops the run immediately rather than repeating the same rejection once per collection.
- One failing collection never aborts the run. Errors land in
RUN_SUMMARY.failuresand the next collection starts. The Actor only throws if every sweep failed. - Transient errors are retried. 5xx gets three attempts with linear backoff.
- Pagination is cursor-based. GovInfo uses an
offsetMarkcursor rather than page numbers, which is what makes deep result sets reachable at all. The Actor follows it and stops when the cursor stops advancing. - Public-record data only. Everything here is published by the U.S. Government Publishing Office for reuse; no authentication protects it and no commercial licence is required.
Finding a collection code
The code is the uppercase token in every GovInfo URL. Open a document on govinfo.gov and read the package ID:
| Package ID you see | Collection code | What it is |
|---|---|---|
BILLS-119s5239is | BILLS | Congressional bills |
PLAW-119publ102 | PLAW | Enacted public and private laws |
CREC-2026-08-05 | CREC | Daily Congressional Record |
CHRG-119hhrg58123 | CHRG | Committee hearings |
USCOURTS-ca9-20-12345 | USCOURTS | Federal court opinions |
The complete list of 42 collections is at https://api.govinfo.gov/collections?api_key=DEMO_KEY.
API example
curl -X POST "https://api.apify.com/v2/acts/arman-bd~govinfo-documents-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"collections": ["BILLS", "PLAW"],"congress": 119,"searchTerms": ["climate", "clean energy"],"fromDate": "2026-01-01","maxResults": 200,"apiKey": "YOUR_GOVINFO_KEY"}'
JavaScript example
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_TOKEN' });const run = await client.actor('arman-bd/govinfo-documents-scraper').call({collections: ['BILLS'],congress: 119,searchTerms: ['artificial intelligence'],fromDate: '2026-01-01',apiKey: 'YOUR_GOVINFO_KEY',});const { items } = await client.dataset(run.defaultDatasetId).listItems();for (const doc of items) {console.log(`${doc.dateIssued} ${doc.packageId.padEnd(22)} ${doc.title}`);console.log(` text: ${doc.textUrl}`);}
FAQ
Do I need a proxy? No. Proxy configuration is not required to run this Actor.
Do I need an account on GovInfo? No. You supply no credentials.
Can I run it without a key at all? Yes, on DEMO_KEY, which is what the Actor uses by default. It is shared across every anonymous caller and capped at 10 requests/hour, so treat it as a trial, not a plan.
Why doesn't it use the wssearch endpoint? Because it is not a document search. wssearch/rb/{collection} returns the browse navigation tree, Congress numbers and counts, no documents, and answers 405 to POST. wssearch/search is POST-only, undocumented, and rejects requests it does not recognise with an unhelpful 400. The documented api.govinfo.gov/search returns real records and is what a production Actor should depend on.
Why is summary null? Because includeDetails is off. GovInfo's search index does not return an abstract; the official long title lives on the package record, which costs an extra request per document to fetch.
Why did congress come back null? The document is from a date-keyed collection (FR, CREC, USCOURTS) whose package IDs carry a date instead of a Congress number.
What happens if GovInfo is unavailable? 5xx responses are retried three times, then that collection is recorded in RUN_SUMMARY.failures and the run continues with the next one.
Can I schedule it? Yes, it is designed for it. Set fromDate to the previous run's date and diff on packageId.
Can I integrate it with something else? Yes, Apify API, client libraries, webhooks, scheduled runs, dataset exports (JSON/CSV/Excel) or MCP. Output is structured JSON.