DEV Community

Fatih İlhan
Fatih İlhan

Posted on

House Stock Watcher and Senate Stock Watcher are down: what to use instead (2026)

If your congress-trades feature stopped working, you're not alone. House Stock Watcher and Senate Stock Watcher were the default free source for STOCK Act trade data for years, and a lot of projects still point at them. They are no longer usable:

Source Status (checked Oct 2026)
house-stock-watcher-data.s3-us-west-2.amazonaws.com 403 Forbidden
senate-stock-watcher-data.s3-us-west-2.amazonaws.com 403 Forbidden
housestockwatcher.com, senatestockwatcher.com (incl. /api) Domain doesn't resolve
raw.githubusercontent.com/timothycarambat/senate-stock-watcher-data/... Still responds, but last commit was March 2021. Using it gives you 5-year-old data with no error message

The last one is the dangerous case. I found several projects that use the GitHub mirror as a "fallback". That fallback never fails, so nobody notices the data stopped in 2021.

You can check the others yourself:

curl -I https://house-stock-watcher-data.s3-us-west-2.amazonaws.com/data/all_transactions.json
# HTTP/1.1 403 Forbidden
Enter fullscreen mode Exit fullscreen mode

Below are your options, from free-but-work to paid-but-easy.

Disclosure: I build one of the options below (option 3). I've tried to list the others fairly.

Option 1: Parse the official sources yourself (free)

All of this data comes from two government sites:

  • House: the House Clerk Financial Disclosure site publishes a yearly ZIP with an XML index of every filing ({year}FD.zip). Periodic Transaction Reports (PTRs) are PDFs at /public_disc/ptr-pdfs/{year}/{doc_id}.pdf.
  • Senate: Senate eFD has a search UI. You must accept its terms, and it uses a session and CSRF token. Electronic PTRs are HTML tables. Paper filings are scanned images.

The catch is that the House side is PDF parsing. Most PTRs have a text layer, but the layout varies:

  • amounts can be split across lines
  • some filings list exchanges
  • around 14% of recent House PTRs are scanned images with no text at all

A naive regex parser silently drops a lot of rows. Mine dropped almost half of them before I caught it. If you go this route, count filings in vs. rows out, and log the filings that produce zero rows.

Good fit: you want full control and don't mind maintaining a parser.

Option 2: Commercial APIs and sites

Several services sell this data, including Quiver Quantitative, Unusual Whales, Capitol Trades (web UI) and some general market-data APIs that have congress endpoints. They're polished, but check two things before you integrate:

  1. Pricing and rate limits for the volume you need.
  2. Commercial-use terms. Federal law (5 U.S.C. §13107(c)) restricts some commercial uses of these disclosure reports, and vendors handle that differently.

Good fit: you need a dashboard or many extra datasets, and the price works for you.

Option 3: Hosted feeds on Apify (pay per row)

I maintain two Apify actors that parse the official House and Senate sources into one clean JSON schema:

What you get:

  • One schema for both chambers, with member_bioguide_id on each row so you can join to other congress data
  • Filters: member (nickname-aware), ticker, filing-date window, transaction-date range
  • No silent drops: filings that can't be parsed (scanned or failed) come back as placeholder rows with a parse_status, instead of disappearing
  • Amendment handling: filing_type, supersedes_filing_id, is_superseded
  • Pricing: $2 per 1,000 rows (House) and $3 per 1,000 rows (Senate). Apify's free plan includes monthly credit, which covers a typical weekly pull.

Python example:

from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")

run = client.actor("seralifatih/congress-trading-pipeline-1").call(
    run_input={"fetchDaysBack": 30, "tickers": ["NVDA", "MSFT"]}
)

for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["transaction_date"], row["politician"], row["ticker"],
          row["type"], row["amount_min"], row["amount_max"])
Enter fullscreen mode Exit fullscreen mode

Migrating from Stock Watcher fields

If your code expects the old Stock Watcher JSON, the mapping is mostly direct:

Stock Watcher This schema Note
representative / senator politician normalized name; raw name in politician_raw
transaction_date transaction_date ISO YYYY-MM-DD
disclosure_date filing_date
ticker ticker empty when the filing has none
asset_description asset_name
type (purchase, sale_full, …) type buy / sell / exchange
amount ("$1,001 - $15,000") amount_min, amount_max already numeric
owner owner self / spouse / joint / child
ptr_link pdf_url House

Good fit: you want the old "just give me JSON" experience without maintaining a parser.

Option 4: Just need history? Free 2025 snapshot

If you only need a fixed dataset for backtesting or analysis, I published every 2025 House and Senate trade as a free CSV/Parquet file. It has 8,462 rows, 127 members, and the same schema as option 3:

import pandas as pd
df = pd.read_parquet("hf://datasets/seralifatih/us-congress-stock-trades-2025/us_congress_trades_2025.parquet")
Enter fullscreen mode Exit fullscreen mode

One finding from that data: about 12% of 2025 trades were disclosed more than 45 days after the trade, which is past the STOCK Act deadline. If your strategy assumes disclosures arrive on time, check that assumption.

Quick checklist if your feature broke

  1. Search your code for stock-watcher, stockwatcher.com and timothycarambat.
  2. Remove any "fallback" to the GitHub mirror. It hides the outage.
  3. Pick an option above and update the field mapping.
  4. Add a freshness check: alert if the newest filing_date is more than ~7 days old.

If you know another working source, leave a comment and I'll add it to the list.

Top comments (0)