Lead generation
IRS 990 Scraper — Nonprofit Officer Comp
Scrape IRS Form 990 nonprofit officer compensation and key financials as structured rows via the ProPublica Nonprofit Explorer API — bulk EIN lookup or name/state search, one row per filing year, 990 / 990EZ / 990PF field mapping — export to JSON or CSV. No key, no login.
Free Apify credit covers a first run. No credit card to try.
What this Actor scrapes
One ResultRow per (EIN, tax year) filing. Every row carries the same 21 columns regardless of which input mode you used. Data is published by ProPublica under their Terms of Use (IRS source data is public domain).
What we handle for you
- Two input modes —
eins(explicit list) andsearchQuery(name search). Pydantic XOR validator enforces exactly one before any network call. EIN normaliser accepts13-1684331,131684331, or integer forms. - Formtype-correct field mapping — officer comp lives in
compnsatncurrofcron 990/990EZ andcompofficerson 990PF. We pick the right field for each form so you never get a null officer-comp row for a private foundation. - Year-window filtering —
startYearandendYeardefault to the last 3 calendar years. Out-of-window filings are dropped silently. - Computed total compensation and benefits — sum of officer comp + non-officer salaries + payroll tax + pension + other benefits, computed per filing. Null only when all 5 components are null; never falsely zero.
- State filter (search mode) — pass
stateFilter=CAto scope a name search to a single state viasearch.json?state[id]=. - Multi-form support — 990, 990EZ, and 990PF all produce clean rows. Unknown formtypes are logged and dropped (forward-compatible with new IRS forms).
- We handle retries with exponential backoff —
Retry-Afterheaders honoured for429and503responses; up to 5 attempts per request before we surface a clear error. - We rotate browser fingerprints —
curl-cffiwith Chrome 131 TLS impersonation so the upstream sees real-browser TLS handshakes, not a Python script. - We rotate proxies on every block — Apify Proxy support via the
BUYPROXIES94952group keeps requests flowing through fresh exit IPs. - Pydantic v2 input and output models —
form_typevalidated against the enum ("990"/"990EZ"/"990PF"); EINs zero-padded to 9 digits; typed rows guaranteed.
Use cases
- Nonprofit executive-pay benchmarking — bulk-pull officer compensation for a list of 100–1,000 peer organisations to benchmark CEO/CFO pay against revenue and asset size.
- Investigative journalism — flag nonprofits where officer comp is an outsized fraction of revenue or expenses; spot rapid year-over-year jumps across sector-wide datasets.
- Foundation due diligence — research a foundation's officer payroll and asset trajectory before applying for a grant or entering a partnership.
- Charity-rating data pipelines — feed a structured 990 dataset into your own scoring model without writing a ProPublica wrapper from scratch.
- Academic research — build multi-year panel datasets on nonprofit-sector compensation and finances for economics or public-policy papers.
- State-level nonprofit-sector reports — combine
stateFilterwith a broadsearchQuery(e.g."foundation") to enumerate an entire state's nonprofit landscape in one run. - Prospect research for nonprofit-tech vendors — enrich your CRM with 990-derived financials for sales outreach to development directors at larger organisations.
Input
Paste this into the Apify Console, or send it as the run input over the API. Proxy settings are on by default; you rarely need to touch them.
| Field | Type | Required | What it does |
|---|---|---|---|
eins | array | no | Explicit IRS Employer Identification Numbers to fetch (9 digits, hyphens optional, e.g. 13-1684331 or 131684331). XOR with searchQuery. |
searchQuery | string | no | Free-text search across nonprofit names. Resolves to a list of EINs via ProPublica's search.json endpoint, capped by maxOrgs. XOR with eins. |
stateFilter | string | no | USPS 2-letter state code (e.g. CA, NY, TX). Applied to search mode only; ignored in eins mode. |
startYear | integer | no | Earliest tax_prd_yr to include. Defaults to current year minus 3. |
endYear | integer | no | Latest tax_prd_yr to include. Defaults to current year. |
maxOrgs | integer | no | Hard cap on EINs resolved from searchQuery. Ignored in eins mode. |
useProxy | boolean | no | Route requests through Apify Proxy (BUYPROXIES94952). ProPublica does not currently rate-limit datacenter IPs; leave off unless you see 429. |
{
"eins": [
"131684331"
],
"maxOrgs": 100,
"useProxy": false
} Output
One row per result, schema-validated before it is written. Export JSON, CSV, Excel or XML from the run, or read it over the API.
einorganization_nameorganization_urlstatecityntee_codesubsection_codetax_yeartax_period_endform_typepdf_urlofficer_comp_usdother_salaries_wages_usdpayroll_taxes_usdpension_contributions_usdother_employee_benefits_usd
{
"ein": "131684331",
"organization_name": "Metropolitan Museum of Art",
"organization_url": "https://projects.propublica.org/nonprofits/organizations/131684331",
"state": "NY",
"city": "New York",
"ntee_code": "A51",
"subsection_code": 3,
"tax_year": 2022,
"tax_period_end": "2022-06",
"form_type": "990",
"pdf_url": "https://projects.propublica.org/nonprofits/organizations/131684331/202341349349303881/full",
"officer_comp_usd": 4872543,
"other_salaries_wages_usd": 198345612,
"payroll_taxes_usd": 15234871,
"pension_contributions_usd": 18924301,
"other_employee_benefits_usd": 22341887,
"total_comp_and_benefits_usd": 259719214,
"total_revenue_usd": 412345678,
"total_functional_expenses_usd": 389234512,
"total_assets_end_usd": 5234123456,
"scraped_at": "2024-03-15T14:22:31Z"
} Pricing
| Event | Price | When |
|---|---|---|
| Actor start | $0.20 | Once per run, covers warm-up and proxy session setup. |
| Result row emitted | $0.0030 | Per result written to the dataset. |
You pay only for results that land. Cap any run with maxTotalChargeUsd. See pricing & billing for worked examples.
Limitations
- Per-officer breakdown (name / title / hours / individual comp from Part VII Section A) — that detail lives only in the 990 PDF and is not exposed by ProPublica's structured API. v1 emits the aggregate Part IX line 5 / 990PF Part I line 15 officer-compensation total. Per-officer PDF parsing is on the v2 roadmap.
- Compensation from related organisations (Schedule J Part II) — same reason; PDF-only.
- Filings older than approximately 2010 — ProPublica's structured coverage does not extend earlier.
- Annual filing cadence — 990s file annually, often with an 18-month lag. This Actor provides historical and benchmark data, not a real-time feed.
- 990-N (e-Postcard) — the very smallest nonprofits file 990-N, which has no financial detail. These organisations are not returned.
FAQ
What is an IRS 990 scraper?
How does this differ from ProPublica's bulk download?
total_comp_and_benefits_usd field; and (3) on-demand EIN or name-search queries without downloading the entire bulk file.What is a nonprofit data API?
How do I do a form 990 data download for a specific sector?
searchQuery mode with a sector keyword (e.g. "hospital", "education", "housing") and optionally set stateFilter. Set maxOrgs to control the batch size. The resulting dataset exports as CSV, JSON, Excel, or XML from the Apify Console.Does this support 990PF (private foundations)?
compofficers) than the standard 990/990EZ field (compnsatncurrofcr). We pick the correct field per filing so private foundations always return a populated officer_comp_usd value.Can I use this for nonprofit officer compensation data research?
startYear and endYear to build multi-year panels.What is the 990 financial data API pricing?
Is the underlying data public domain?
Ready to run it?
Open the listing on Apify, paste the input above, and watch rows land. If it ever breaks, it is our problem before it is yours.
Related Actors