# IRS Nonprofit 990 Scraper - Charities, Revenue & Officer Pay (`flash_scraper/nonprofit-990-leads`) Actor

Scrape US nonprofits and charities from official IRS Form 990 data: name, EIN, address, NTEE cause area, 501(c) type, revenue, expenses, assets, surplus/deficit, officer pay and year-over-year growth. Filter by state, cause, 501(c) type and minimum revenue. Export CSV/JSON/Excel. No API key.

- **URL**: https://apify.com/flash\_scraper/nonprofit-990-leads.md
- **Developed by:** [Flash Scrape](https://apify.com/flash_scraper) (community)
- **Categories:** Lead generation, Business, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 results

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/platform/actors/running/actors-in-store#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

## IRS Nonprofit 990 Scraper — Charities, Revenue & Officer Pay

**Turn the US nonprofit sector into a spreadsheet.** Search official IRS Form 990 data by
keyword, state, cause area and 501(c) type, and get **one clean row per organization**: name,
EIN, address, cause area, 501(c) type, and — straight from the organization's own filings —
**total revenue, expenses, end-of-year assets, surplus/deficit, operating margin, officer
compensation and year-over-year revenue growth**, plus a link to the source 990 PDF.

**No API key, no login, no proxy.** Public IRS data via ProPublica's free Nonprofit Explorer API.

### What you can do with it

- 💰 **Qualify prospects by size** — `minRevenue` + the `size_tier` column ("mid ($1M-10M)")
  give you only the nonprofits big enough to be worth a pitch.
- 🎯 **Build a targeted list** — every food bank in Texas, every health charity in Wyoming,
  every 501(c)(6) chamber of commerce in your state.
- 📈 **Spot who is growing** — `revenue_growth_pct` compares the latest filing to the prior
  year, so you can find organizations whose budgets are expanding.
- 🔎 **Check financial health** — `surplus` and `operating_margin_pct` show at a glance who
  runs a deficit and who does not.
- 🧾 **Research officer pay** — `officer_compensation` comes from the filing itself.
- 🗂️ **Export** to CSV, JSON or Excel.

Built for fundraising consultants, grant writers, nonprofit-sector vendors, researchers and
journalists who need the whole segment rather than one EIN lookup at a time.

### Input

| Field | Type | Description |
|---|---|---|
| `searchTerms` | array | Keywords matched against organization names, e.g. `food bank`, `animal rescue`. Leave empty to browse a whole state or cause area. |
| `states` | array | Two-letter US state codes, e.g. `["TX","CA"]`. Empty = all states. |
| `causeArea` | select | One NTEE major group — Arts, Education, Environment & Animals, Health, Human Services, International, Public Benefit, Religion, Mutual Benefit, Unclassified. |
| `subsectionCode` | select | One 501(c) type. `3` is the classic tax-deductible public charity. |
| `includeFinancials` | boolean | Fetch each organization's filing history for revenue/assets/officer pay. Default `true`. Turn off for a fast name-and-address list. |
| `minRevenue` | integer | Drop organizations below this latest reported revenue. `0` = no filter. |
| `minAssets` | integer | Drop organizations below this latest reported end-of-year assets. `0` = no filter. |
| `onlyWithFilings` | boolean | Skip organizations with no 990 data on record. |
| `maxItems` | integer | Max organizations per run (1–1000). |

Every search term is combined with every state, so `["food bank"] × ["TX","CA"]` runs two
queries and merges the results, deduplicated by EIN.

#### Examples

Qualified prospects — Texas food banks over $1M revenue:

```json
{ "searchTerms": ["food bank"], "states": ["TX"], "minRevenue": 1000000, "maxItems": 100 }
```

Browse a whole segment — every 501(c)(3) health nonprofit in Wyoming, no keyword needed:

```json
{ "searchTerms": [], "states": ["WY"], "causeArea": "4", "subsectionCode": "3", "maxItems": 200 }
```

### Output (one row per organization)

`ein`, `ein_formatted`, `name`, `also_known_as`, `city`, `state`, `address`, `zipcode`,
`care_of_name`, `ntee_code`, `cause_area`, `subsection_code`, `organization_type`, `is_501c3`,
`ruling_date`, `tax_period`, `has_filings`, `filing_count`, `filing_years`,
`latest_fiscal_year`, `total_revenue`, `total_expenses`, `total_assets`, `surplus`,
`operating_margin_pct`, `officer_compensation`, `revenue_growth_pct`, `size_tier`,
`irs_revenue_amount`, `irs_income_amount`, `irs_asset_amount`, `latest_filing_pdf`,
`propublica_url`, `matched_search_term`.

#### Sample row

```json
{
  "ein": "742181456",
  "name": "Houston Food Bank",
  "city": "Houston",
  "state": "TX",
  "ntee_code": null,
  "cause_area": null,
  "organization_type": "501(c)(3) charitable / educational",
  "latest_fiscal_year": 2023,
  "total_revenue": 298504285,
  "total_expenses": 314899919,
  "total_assets": 154916055,
  "surplus": -16395634,
  "operating_margin_pct": -5.49,
  "officer_compensation": 1538220,
  "revenue_growth_pct": -20.69,
  "size_tier": "very large ($50M+)",
  "filing_count": 13
}
```

Note the `null` `cause_area` above: the IRS search index carries no NTEE code for this
organization, so the actor reports null rather than guessing a category. Most rows do have one.

Results are sorted **largest revenue first** when financials are on, so the best-qualified
prospects are at the top.

### Honest notes

- **Financial fields can legitimately be `null`.** An organization can sit in the IRS master
  file with no Form 990 data at all — usually very small or newly registered ones. Use
  `onlyWithFilings: true` to exclude them. Nothing is guessed or filled in.
- **`latest_fiscal_year` is the filing's tax year, not today.** IRS 990 data runs a year or
  two behind by nature; the actor reports the most recent filing that exists.
- **Two sets of money fields, on purpose.** `total_revenue` / `total_expenses` /
  `total_assets` come from the organization's own filings. The `irs_*_amount` fields come from
  the IRS master file and can differ or lag — both are exposed rather than silently picked.
- **`minRevenue` / `minAssets` need financials**, so setting either switches
  `includeFinancials` on automatically and says so in the log.
- **Cause area is labelled per row from its own NTEE letter**, which is more precise than the
  numeric group you searched under (group 3 covers both Environment and Animal-Related, for
  instance).
- Broad queries top out around 1,000 organizations per query — that is the API's practical
  paging limit, not a cap this actor adds. Narrow by state or cause area to go deeper.
- Requests are paced and retried automatically. An unknown state code is reported as a fixable
  input problem, never as an outage, and nothing is charged for it.

# Actor input Schema

## `searchTerms` (type: `array`):

Keywords to match against organization names, e.g. 'food bank', 'animal rescue', 'youth center'. Leave empty to browse a whole state or cause area instead.

## `states` (type: `array`):

Two-letter US state codes to restrict to, e.g. \['TX','CA']. Empty = all states.

## `causeArea` (type: `string`):

Restrict to one NTEE major group - the IRS classification of what the nonprofit does.

## `subsectionCode` (type: `string`):

Restrict to one 501(c) subsection. '3' = the classic tax-deductible public charity.

## `includeFinancials` (type: `boolean`):

Fetch each organization's filing history for revenue, expenses, assets, officer pay and year-over-year growth. Costs one extra request per organization, so turn it off for a fast name-and-address list.

## `minRevenue` (type: `integer`):

Drop organizations whose latest reported total revenue is below this. 0 = no filter. Qualifies prospects by size.

## `minAssets` (type: `integer`):

Drop organizations whose latest reported end-of-year assets are below this. 0 = no filter.

## `onlyWithFilings` (type: `boolean`):

Skip organizations that have no Form 990 data available at all (usually very small or newly registered ones).

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

Maximum number of organizations to return across all search terms and states.

## Actor input object example

```json
{
  "searchTerms": [
    "food bank"
  ],
  "states": [
    "TX"
  ],
  "causeArea": "any",
  "subsectionCode": "any",
  "includeFinancials": true,
  "minRevenue": 0,
  "minAssets": 0,
  "onlyWithFilings": false,
  "maxItems": 50
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "searchTerms": [
        "food bank"
    ],
    "states": [
        "TX"
    ],
    "causeArea": "any",
    "subsectionCode": "any",
    "includeFinancials": true,
    "minRevenue": 0,
    "minAssets": 0,
    "onlyWithFilings": false,
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("flash_scraper/nonprofit-990-leads").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 = {
    "searchTerms": ["food bank"],
    "states": ["TX"],
    "causeArea": "any",
    "subsectionCode": "any",
    "includeFinancials": True,
    "minRevenue": 0,
    "minAssets": 0,
    "onlyWithFilings": False,
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("flash_scraper/nonprofit-990-leads").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "food bank"
  ],
  "states": [
    "TX"
  ],
  "causeArea": "any",
  "subsectionCode": "any",
  "includeFinancials": true,
  "minRevenue": 0,
  "minAssets": 0,
  "onlyWithFilings": false,
  "maxItems": 50
}' |
apify call flash_scraper/nonprofit-990-leads --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=flash_scraper/nonprofit-990-leads",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/GDX5mqo9DCZCh45Mm/builds/7nW00fY0YdZPcrvIn/openapi.json
