# IRS Tax Exempt Organization Search Scraper (`automation-lab/tax-exempt-organization-search`) Actor

Search and export official IRS EO BMF records by EIN, name, state, subsection, NTEE, status, and tax period for nonprofit screening and research.

- **URL**: https://apify.com/automation-lab/tax-exempt-organization-search.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Business
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 Tax Exempt Organization Search Scraper

Search and export official IRS Exempt Organizations Business Master File (EO BMF) records without an IRS login or API key.

This Actor turns the IRS tax exempt organization search bulk files into filtered, typed dataset rows.
Look up a nonprofit by EIN, search organization names, select states, or combine subsection, NTEE, status, and tax-period filters for recurring screening.

The result is an integration-ready dataset with organization identity, filing address, classification codes, filing requirements, and the financial amounts available in the EO BMF.

### What can the IRS tax exempt organization search scraper do?

- Look up one organization by its nine-digit EIN.
- Search official organization names with case-insensitive text matching.
- Search one or several US states, the District of Columbia, Puerto Rico, or international records.
- Filter 501(c)(3) organizations with subsection code `03`.
- Select nonprofit sectors with NTEE codes or prefixes.
- Filter the current IRS master-file status code.
- Restrict records to a tax-period range.
- Export up to 10,000 matching organizations per run.
- Feed typed results into spreadsheets, databases, CRM enrichment, and screening workflows.
- Schedule the same query and compare datasets between IRS updates.

The Actor streams the official CSV files instead of loading the roughly two-million-record master file into memory.
When states are selected, it requests the smaller official state files for faster and cheaper runs.

### Who is it for?

**Nonprofit compliance teams** can screen EINs and classification fields on a schedule.

**Grantmakers and foundations** can assemble official organization lists before deeper due diligence.

**Fundraising and prospecting teams** can discover organizations by geography and nonprofit sector.

**Researchers and journalists** can export reproducible snapshots from an official US government source.

**Data engineers** can replace manual IRS CSV downloads with an Apify Task, API call, webhook, or schedule.

**Developers** can retrieve normalized JSON without implementing large-file streaming and IRS code filtering.

Use a Form 990-focused source when you need filing documents, officers, grants, or filing-level details.
This Actor returns the EO BMF organization record, not complete Form 990 submissions.

### Why use this instead of downloading IRS CSV files manually?

The IRS publishes high-quality public bulk data, but direct use requires selecting files, downloading large CSVs, preserving leading zeros, interpreting codes, and filtering millions of rows.

This Actor provides:

1. validated search inputs;
2. state-file routing for focused searches;
3. streaming CSV parsing with bounded memory;
4. exact preservation of EINs and classification codes;
5. numeric asset, income, and revenue fields;
6. per-result charging rather than a fixed data subscription;
7. standard Apify datasets, schedules, webhooks, API clients, and integrations;
8. explicit source URLs on every row.

No proxy, browser, CAPTCHA solver, private IRS account, or third-party nonprofit API is required.

### Input parameters

| Field | Type | Description |
| --- | --- | --- |
| `ein` | string | Exact nine-digit EIN. Hyphens and spaces are accepted. |
| `name` | string | Case-insensitive substring of the official IRS organization name. Minimum two characters. |
| `states` | string\[] | Two-letter filing-address codes. Use `DC`, `PR`, or `XX` where applicable. |
| `subsections` | string\[] | Two-digit IRC subsection codes, such as `03` for 501(c)(3). |
| `nteeCodes` | string\[] | NTEE codes or prefixes, such as `B`, `B20`, or `E21`. |
| `statusCodes` | string\[] | Two-digit status values from the IRS EO BMF information sheet. |
| `taxPeriodFrom` | string | Earliest accepted tax period in `YYYYMM` format. |
| `taxPeriodTo` | string | Latest accepted tax period in `YYYYMM` format. |
| `maxItems` | integer | Maximum results, from 1 to 10,000. Default: 100. |

All supplied filters are combined with AND logic.
Values within one list use OR logic.
For example, `states: ["NY", "NJ"]` and `subsections: ["03"]` returns 501(c)(3) records in either New York or New Jersey.

NTEE filtering uses prefixes.
A value of `B` includes all education categories whose NTEE code starts with B.

Records without a tax period do not match `taxPeriodFrom` or `taxPeriodTo`.

### Getting started

1. Open the Actor input page.
2. Enter an EIN or choose one or more filters.
3. Keep `maxItems` small for the first run.
4. Click **Start**.
5. Open the **Dataset** tab when the run succeeds.
6. Export results as JSON, CSV, Excel, XML, or another Apify-supported format.
7. Save the input as a Task if you want schedules, webhooks, or repeat runs.

A focused 501(c)(3) search can use:

```json
{
  "states": ["NY"],
  "subsections": ["03"],
  "maxItems": 25
}
```

An exact EIN lookup can use:

```json
{
  "ein": "53-0196605",
  "states": ["DC"],
  "maxItems": 1
}
```

Supplying the state with an EIN is optional, but it avoids scanning unrelated regional files and usually finishes faster.

### Output fields

Every matching organization is stored in the default dataset.

| Field | Meaning |
| --- | --- |
| `ein` | Nine-digit Employer Identification Number. |
| `name` | Official IRS organization name. |
| `careOfName` | In-care-of name when provided. |
| `street`, `city`, `state`, `zip` | Filing-address fields. |
| `groupExemptionNumber` | Group exemption number. |
| `subsectionCode` | IRC subsection code. |
| `affiliationCode` | IRS affiliation code. |
| `classificationCode` | Organization classification code or codes. |
| `rulingDate` | Ruling date in `YYYYMM` format. |
| `deductibilityCode` | Deductibility limitation code. |
| `foundationCode` | Foundation classification code. |
| `activityCodes` | Combined IRS activity codes. |
| `organizationCode` | Organization type code. |
| `statusCode` | Current EO BMF status code. |
| `taxPeriod` | Latest available tax period in `YYYYMM`. |
| `assetCode`, `incomeCode` | IRS amount-range codes. |
| `filingRequirementCode` | Form 990-series filing requirement code. |
| `privateFoundationFilingRequirementCode` | Private-foundation filing requirement code. |
| `accountingPeriod` | Accounting period ending month. |
| `assetAmount` | Latest asset amount supplied in the master file. |
| `incomeAmount` | Latest income amount supplied in the master file. |
| `revenueAmount` | Latest revenue amount supplied in the master file. |
| `nteeCode` | National Taxonomy of Exempt Entities code. |
| `sortName` | Alternate IRS sort name when available. |
| `sourceUrl` | Exact official IRS CSV file used. |
| `scrapedAt` | ISO timestamp for extraction. |

Blank IRS values are returned as `null`.
Financial amounts are numbers when present, but they are not guaranteed for every organization.
Code fields remain strings so leading zeros are preserved.

### Example result

This abbreviated example reflects the Actor's current output shape:

```json
{
  "ein": "530196605",
  "name": "AMERICAN NATIONAL RED CROSS",
  "city": "WASHINGTON",
  "state": "DC",
  "subsectionCode": "03",
  "statusCode": "01",
  "taxPeriod": "202506",
  "filingRequirementCode": "01",
  "nteeCode": "P210",
  "sourceUrl": "https://www.irs.gov/pub/irs-soi/eo_dc.csv",
  "scrapedAt": "2026-08-07T06:09:06.755Z"
}
```

The source may change tax periods or other fields when the IRS refreshes its files.
Treat the live dataset row as authoritative for that run.

### How much does it cost to search IRS tax-exempt organizations?

Pricing uses one small Actor start charge plus one `Organization record` event for every result saved.
The per-record price decreases across Apify subscription tiers.
No proxy event or separate charge is added for the included classification and financial fields.

At the BRONZE rate of **$0.002732 per record** plus a **$0.005 start fee**:

| Saved organizations | Example total |
| ---: | ---: |
| 1 | $0.0077 |
| 25 | $0.0733 |
| 100 | $0.2782 |
| 1,000 | $2.7370 |

These examples use BRONZE pricing.
Your Console shows the active rate for your Apify plan before each run.
A no-result run incurs only the start charge.
Compute usage is included in pay-per-event pricing rather than billed as another Actor event.

### Search and screening workflows

#### Verify a known nonprofit

Use an EIN plus a state when known.
Store the returned status, subsection, filing requirement, and source URL with the screening record.

#### Build a state nonprofit list

Select one state, subsection `03`, and a useful `maxItems`.
Export the resulting dataset to CSV or Excel.
Use narrower NTEE filters if the state contains more matches than one run returns.

#### Create education or health prospect lists

Use NTEE prefix `B` for education or `E` for health-related records.
Combine the prefix with state and subsection filters.
Review IRS code definitions before using a list for eligibility decisions.

#### Monitor master-file changes

Save the input as an Apify Task and schedule it after expected IRS updates.
Send completed datasets to your data warehouse.
Compare rows by `ein` rather than by organization name.
The Actor does not calculate changes itself; use dataset comparison or your own pipeline.

### Scheduling and integrations

Apify Tasks preserve a validated input for repeat runs.
Schedules can execute a Task daily, weekly, monthly, or with a custom cron expression.

Useful integrations include:

- Google Sheets for analyst review;
- Airtable for research queues;
- Make or Zapier for workflow routing;
- webhooks for run completion;
- Amazon S3, Google Cloud Storage, or a data warehouse for snapshots;
- a CRM enrichment job keyed by EIN;
- Apify dataset APIs for downstream applications.

For recurring screening, retain the extraction timestamp and source URL.
That creates a clearer audit trail than copying values without provenance.

### Use the Actor through the API

Replace `APIFY_TOKEN` with your token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~tax-exempt-organization-search/run-sync-get-dataset-items?token=APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"states":["CA"],"subsections":["03"],"nteeCodes":["B"],"maxItems":50}'
```

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/tax-exempt-organization-search').call({
  states: ['CA'],
  subsections: ['03'],
  nteeCodes: ['B'],
  maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/tax-exempt-organization-search').call(
    run_input={
        'states': ['CA'],
        'subsections': ['03'],
        'nteeCodes': ['B'],
        'maxItems': 50,
    }
)
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

For searches that may run several minutes, prefer the asynchronous run endpoint or an SDK `call()` over a short HTTP client timeout.

### Use with Model Context Protocol (MCP)

#### Claude Code setup

Add this Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/tax-exempt-organization-search"
```

#### Claude Desktop setup

Add the following server to the Claude Desktop MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/tax-exempt-organization-search"
    }
  }
}
```

#### Cursor setup

Add the same `apify` server URL in **Cursor Settings → MCP**.

#### VS Code setup

Add the same `apify` server URL to your VS Code MCP server configuration.

Example prompts:

- “Look up EIN 53-0196605 in the IRS tax-exempt master file.”
- “Export 25 New York 501(c)(3) organizations.”
- “Find California education nonprofits with status code 01 and tax periods from 202301.”

MCP clients still use your Apify account and the Actor's active pricing.

### Performance tips

1. Supply `states` whenever geography is known.
2. Supply the state with an EIN when possible.
3. Start with a low `maxItems` while refining filters.
4. Use an NTEE prefix to split large state searches into meaningful segments.
5. Increase Task timeout if you intentionally run a nationwide name search.
6. Schedule repeat queries rather than manually rebuilding inputs.

The official state files are usually much smaller than the four regional files.
A nationwide query must stream regional data until enough matches are found or all files are exhausted.
Run duration therefore depends on filter selectivity, file size, IRS transfer speed, and where matching EINs occur in the sorted files.

### Data freshness and limitations

- Data comes from the cumulative IRS EO BMF extract.
- Freshness follows the IRS publication schedule; this is not a real-time IRS status API.
- Filing addresses represent headquarters and may not represent every operating location.
- The EO BMF is not the same as the full Tax Exempt Organization Search product.
- The Actor does not download determination letters, Form 990 PDFs, revocation files, or organization officers.
- `assetAmount`, `incomeAmount`, `revenueAmount`, and `taxPeriod` can be null.
- NTEE and IRS classification codes require domain interpretation.
- A result indicates what the source file reported, not a legal opinion or endorsement.
- `maxItems` stops the run after the requested number of matches; it is not a claim that no additional matches exist.
- If an IRS file repeatedly fails, the run fails instead of silently returning an incomplete nationwide dataset.

For code meanings, consult the IRS EO BMF information sheet linked from the IRS download page.

### Legality and responsible use

IRS EO BMF data is public US government organization data.
You remain responsible for how you combine, store, and use it.

Do not treat one code as a complete eligibility, fraud, sanctions, or charitable-status decision.
Confirm high-impact decisions with current IRS guidance and other appropriate primary records.
Respect applicable privacy, anti-discrimination, marketing, and data-retention rules.

This Actor is independently operated and is not endorsed by the Internal Revenue Service.

### Troubleshooting

#### The run returned no records

Check that EINs contain nine digits after punctuation is removed.
Confirm state, subsection, NTEE, status, and tax-period filters are not mutually exclusive.
Remember that records with blank tax periods do not match a tax-period range.
Try one filter at a time before combining them.

#### The run is slower than expected

Add a state filter so the Actor can use an official state file.
Reduce `maxItems` while testing.
Nationwide name and classification searches can scan large regional files.

#### The run failed with an IRS HTTP error

The Actor retries initial transient download failures.
If all retries fail, wait for the public file to become available and rerun the same Task.
No proxy configuration is required or accepted.

#### Why is a financial amount null?

The IRS master file does not supply every amount for every organization.
Null means the field was blank or unavailable in that source row; it does not mean zero.

#### Why are codes strings instead of numbers?

EINs, subsections, status values, filing requirement codes, and other identifiers can contain leading zeros.
Strings preserve the official representation.

### FAQ

#### Does this Actor require an IRS account or IRS login?

No.
It reads public official bulk CSV files and requires no IRS credentials.

#### Can I search 501(c)(3) organizations?

Yes.
Set `subsections` to `["03"]` and add state or NTEE filters as needed.

#### Can I search by EIN?

Yes.
Use `ein` for an exact lookup.
Hyphenated and unhyphenated EINs are accepted.

#### Does it return Form 990 filings?

No.
It returns organization-level EO BMF fields, including the latest available tax period and summary amounts.
Use a filing-focused Actor for filing documents and filing-level details.

#### Does status code 01 prove tax deductibility?

No.
Status, deductibility, subsection, filing requirements, and source freshness must be interpreted together under current IRS guidance.

#### Can I export all matching organizations?

One run can save up to 10,000 matches.
Split larger exports by state, NTEE prefix, subsection, or another supported filter.

#### Can I monitor changes automatically?

You can schedule repeat Tasks and compare datasets by EIN.
The Actor supplies snapshots; it does not emit a separate change-event record.

### Related Automation Lab Actors

- [ProPublica Nonprofit Explorer Scraper](https://apify.com/automation-lab/propublica-nonprofit-explorer-scraper) — use when you need nonprofit profiles and Form 990-derived financial information beyond the EO BMF record.
- [US Denied Party Screening API](https://apify.com/automation-lab/us-denied-party-screening-api) — add a separate US restricted-party screening step to compliance workflows.

These Actors serve adjacent workflows and use separate sources, inputs, outputs, and pricing.

# Actor input Schema

## `ein` (type: `string`):

Exact 9-digit EIN. Hyphens and spaces are accepted.

## `name` (type: `string`):

Case-insensitive text contained in the official IRS organization name.

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

Two-letter filing-address codes. Selecting states uses the smaller official state files for faster runs. Use PR for Puerto Rico or XX for international records.

## `subsections` (type: `array`):

Two-digit Internal Revenue Code subsection codes, such as 03 for 501(c)(3).

## `nteeCodes` (type: `array`):

One or more National Taxonomy of Exempt Entities codes or prefixes, such as B for education or E21 for community health systems.

## `statusCodes` (type: `array`):

Two-digit status codes from the EO BMF information sheet, such as 01 for organizations with current filing requirements.

## `taxPeriodFrom` (type: `string`):

Earliest tax period in YYYYMM format. Records without a tax period do not match this filter.

## `taxPeriodTo` (type: `string`):

Latest tax period in YYYYMM format. Records without a tax period do not match this filter.

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

Maximum number of matching organization records to save.

## Actor input object example

```json
{
  "states": [
    "NY"
  ],
  "subsections": [
    "03"
  ],
  "maxItems": 20
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing matching IRS tax-exempt organization records.

# 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 = {
    "states": [
        "NY"
    ],
    "subsections": [
        "03"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/tax-exempt-organization-search").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 = {
    "states": ["NY"],
    "subsections": ["03"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/tax-exempt-organization-search").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 '{
  "states": [
    "NY"
  ],
  "subsections": [
    "03"
  ],
  "maxItems": 20
}' |
apify call automation-lab/tax-exempt-organization-search --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/tax-exempt-organization-search"
        }
    }
}

```

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/g9oEt9RkMinbJDnPN/builds/Iia8GvLkxzUu6ykoV/openapi.json
