# NASBA CPA Directory Scraper (`muhammadafzal/nasba-cpa-directory-scraper`) Actor

Search the official NASBA CPAverify public directory by last name, first name, license number, and jurisdiction. Returns CPA license numbers, statuses, dates, board data, addresses, and disciplinary information. No login required. Charged $0.005 per returned record plus a $0.00005 run-start event.

- **URL**: https://apify.com/muhammadafzal/nasba-cpa-directory-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Automation, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 cpa record returneds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## NASBA CPA Directory Scraper

Search the official NASBA CPAverify public directory and return normalized CPA license records. Use it for license verification workflows, accounting-firm research, compliance review, and agent pipelines that need a CPA’s public board status, license number, dates, and source URL.

The actor searches public data supplied by U.S. state Boards of Accountancy to NASBA’s Accountancy Licensee Database. It does not require a login and does not invent missing values.

### What it extracts

Each dataset item represents one CPA directory result and, when enabled, its public detail page.

| Field | Description |
| --- | --- |
| `licenseeName` | CPA name shown in the directory |
| `jurisdiction` | Board jurisdiction code, such as `NY` or `TX` |
| `licenseNumber` | License, permit, or certification number |
| `licenseStatus` | Status shown in the search table |
| `licenseType` | Detail-page license type, usually `CPA` |
| `issueDate`, `expirationDate` | Public license dates when displayed |
| `disciplinaryAction` | Board-reported enforcement or disciplinary text |
| `cpeId`, `registrationNumber`, `basisForLicense` | Additional public license metadata |
| `homeAddress`, `businessAddress`, `mailingAddress` | Public address summaries, when shown |
| `recordLastUpdated` | Update date displayed by NASBA |
| `detailUrl` | Direct NASBA page for verification |
| `detailFetched`, `detailError` | Enrichment diagnostics |

Missing values are returned as `null`. The source directory may not participate for every U.S. jurisdiction, and the page itself notes that firm data is unavailable for some jurisdictions. This actor searches CPA license records, not firm records.

### When to use it

Use this actor when you have a last name and need official public CPA license records. Narrow broad surnames with `firstName`, `jurisdiction`, `licenseNumber`, or `middleName`. Set `includeDetails` to `false` when you only need the fast search-table fields.

Do not use it for:

- CPA firm discovery or firm contact enrichment; NASBA has a separate Firm search surface.
- Private contact data, email addresses, phone numbers, or a determination that a license is legally valid beyond the board’s displayed status.
- A replacement for direct verification with the relevant State Board of Accountancy.

### Input example

```json
{
  "lastName": "Smith",
  "firstName": "Aaron",
  "jurisdiction": "NY",
  "maxResults": 10,
  "maxPages": 1,
  "includeDetails": true
}
```

`lastName` defaults to `Smith` so the Apify health check has a working example. For production runs, supply a narrower name or license number. The source displays up to 25 rows per page and no more than 250 results for one search; `maxPages` controls how many of those pages the actor reads.

### Output example

```json
{
  "licenseeName": "AARON JAMES SMITH",
  "maidenName": null,
  "jurisdiction": "NY",
  "licenseNumber": "122833",
  "licenseStatus": "Registered",
  "disciplinaryAction": "None reported to this site by the board.",
  "cpeId": "CPE-C7589",
  "licenseType": "CPA",
  "basisForLicense": null,
  "issueDate": "2016-11-14",
  "expirationDate": "2028-07-31",
  "yearsLicensed": 9,
  "recordLastUpdated": "2026-08-02",
  "mailingAddress": "BENTONVILLE, AR",
  "detailFetched": true,
  "detailError": null,
  "detailUrl": "https://ald.nasba.org/search/cpa/513608543?jurisdictionId=20",
  "sourceUrl": "https://ald.nasba.org/search/cpa/513608543?jurisdictionId=20",
  "scrapedAt": "2026-08-02T00:00:00.000Z"
}
```

The default key-value store also receives an `OUTPUT` object with `status`, `records`, `searchUrl`, `includeDetails`, `maxResults`, completion time, and warnings. A valid search with no matches is a successful warning outcome. If NASBA does not serve the search page after retries, the actor reports a failed run instead of silently returning an empty dataset.

### Pricing

| Event | Price |
| --- | ---: |
| Actor start | $0.00005 |
| CPA record returned | $0.005 |

The record event is charged only after the dataset item is saved. A run capped at 10 records costs at most $0.05005 in declared PPE charges, before any applicable platform usage charges. The actor never intentionally emits more than `maxResults` items.

### API and MCP usage

JavaScript API example:

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('YOUR_USERNAME/nasba-cpa-directory-scraper').call({
  lastName: 'Smith',
  jurisdiction: 'NY',
  maxResults: 10
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

The stable title, input descriptions, and dataset schema are designed for Apify’s hosted MCP integration. Agents should use this actor for CPA license-directory lookups, not firm discovery or contact enrichment. The tool’s result preview is the dataset; paginate with the dataset ID when a run returns more records than the preview.

### Reliability and legal notes

The actor uses a browser because NASBA’s current public search is a rendered web application. It keeps a single browser session per run, retries temporary page failures, deduplicates by jurisdiction/license/detail URL, and preserves search-table data if an individual detail page fails. It does not bypass CAPTCHA, authentication, paywalls, or access restrictions.

NASBA states that CPAverify is populated from official, publicly available state regulatory data. The data can be incomplete, delayed, or unavailable for non-participating jurisdictions. Always confirm important licensing decisions with the relevant state board. You are responsible for complying with NASBA terms of use, applicable privacy law, and restrictions on storing or redistributing public license information. This independent actor is not affiliated with or endorsed by NASBA or any state Board of Accountancy.

### Troubleshooting

If a broad surname returns the source’s 250-result ceiling, add a jurisdiction or first name. If a record has `detailFetched: false`, the search result itself was preserved and `detailError` explains the failed detail request. If a run fails before returning records, retry later and include the run ID when reporting a possible NASBA layout or access-control change.

# Actor input Schema

## `lastName` (type: `string`):

Use this when searching NASBA CPA records by surname. Enter a last name such as Smith. Required by the source directory; this is not a free-text company or firm search.

## `firstName` (type: `string`):

Use this to narrow the CPA search to a given name, such as Aaron. Leave blank for all first names matching lastName; this is not a firm name.

## `middleName` (type: `string`):

Use this when the directory record includes a middle name and you need a narrower person lookup. Enter plain text such as James; leave blank when unknown.

## `maidenName` (type: `string`):

Use this when searching for a CPA by a recorded maiden name. Enter plain text; leave blank when not applicable. This field is not a current surname replacement.

## `licenseNumber` (type: `string`):

Use this to narrow a person lookup to a known CPA license number, such as 122833. Leave blank for name-based search; this is not an internal NASBA record ID.

## `jurisdiction` (type: `string`):

Use this to limit results to one NASBA participating jurisdiction. Enter a code such as NY, CA, or TX. Leave blank for the national public search; this is not a city or country name.

## `maxResults` (type: `integer`):

Use this to cap the total unique CPA license records returned. Enter 1–250; the source directory displays no more than 250 results for one search. Defaults to 10; this is not a per-page limit.

## `maxPages` (type: `integer`):

Use this to control pagination when a search has more than 25 matches. Enter 1–10 pages; each source page contains up to 25 rows. Defaults to 1 to keep health checks fast.

## `includeDetails` (type: `boolean`):

Use this to open each public CPA detail page for dates, addresses, CPE ID, license type, and other information. Defaults to true; set false for faster search-table-only output.

## `maxRequestRetries` (type: `integer`):

Use this to retry temporary NASBA page failures. Enter 0–5; defaults to 2. This is an operational retry cap, not the number of CPA records returned.

## Actor input object example

```json
{
  "lastName": "Smith",
  "firstName": "",
  "middleName": "",
  "maidenName": "",
  "licenseNumber": "",
  "jurisdiction": "NY",
  "maxResults": 10,
  "maxPages": 1,
  "includeDetails": true,
  "maxRequestRetries": 2
}
```

# Actor output Schema

## `records` (type: `string`):

Normalized CPA license records from the NASBA public directory.

## `summary` (type: `string`):

Run status, count, input URL, and warnings.

# 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 = {
    "lastName": "Smith",
    "firstName": "",
    "middleName": "",
    "maidenName": "",
    "licenseNumber": "",
    "jurisdiction": "NY",
    "maxResults": 10,
    "maxPages": 1,
    "includeDetails": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/nasba-cpa-directory-scraper").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 = {
    "lastName": "Smith",
    "firstName": "",
    "middleName": "",
    "maidenName": "",
    "licenseNumber": "",
    "jurisdiction": "NY",
    "maxResults": 10,
    "maxPages": 1,
    "includeDetails": True,
}

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/nasba-cpa-directory-scraper").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 '{
  "lastName": "Smith",
  "firstName": "",
  "middleName": "",
  "maidenName": "",
  "licenseNumber": "",
  "jurisdiction": "NY",
  "maxResults": 10,
  "maxPages": 1,
  "includeDetails": true
}' |
apify call muhammadafzal/nasba-cpa-directory-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/nasba-cpa-directory-scraper"
        }
    }
}

```

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/EARaCqRMjEQWdO82r/builds/qrqk6jp30c4c7PdB1/openapi.json
