# FEC Campaign Finance Scraper (`automation-lab/fec-candidates-campaign-finance`) Actor

Search official OpenFEC candidates, committees, filings, receipts, disbursements, and finance summaries for recurring campaign research.

- **URL**: https://apify.com/automation-lab/fec-candidates-campaign-finance.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.96 / 1,000 item extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## FEC Campaign Finance Scraper

Export official FEC campaign finance data from OpenFEC as clean, integration-ready dataset records.
Search candidates and committees, retrieve filings, inspect itemized receipts and disbursements, or compare candidate and committee finance summaries across election cycles.

The Actor uses the official Federal Election Commission API.
Every result includes the complete source record plus normalized fields for spreadsheets, databases, dashboards, and recurring research.

### What can this FEC campaign finance scraper do?

- Look up federal candidates by name or FEC candidate ID.
- Search committees and PACs by name or committee ID.
- Export official campaign filings for selected candidates or committees.
- Retrieve itemized Schedule A receipts and contributions.
- Retrieve itemized Schedule B disbursements.
- Export candidate or committee totals, including receipts, spending, and cash on hand.
- Filter by election cycle and bounded transaction dates.
- Stop at an exact `maxItems` limit and deduplicate source records.
- Preserve the complete OpenFEC response under `data` for advanced analysis.

### Who is it for?

**Political researchers** use it to build auditable candidate and committee datasets.

**Journalists** use it to inspect filings, contributions, spending, and campaign totals.

**Compliance teams** use scheduled runs to collect source-backed records for review.

**Civic data teams** use normalized output instead of maintaining OpenFEC pagination code.

**Developers and analysts** connect the dataset to Python, JavaScript, SQL, Google Sheets, or BI tools.

### Why use the Actor instead of calling OpenFEC directly?

OpenFEC is already an excellent public source.
This Actor adds an input form, validation, bounded pagination, transient retries, deduplication, normalized fields, Apify datasets, scheduling, webhooks, API access, and MCP access.

It does not replace or obscure the source.
Each row includes a FEC URL and the complete returned record.

No browser or proxy is used.
That keeps runs lightweight and makes API failures explicit rather than silently returning empty output.

### What FEC data is extracted?

| Record type | Typical fields |
| --- | --- |
| `candidate` | candidate ID, name, party, office, state, active cycles |
| `committee` | committee ID, name, designation, type, party, candidate IDs |
| `filing` | filing ID, committee, form/report type, coverage dates, totals |
| `receipt` | contributor, amount, date, employer, occupation, memo, committee |
| `disbursement` | payee, amount, date, purpose, category, committee |
| `candidate_summary` | cycle totals, receipts, disbursements, cash on hand |
| `committee_summary` | cycle totals, receipts, spending, debts, cash on hand |

Fields vary by OpenFEC record type.
Normalized properties may be absent when the upstream record does not contain that concept.
The `data` object preserves all source fields.

### How to run an FEC candidate lookup

1. Open the Actor input page.
2. Select `Candidates` as the record type.
3. Enter a name such as `Bernie Sanders`.
4. Choose a small `maxItems` value for the first run.
5. Click **Start**.
6. Open the default dataset to inspect or export results.

Example input:

```json
{
  "recordType": "candidate",
  "query": "Bernie Sanders",
  "maxItems": 5
}
```

This query currently returns official candidate identities including `P60007168`.

### Input parameters

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `recordType` | string | Yes | Candidate, committee, filing, receipt, disbursement, or a finance summary. |
| `query` | string | By mode | Candidate or committee name search. |
| `candidateIds` | string\[] | By mode | Exact nine-character FEC candidate IDs. |
| `committeeIds` | string\[] | By mode | Exact nine-character FEC committee IDs. |
| `cycle` | integer | No | Even election-cycle year from 1976 onward. |
| `minDate` | string | Transactions | Start date in `MM/DD/YYYY` format. |
| `maxDate` | string | Transactions | End date in `MM/DD/YYYY` format. |
| `apiKey` | string | No | Data.gov API key for higher limits; stored as a secret input. |
| `maxItems` | integer | No | Maximum unique rows, from 1 to 10,000. |

Candidate searches require `query` or `candidateIds`.
Committee searches require `query` or `committeeIds`.
Filings require at least one candidate or committee ID.
Receipts and disbursements require committee IDs and both transaction dates.
Summary modes require IDs for the selected entity.

### Output example

A candidate lookup produces rows like this abbreviated real record:

```json
{
  "recordType": "candidate",
  "sourceId": "P60007168",
  "sourceUrl": "https://www.fec.gov/data/candidate/P60007168/",
  "name": "SANDERS, BERNARD",
  "candidateId": "P60007168",
  "party": "DEM",
  "office": "P",
  "state": "US",
  "retrievedAt": "2026-08-28T20:20:00.000Z",
  "data": {
    "candidate_id": "P60007168",
    "name": "SANDERS, BERNARD",
    "office": "P",
    "party": "DEM"
  }
}
```

Export dataset rows as JSON, CSV, Excel, XML, RSS, or JSONL using Apify's dataset endpoints.

### How much does it cost to export FEC campaign finance records?

Pricing uses one small start event plus one `item` event for each accepted dataset row.
Rejected, duplicate, or failed records are not charged as items.

The exact tier applicable to your account is displayed by Apify before a run.
At the current Bronze configuration, the start fee is **$0.00005** and 100 records cost about **$0.16005** in Actor charges.
A 1,000-record run costs about **$1.60005** at that tier.
Higher usage tiers have lower per-record prices.

Apify platform compute is accounted for by the pay-per-event price.
A personal Data.gov key is free to obtain from Data.gov and is not sold by this Actor.

### Candidate, committee, and filing workflows

Use a name search first to discover official IDs.
Then use those stable IDs in filing or summary runs.

A repeatable workflow can be:

1. Search a candidate name.
2. Save the returned candidate ID.
3. Retrieve candidate summaries by cycle.
4. Find associated committee IDs in the complete source data.
5. Export filings for selected committees.
6. Schedule the same inputs and compare datasets over time.

For receipts or disbursements, keep date ranges narrow.
This improves API response time and reduces the chance of upstream query timeouts.

### Scheduling and monitoring

Create an Apify Task from a tested input.
Set a daily, weekly, or monthly schedule.
Use a webhook to notify a data pipeline after successful runs.

The Actor exports snapshots; it does not itself calculate changes or send alerts.
Compare stable `sourceId` values and source fields between scheduled datasets to identify new or changed records.

### Use from the Apify API with cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~fec-candidates-campaign-finance/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"recordType":"candidate_summary","candidateIds":["P60007168"],"maxItems":20}'
```

For production systems, send the Apify token in an authorization header rather than storing it in source code.
Poll the returned run ID or use a webhook to wait for completion.

### Use from JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/fec-candidates-campaign-finance').call({
  recordType: 'filing',
  committeeIds: ['C00577130'],
  cycle: 2020,
  maxItems: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Use from Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/fec-candidates-campaign-finance').call(run_input={
    'recordType': 'committee_summary',
    'committeeIds': ['C00577130'],
    'maxItems': 20,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with MCP and AI assistants

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/fec-candidates-campaign-finance"
```

#### Claude Desktop, Cursor, and VS Code MCP setup

Use this JSON configuration in Claude Desktop, Cursor, or VS Code:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/fec-candidates-campaign-finance"
    }
  }
}
```

MCP example prompts:

**Example prompt:** “Use the FEC Campaign Finance Scraper MCP tool to look up candidates named Bernie Sanders and return their IDs and election cycles.”

- “Using MCP, run the Actor to export 2020 filings for committee C00577130 and summarize the report types.”
- “Call the campaign-finance MCP tool for candidate P60007168 and compare receipts with disbursements.”

### Data.gov API keys and rate limits

If `apiKey` is omitted, the Actor loads the current public API configuration from the official FEC data site and uses its browser-facing OpenFEC key. This avoids relying on the globally shared, low-quota `DEMO_KEY`.

For higher-volume recurring jobs, request a free Data.gov API key and provide it in the secret `apiKey` field.
The Actor redacts the key from request logs.
Keys belong in Actor inputs or secure Task configuration, never in README files or code.

Transient 429 and 5xx responses are retried twice with bounded backoff.
Persistent quota, authorization, or upstream errors fail the run with a non-zero status.

### Limits and failure behavior

- OpenFEC controls source freshness, coverage, and field definitions.
- A successful no-result query produces an empty dataset.
- Invalid IDs, dates, cycles, modes, and missing mode-specific filters fail before extraction.
- Transaction queries must include a committee and bounded date range.
- The Actor does not infer donor identity or merge people with similar names.
- The Actor does not bypass redactions made by the FEC.
- The Actor does not provide legal compliance advice.
- `maxItems` is capped at 10,000 per run.
- Large OpenFEC queries can time out upstream even when the Actor is healthy.

### Responsible use and legal considerations

FEC records are official public government data.
Use them for lawful research, journalism, compliance, civic analysis, and public-interest work.

Campaign-finance records can contain names, addresses, occupations, and employers.
Apply applicable privacy, data-retention, security, and fair-use requirements.
Do not use the output for harassment, identity theft, unlawful discrimination, or unsupported allegations.
Always verify consequential conclusions against the linked FEC source and current law.

### Troubleshooting

**The run failed with HTTP 429.**
The current official FEC public key can still enforce upstream limits. Provide your own Data.gov API key, reduce concurrent scheduled runs, or retry after the quota window resets.

**A transaction request timed out.**
Use a smaller date range, one committee per run, and a lower `maxItems` value.

**The dataset is empty.**
Check the official ID, election cycle, and date range on fec.gov.
An empty result can be valid when no matching source records exist.

**The Actor rejects my ID.**
Use the nine-character ID shown by FEC, such as `P60007168` or `C00577130`.

**Some normalized fields are missing.**
Different OpenFEC collections expose different fields.
Inspect the complete `data` object for source-specific values.

### FAQ

#### Does the Actor scrape web pages?

No.
It calls the official OpenFEC JSON API directly.

#### Does it require a proxy?

No.
No proxy option or automatic proxy fallback is enabled.

#### Can it export all receipts for every committee?

The current product is intentionally query-driven.
Provide committee IDs and dates, then use scheduled or partitioned runs for large research projects.

#### Are election cycles included?

Yes when OpenFEC exposes them.
Candidate records preserve their `cycles` array in `data`, while summary and transaction rows expose normalized cycle fields where available.

#### Are all outputs charged separately?

No.
There is one `item` event for every accepted row, regardless of record type.
The complete source object does not incur a separate event.

#### Can I use the data in Google Sheets?

Yes.
Export CSV or Excel from the dataset, or connect Apify to Google Sheets through an integration or webhook workflow.

### Related Actors

This Actor is currently positioned as a standalone official FEC research tool.
No existing Automation Lab Actor provides a directly adjacent workflow that would improve the supported buyer journey without creating a misleading cross-link.

For general Apify integrations, use dataset exports, schedules, webhooks, Make, Zapier, JavaScript, Python, or MCP.

# Actor input Schema

## `recordType` (type: `string`):

The OpenFEC record collection to export.

## `query` (type: `string`):

Candidate or committee name to search. Used by candidate and committee record types.

## `candidateIds` (type: `array`):

Official FEC candidate IDs, such as P60007168.

## `committeeIds` (type: `array`):

Official FEC committee IDs, such as C00577130.

## `cycle` (type: `integer`):

Optional even-numbered FEC election cycle year.

## `minDate` (type: `string`):

Required for receipt and disbursement searches. Format MM/DD/YYYY.

## `maxDate` (type: `string`):

Required for receipt and disbursement searches. Format MM/DD/YYYY.

## `apiKey` (type: `string`):

Optional Data.gov key for higher OpenFEC limits. If omitted, the Actor loads the current browser-facing public key from the official FEC data site.

## `maxItems` (type: `integer`):

Stop after this many unique records.

## Actor input object example

```json
{
  "recordType": "candidate",
  "query": "Bernie Sanders",
  "candidateIds": [],
  "committeeIds": [],
  "maxItems": 20
}
```

# Actor output Schema

## `overview` (type: `string`):

Open the default dataset using the overview view.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "recordType": "candidate",
    "query": "Bernie Sanders",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/fec-candidates-campaign-finance").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "recordType": "candidate",
    "query": "Bernie Sanders",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/fec-candidates-campaign-finance").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "recordType": "candidate",
  "query": "Bernie Sanders",
  "maxItems": 20
}' |
apify call automation-lab/fec-candidates-campaign-finance --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/fec-candidates-campaign-finance"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ly0rmXjeJjNZnQ93R/builds/pSgTiHbdOqj3v08qY/openapi.json
