Skip to main content

How to Read an FEC Independent Expenditure Filing Without Getting Fooled

By LobbyVault

If you've ever clicked through an "[INDEPENDENT EXPENDITURE REPORT]" on the FEC website, you've seen the schedule E rows: dozens of entries tagged SUPPORT or OPPOSE, each one naming a candidate, a dollar amount, a purpose, and a date. The format looks simple. It isn't.

This post is a field guide to the underlying data — the same rows that populate LobbyVault's independent expenditure pages — and the three analytical mistakes that turn otherwise good campaign-finance reporting into misleading numbers.

The Key Fields

The FEC's bulk independent expenditure file (independent_expenditure.csv) has a wide schema, but the columns that matter for most reporting are:

Field What it actually means
cmte_id The spender (always a committee, usually a Super PAC)
cand_id The targeted candidate — not who benefits, see below
sup_opp S = supports candidate; O = opposes candidate
exp_amo Amount of this expenditure (gross, not net)
exp_dat Date the expenditure was disseminated
pur Free-text purpose — "media", "direct mail", etc.
pay Payee — who actually got paid (the vendor)
file_num The parent filing, useful for amendments

The sup_opp column is the single most important field and the most commonly misread.

Mistake 1: Treating "Oppose" as Hostile to the Candidate

An O (oppose) expenditure against Candidate X often helps Candidate X's opponent. When you aggregate by the cand_id field and call that number "spent on Candidate X," you can badly mislead readers.

The correct aggregation for "money that helped Candidate X" is:

SUM(exp_amo) WHERE cand_id = X AND sup_opp = 'S'
+ SUM(exp_amo) WHERE cand_id = Y AND sup_opp = 'O'   -- for each opponent Y

LobbyVault's candidate pages try to surface both views separately: money for (supportive IE + opposition IE against opponents) and money against (opposition IE against the candidate + supportive IE for opponents). The raw FEC export only gives you one side; the flip has to be reconstructed.

Mistake 2: Summing Amendments Without Deduplication

FEC filings are amended frequently. When a committee files an amendment, it does not update the original rows — it files a new report, and the bulk data keeps both. If you simply SUM(exp_amo) across all filings you will double-count every amended row.

The standard defensive move is to partition by file_num and keep only the latest filing per transaction_id. A more conservative approach is to join against the form_type column and exclude rows from superseded reports.

If the numbers you're computing look too high compared to press coverage of a race, duplication from amendments is the first thing to check.

Mistake 3: Trusting Free-Text pur Fields

The pur (purpose) column is free-text. Committees write things like "media", "television", "TV", "MEDIA BUY", "ADVERTISING - CABLE", and "consulting" interchangeably. Building a "spending by category" chart by grouping on the raw pur string produces a long tail of near-duplicates.

A workable normalization is:

  • Uppercase everything.
  • Collapse any value containing MEDIA, TV, CABLE, BROADCAST, RADIO into MEDIA.
  • Collapse MAIL, PRINT, POSTCARD into DIRECT MAIL.
  • Collapse DIGITAL, ONLINE, WEB, SOCIAL into DIGITAL.
  • Bucket CONSULTING, STRATEGY, RESEARCH into CONSULTING.
  • Everything else → OTHER.

This is crude but survives contact with real FEC data.

Timing: When Do These Rows Appear?

Most independent expenditures are disclosed via 24-hour notices (filed within 24 hours of the expenditure) during the 20 days before an election, and 48-hour notices before that. Outside the pre-election window, they appear in quarterly reports.

This means the exp_dat field and the filing date can drift. If you're producing a time-series chart of IE activity, use exp_dat (the dissemination date) for the story-telling axis but sanity-check against file_num's filing date when looking for reporting anomalies.

Putting It Together

A defensible "top IE spenders of the cycle" query looks roughly like:

SELECT cmte_id,
       SUM(CASE WHEN sup_opp='S' THEN exp_amo ELSE 0 END) AS supporting,
       SUM(CASE WHEN sup_opp='O' THEN exp_amo ELSE 0 END) AS opposing,
       SUM(exp_amo) AS total
FROM fec_independent_expenditure
WHERE exp_dat BETWEEN '2026-01-01' AND '2026-12-31'
  AND is_superseded = 0             -- amendment handling
GROUP BY cmte_id
ORDER BY total DESC
LIMIT 100;

Most of LobbyVault's committee pages run a version of this query, then layer on the support/oppose breakdown per targeted candidate.

The Bottom Line

The FEC publishes enough data to answer almost any question about independent-expenditure spending — but the schema rewards readers who understand the distinction between cmte_id, cand_id, and the sup_opp flag, and who deduplicate amendments. Most of the headline numbers you see in campaign-finance coverage are a rough approximation; the interesting story is usually one layer deeper in the raw rows.

Data Source

All data referenced in this article is sourced from FEC.gov public records. LobbyVault is not affiliated with any political party or candidate.