Spaces:
Running on CPU Upgrade
sidebar_position: 7
FEC Campaign Finance Integration
Track political contributions and campaign finance data using the Federal Election Commission (FEC) via OpenFEC API and Bulk Downloads.
π― Overview
The FEC integration enables tracking of:
- Individual political contributions ($200+)
- Federal candidates (House, Senate, President)
- Political committees and PACs
- Nonprofit leadership political giving
- Donor networks in advocacy organizations
- Campaign expenditures and disbursements
Two access methods:
- OpenFEC API - Real-time queries, filtered searches (API key required)
- Bulk Downloads - Complete datasets, no rate limits (no API key needed)
This data integrates with nonprofit and contacts data to reveal political influence patterns.
π Get API Access
OpenFEC API (Real-time Queries)
1. Sign Up for Free API Key
Visit: https://api.data.gov/signup/
- Free tier: 1,000 requests/hour
- No credit card required
- Instant activation
2. Set Environment Variable
# Add to your .env file
echo 'FEC_API_KEY="your_api_key_here"' >> .env
# Or export for current session
export FEC_API_KEY="your_api_key_here"
Without an API key, you'll use DEMO_KEY (limited to 30 requests/hour).
Bulk Downloads (Complete Datasets)
No API key required! Download complete datasets directly:
Bulk Data Portal: https://www.fec.gov/data/browse-data/?tab=bulk-data
Available datasets:
- Contributions (Schedule A) - All individual contributions $200+
- Expenditures (Schedule B) - All operating expenditures
- Candidate Master - All federal candidates
- Committee Master - All PACs and committees
- Campaign Finance Totals - Summary by cycle
Format: CSV, FEC format
Update Frequency: Nightly
Historical Coverage: 1980s to present
Rate Limits: None (direct download)
When to use bulk downloads:
- Analyzing complete datasets (millions of records)
- Historical analysis across election cycles
- Offline analysis without API rate limits
- Data warehousing and archival
When to use API:
- Real-time contribution lookups
- Filtered searches (by name, employer, state)
- Incremental updates
- Web application queries
π Gold Tables Created
The FEC integration creates 4 gold tables per state:
| Table | Description | Key Fields |
|---|---|---|
| campaigns_candidates | Federal candidates in state | candidate_id, name, party, office, district |
| campaigns_committees | PACs and campaign committees | committee_id, name, type, party |
| campaigns_contributions | Individual contributions $200+ | contributor_name, employer, amount, date, recipient |
| campaigns_nonprofit_donors | Nonprofit leadership donations | ein, organization_name, contributor_name, amount |
π Quick Start
Run Demo Script
cd /home/developer/projects/open-navigator
source .venv/bin/activate
# Basic demo (using DEMO_KEY)
python examples/demo_fec_integration.py --state MA
# With your API key
export FEC_API_KEY="your_key_here"
python examples/demo_fec_integration.py --state MA --cycle 2024
# Search for specific nonprofit donors
python examples/demo_fec_integration.py --state MA --employer "Community Health"
Create Gold Tables
# Create campaign finance tables for Massachusetts
python pipeline/create_campaigns_gold_tables.py \
--state MA \
--cycle 2024 \
--max-contributions 10000
# With custom API key
python pipeline/create_campaigns_gold_tables.py \
--state MA \
--api-key "your_key_here"
π Use Cases
1. Track Nonprofit Leadership Donations
Identify politically active nonprofit officers and directors:
from pipeline.create_campaigns_gold_tables import CampaignsGoldTableCreator
creator = CampaignsGoldTableCreator(state_code="MA")
creator.create_all_campaigns_tables(cycle=2024)
# Analyzes:
# - Contributions where employer matches nonprofit name
# - Contributions from known nonprofit officers/directors
# - Political giving patterns in advocacy sector
Output: data/gold/states/MA/campaigns_nonprofit_donors.parquet
2. Map Donor Networks
Find connections between organizations and political campaigns:
from discovery.fec_integration import OpenFECAPI
api = OpenFECAPI(api_key="your_key")
# Search for contributions from health sector
result = api.search_individual_contributions(
contributor_state="MA",
contributor_employer="Health",
min_amount=1000
)
for contrib in result['results']:
print(f"{contrib['contributor_name']} ({contrib['contributor_employer']})")
print(f" β ${contrib['contribution_receipt_amount']} to {contrib['committee_name']}")
3. Analyze Political Influence on Policy
Cross-reference campaign contributions with grant awards:
import pandas as pd
# Load campaign contributions
contributions = pd.read_parquet('data/gold/states/MA/campaigns_contributions.parquet')
# Load grant data
grants = pd.read_parquet('data/gold/states/MA/grants_revenue_sources.parquet')
# Find organizations that both give politically and receive grants
donor_orgs = contributions['contributor_employer'].unique()
grant_recipients = grants['organization_name'].unique()
overlap = set(donor_orgs) & set(grant_recipients)
print(f"Organizations that both donate politically and receive grants: {len(overlap)}")
πΎ Using Bulk Downloads
For large-scale analysis, use FEC bulk downloads instead of the API:
Download Complete Datasets
# Download candidate master file (all federal candidates)
wget https://www.fec.gov/files/bulk-downloads/2024/cn24.zip
unzip cn24.zip
# Download committee master file (all PACs and committees)
wget https://www.fec.gov/files/bulk-downloads/2024/cm24.zip
unzip cm24.zip
# Download individual contributions (Schedule A)
# Warning: Very large file (100s of MB to GBs)
wget https://www.fec.gov/files/bulk-downloads/2024/indiv24.zip
unzip indiv24.zip
Process Bulk Data with Pandas
import pandas as pd
from pathlib import Path
# Load contributions for specific cycle
contributions_file = Path("data/fec/bulk/indiv24.txt")
df = pd.read_csv(
contributions_file,
sep="|",
header=None,
names=[
"CMTE_ID", "AMNDT_IND", "RPT_TP", "TRANSACTION_PGI",
"IMAGE_NUM", "TRANSACTION_TP", "ENTITY_TP", "NAME",
"CITY", "STATE", "ZIP_CODE", "EMPLOYER", "OCCUPATION",
"TRANSACTION_DT", "TRANSACTION_AMT", "OTHER_ID",
"TRAN_ID", "FILE_NUM", "MEMO_CD", "MEMO_TEXT", "SUB_ID"
],
encoding="latin1",
low_memory=False
)
# Filter to Massachusetts contributors
ma_contributions = df[df['STATE'] == 'MA']
# Filter to health sector
health_donors = ma_contributions[
ma_contributions['EMPLOYER'].str.contains('Health|Hospital|Dental', case=False, na=False)
]
print(f"Found {len(health_donors):,} health sector contributions from MA")
print(f"Total amount: ${health_donors['TRANSACTION_AMT'].sum():,.2f}")
# Save to parquet for faster future access
health_donors.to_parquet('data/gold/states/MA/campaigns_contributions.parquet')
Bulk Download File Formats
Candidate Master File (cn.txt):
- Delimiter: Pipe (
|) - Columns:
CAND_ID,CAND_NAME,CAND_PTY_AFFILIATION,CAND_ELECTION_YR,CAND_OFFICE_ST,CAND_OFFICE,CAND_OFFICE_DISTRICT, etc.
Committee Master File (cm.txt):
- Delimiter: Pipe (
|) - Columns:
CMTE_ID,CMTE_NM,TRES_NM,CMTE_CITY,CMTE_ST,CMTE_TP,CMTE_PTY_AFFILIATION, etc.
Individual Contributions (indiv.txt):
- Delimiter: Pipe (
|) - Columns:
CMTE_ID,NAME,CITY,STATE,ZIP_CODE,EMPLOYER,OCCUPATION,TRANSACTION_DT,TRANSACTION_AMT, etc. - Contains all contributions $200+ as required by law
Advantages of Bulk Downloads
β
Complete data - No pagination, no missing records
β
No rate limits - Download once, analyze forever
β
Historical data - Access to all election cycles
β
Offline analysis - No API dependency
β
Faster processing - Local files vs HTTP requests
When to Use Each Method
| Scenario | Method | Reason |
|---|---|---|
| Find specific donor | API | Filtered search, fast lookup |
| All MA contributions | Bulk Download | Complete dataset, no limits |
| Real-time updates | API | Latest filings |
| Historical analysis | Bulk Download | Multi-cycle coverage |
| Web application | API | Dynamic queries |
| Research/analysis | Bulk Download | Full data access |
π οΈ API Reference
Search Individual Contributions
from discovery.fec_integration import OpenFECAPI
api = OpenFECAPI(api_key="your_key")
# Search by contributor
result = api.search_individual_contributions(
contributor_name="Smith",
contributor_state="MA",
min_amount=200,
min_date="2023-01-01",
max_date="2024-12-31"
)
# Search by employer
result = api.search_individual_contributions(
contributor_employer="Community Foundation",
contributor_state="MA",
min_amount=1000
)
Search Candidates
# House candidates in Massachusetts
result = api.search_candidates(
state="MA",
office="H", # H=House, S=Senate, P=President
cycle=2024
)
# Senate candidates
result = api.search_candidates(
state="MA",
office="S",
party="DEM", # or "REP"
cycle=2024
)
Search Committees
# Find PACs in Massachusetts
result = api.search_committees(
state="MA",
committee_type="N" # N=PAC, Q=Super PAC
)
π Data Model Integration
Links to Nonprofit Data
The campaigns_nonprofit_donors table links FEC data to nonprofits:
-- Conceptual SQL (use pandas for actual queries)
SELECT
nd.organization_name,
nd.contributor_name,
nd.contributor_title,
SUM(nd.contribution_amount) as total_contributions,
COUNT(*) as num_contributions
FROM campaigns_nonprofit_donors nd
GROUP BY nd.organization_name, nd.contributor_name
ORDER BY total_contributions DESC;
Links to Contacts
Match contributions to nonprofit officers:
import pandas as pd
# Load data
officers = pd.read_parquet('data/gold/states/MA/contacts_nonprofit_officers.parquet')
contributions = pd.read_parquet('data/gold/states/MA/campaigns_contributions.parquet')
# Match by name
merged = officers.merge(
contributions,
left_on='officer_name',
right_on='contributor_name',
how='inner'
)
print(f"Found {len(merged)} contribution records from known nonprofit officers")
βοΈ Configuration
Environment Variables
# Required (or use DEMO_KEY)
FEC_API_KEY="your_api_key_here"
# Optional
FEC_CACHE_DIR="data/cache/fec" # Where to cache bulk downloads
Rate Limits
| API Key | Rate Limit | Notes |
|---|---|---|
| DEMO_KEY | 30 requests/hour | Shared across all users |
| Free API Key | 1,000 requests/hour | Recommended |
| Bulk Download | No limit | 1-5 GB files, use for comprehensive data |
π Advanced Usage
Bulk Data Download
For comprehensive historical analysis, download bulk files:
from discovery.fec_integration import FECBulkDataLoader
loader = FECBulkDataLoader(cache_dir="data/cache/fec")
# Download 2024 individual contributions (WARNING: 1-5 GB)
zip_path = loader.download_individual_contributions(cycle="2024")
# Parse and filter
df = loader.parse_individual_contributions(
zip_path=zip_path,
state_filter="MA",
employer_filter="Foundation",
min_amount=200
)
print(f"Found {len(df):,} contributions from MA foundations")
Custom Analysis Pipeline
Build custom analysis workflows:
from discovery.fec_integration import OpenFECAPI
import pandas as pd
api = OpenFECAPI(api_key="your_key")
# 1. Get all House candidates in MA
candidates_result = api.search_candidates(state="MA", office="H", cycle=2024)
candidates = candidates_result['results']
# 2. For each candidate, get top donors
for candidate in candidates:
candidate_id = candidate['candidate_id']
# Get candidate committees
committees_result = api.search_committees(candidate_id=candidate_id)
# Analyze fundraising
print(f"\n{candidate['name']} ({candidate['party']})")
print(f" Committees: {len(committees_result['results'])}")
π Data Quality Notes
Contribution Reporting Threshold
- FEC requires reporting for contributions $200 or more
- Smaller contributions are not itemized
- Use
min_amount=200for complete data
Employer Field
- Self-reported by contributor
- May have inconsistent formatting
- "Community Health Center" vs "Community Health Ctr"
- Use fuzzy matching for nonprofit employer analysis
Update Frequency
- FEC data updated daily
- Electronic filings appear within 24 hours
- Paper filings may take 30+ days
π Additional Resources
- OpenFEC API Docs: https://api.open.fec.gov/developers/
- FEC Bulk Data: https://www.fec.gov/data/browse-data/?tab=bulk-data
- Campaign Finance Guide: https://www.fec.gov/help-candidates-and-committees/
- Data Dictionary: https://www.fec.gov/campaign-finance-data/contributions-individuals-file-description/
π€ Related Integrations
- Nonprofit Discovery - Match employers to EINs
- IRS BMF Data - Nonprofit organization data
- Gold Table Pipeline - Full data model
π‘ Pro Tips
- Start with API, use bulk for scale: API is easier for exploration, bulk files for comprehensive analysis
- Cache aggressively: Set up
data/cache/fec/to avoid re-downloading - Match on lowercase: Employer names vary in capitalization
- Use year ranges: Contributions span multiple years, use date filters
- Join with EINs: Match FEC employer field to
nonprofits_organizations.einfor verified linkage