# NPI Registry Scraper - NPI Lookup & NPPES Provider Search (`s-r/npi-registry`) Actor

Look up NPI numbers in bulk and search the official NPPES NPI Registry by name, specialty and location. Get provider names, specialties, licenses, practice and mailing addresses, phone numbers, other IDs and update dates.

- **URL**: https://apify.com/s-r/npi-registry.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Lead generation, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 providers

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## NPI Registry Scraper: bulk NPI lookup and NPPES provider search

This NPI Registry scraper runs an NPI lookup for a list of numbers, or searches the official NPPES NPI Registry by name, specialty and location, and returns one clean row per US healthcare provider. Each row carries the NPI number, provider name, specialties, licenses, practice and mailing addresses, phone numbers and the source's registration and update dates, for individual practitioners and for organizations.

Use it to enrich an existing provider list, prepare a directory import, build a lead list of organizations in a specialty or location, check provider details during onboarding, or attach official registry identifiers to CRM records. Every delivered row includes `npi` as text and `provider_id` with the same value. These stable identifiers let you join provider records to other US healthcare directories when those directories publish an NPI.

### NPI Registry input and search options

#### NPI lookup by number

For an existing list, supply `npi_numbers` as an array of strings. For example, NPI `1003000126` belongs to ARDALAN ENKESHAFI, M.D. in the source response used for this actor's examples. This is a real registry record, and its details can change when the provider updates NPPES.

```json
{
  "npi_numbers": ["1003000126"],
  "max_items": 100
}
```

#### NPPES provider search by name, specialty and location

For discovery, use `first_name`, `last_name`, `organization_name`, `taxonomy_description`, `city`, `state`, `postal_code` and `country_code`. Set `provider_type` to `individual`, `organization` or `any`. The specialty filter expects a description such as `Dentist` or `Cardiovascular Disease`. It does not accept a taxonomy code such as `207RC0000X`. The source may match any of a provider's taxonomies, so the primary specialty on a returned row can differ from the searched specialty.

A name can use one trailing wildcard after at least two characters, such as `mayo*` for organization names. `use_first_name_alias` includes aliases in first-name searches. A US postcode accepts five digits, nine digits or a prefix followed by `*`, such as `752*`. A state alone does not define a valid search: combine it with a name, specialty, city or ZIP code.

```json
{
  "taxonomy_description": "Cardiovascular Disease",
  "city": "boston",
  "state": "MA",
  "address_purpose": "PRIMARY",
  "max_items": 100
}
```

The default `address_purpose` is `any`, which lets the source match a mailing address as well as a practice address. Choose `PRIMARY` when the returned primary practice address must match your location filters. `SECONDARY` searches secondary practice locations. `LOCATION` covers primary and secondary practices, while `MAILING` searches mailing addresses. Explicit NPI lookups are independent of these search filters. When both a list and search fields are supplied, the actor looks up the list first, then searches, removing duplicate NPIs across both phases.

### Output fields

Each dataset row represents one provider. The principal fields are `npi`, `name`, `provider_type`, `specialty`, `taxonomy_code`, `license_number`, `license_state`, `address`, `street`, `city`, `state`, `postal_code`, `country_code`, `phone`, `fax`, `enumeration_date`, `last_updated`, `status` and `url`.

Individuals also include published name parts, credentials and sex. Organizations include `organization_name`, subpart information, the parent organization when supplied, and an `authorized_official` object. `taxonomies` preserves every published taxonomy and its primary flag. `specialties` lists unique descriptions with the primary description first when available. Retired taxonomy codes can have a missing description; the actor retains the code and returns a null specialty without guessing a label.

Some active providers have no primary taxonomy flagged. For those records, `primary_taxonomy`, `taxonomy_code`, `specialty`, `license_number` and `license_state` are null, while all taxonomies and specialty descriptions remain available. A missing mailing address produces `mailing_address: null`; a missing primary practice address leaves the practice address fields null. Missing secondary practice locations produce an empty list. Records without a usable NPI, name or provider type are skipped with a warning, while the remaining providers are delivered.

`mailing_address` is separate from the primary practice address. `practice_locations` contains secondary practices. `identifiers`, `other_names` and `endpoints` preserve additional public IDs, aliases and electronic endpoint details. Missing text is null, including the source's `--` name markers. Phone numbers remain in their published form. US ZIP+4 values receive a hyphen, and `postal_code_raw` retains the original value. The actor does not infer an email address from a phone number or endpoint.

### Output example

The row below is an excerpt of a real record returned for NPI `1003000126` (lookup on 5 October 2026); nested taxonomy, identifier and endpoint lists are shortened here and complete in the dataset.

```json
{
  "npi": "1003000126",
  "name": "ARDALAN ENKESHAFI, M.D.",
  "provider_type": "individual",
  "credential": "M.D.",
  "specialty": "Hospitalist",
  "taxonomy_code": "208M00000X",
  "license_number": "MD600003480",
  "license_state": "DC",
  "specialties": ["Hospitalist", "Internal Medicine"],
  "address": "6410 ROCKLEDGE DR STE 304, BETHESDA, MD 20817-1841",
  "city": "BETHESDA",
  "state": "MD",
  "postal_code": "20817-1841",
  "phone": "443-602-6207",
  "enumeration_date": "2007-08-31",
  "last_updated": "2025-05-28",
  "status": "A",
  "url": "https://npiregistry.cms.hhs.gov/provider-view/1003000126"
}
```

Datasets export to JSON, CSV, Excel or XML from the Apify console or API, so the same rows can go straight into a spreadsheet, a CRM import or a data warehouse.

### Use cases

- **Lead generation for healthcare sales.** Search a specialty in a city or ZIP prefix, such as cardiologists in Boston or dentists in `752*`, and export names, practice addresses and phone numbers for outreach or territory planning.
- **Provider data enrichment.** Start from a CRM or claims export that already holds NPI numbers and run a bulk NPI lookup to add specialties, license numbers, addresses and the latest update date.
- **Credentialing and onboarding checks.** Pull the registry's published taxonomies, license fields, status and dates for each provider as source data for an existing review process.
- **Directory building and joins.** Use `npi` as the join key between this registry and other US provider directories, review sites or internal systems that publish the same identifier.
- **Change monitoring.** Re-run the same NPI list on a schedule and compare `last_updated`, addresses or phone numbers to see which providers changed their NPPES record.

### How it compares

| Option | Bulk NPI list | Search filters | Structured export | Over 1,200 matches |
|---|---|---|---|---|
| NPI Registry website | One provider at a time | Yes | No, manual copying | No |
| NPPES API directly | One request per NPI or page | Yes | Raw JSON, nested | You write paging and splitting |
| NPPES full download file | Whole country only | No | Very large CSV, needs processing | Yes, but no filters |
| This NPI Registry scraper | Yes, up to 50,000 rows per job | Yes | Flat rows plus full nested data | ZIP splitting with deduplication |

The registry website is fine for a single NPI lookup. The full NPPES download suits teams that want the entire national file and can process several gigabytes. This actor sits in between: targeted searches and list lookups with clean, deduplicated rows, ready to export.

### Volume, continuation and coverage

`max_items` limits the total number of unique delivered providers, with a default of 100 and an upper limit of 50,000. It applies across the entire job, including the `npi_numbers` list. Increase `max_items` to the size of your list to process all its valid, unique NPIs. If the limit leaves NPI numbers unprocessed, collection stops with partial output and a warning stating how many numbers were not looked up. Larger collections continue automatically between bounded requests until that limit is reached. The run summary includes warnings and indicates any incomplete coverage; API callers can resume using `cursor` while keeping the other input values unchanged.

NPPES exposes at most 1,200 records for one set of search criteria. A full window produces an explicit warning. Enable `split_large_searches` to search narrower US ZIP prefixes and deduplicate their results by NPI. This can retrieve more providers, although a full exact ZIP code still requires narrower name or specialty filters. ZIP splitting cannot guarantee worldwide coverage; searches without a US location restriction warn that foreign or missing postcodes may be omitted. Providers sharing a mailing or practice address may occur in several searches, but duplicate NPIs are delivered only once.

### Pricing for NPI Registry lookups

The actor charges one `provider` event for each delivered provider row. Empty results, invalid NPI values and missing providers do not produce provider charges. Duplicate NPIs do not produce extra rows or extra provider charges. Consult the actor's Pricing tab for the current amount per event and your account's usage limits.

Users without a paid Apify plan receive at most ten providers per run. Larger requested limits are capped, and ZIP splitting is disabled for these runs. Paying users can request the documented volume. The output summary reports whether the free cap applied, along with delivery counts and warnings.

### FAQ

#### Does an NPI prove that a provider is licensed or credentialed?

An NPI is an identifier. The actor returns the registry's published taxonomy and license fields, status and dates. It does not independently verify a license, professional qualification, eligibility or credentialing decision. Use the returned license numbers and dates as source data for the verification process you already use.

#### Why does a Boston search return a provider with a different primary practice city?

The default address mode can match the provider's mailing address or another practice location. Select `address_purpose: "PRIMARY"` to restrict a location search to the primary practice address. The other address objects remain available so you can inspect how the source record is structured.

#### What happens to an invalid or unknown NPI?

Invalid checksums and malformed NPI values are skipped with a warning when other usable input remains. A wholly invalid list is rejected. An unknown but valid NPI adds a missing-provider warning; it never creates a placeholder provider row. A valid search with no matching records returns an empty result with no provider event charges.

#### Can I retrieve every US provider with one broad search?

Broad searches encounter the source's search window. ZIP splitting expands coverage, and full ZIP searches require further filtering. Check the summary warnings before treating a collection as complete. NPPES does not expose a total match count: its result count describes a single returned page.

#### Can I look up an NPI number by provider name?

Yes. Leave `npi_numbers` empty and search with `first_name` and `last_name` for individuals or `organization_name` for organizations, optionally combined with `state`, `city` or a specialty. Each matching provider comes back with its NPI number.

#### Does the NPI Registry include email addresses?

No. NPPES does not publish email addresses, and the actor does not guess one from a phone number or endpoint. Electronic endpoints, where a provider published them, are returned unchanged in `endpoints`.

#### Can I use this as an NPI Registry API?

Yes. Start the actor through the Apify API with the same JSON input shown above and read the dataset when the run finishes. Larger collections continue automatically within a run; if the summary reports incomplete coverage, API callers can resume with `cursor` while keeping the other input values unchanged.

#### Where does the information come from?

The source is the official CMS NPPES NPI Registry API, version 2.1. Each row links to the official provider page and includes `fetched_at`. Deactivated or unpublished records may be absent from this API. The source can update between requests, so repeated exports may reflect changed provider information.

# Actor input Schema

## `first_name` (type: `string`):

First name; a trailing \* requires at least two leading characters.

## `last_name` (type: `string`):

Last name; a trailing \* requires at least two leading characters.

## `organization_name` (type: `string`):

Organization name; a trailing \* requires at least two leading characters.

## `taxonomy_description` (type: `string`):

Specialty description such as Dentist or Cardiovascular Disease. Taxonomy codes are not accepted.

## `city` (type: `string`):

City matched against the selected address purpose.

## `state` (type: `string`):

Two-letter state or territory. Requires another search criterion.

## `postal_code` (type: `string`):

US ZIP (5 or 9 digits) or prefix with a trailing *, such as 752*. Foreign postcodes require country_code.

## `country_code` (type: `string`):

Two-letter country code. Requires another search criterion.

## `npi_numbers` (type: `array`):

NPI numbers as strings, validated with the NPI checksum. Empty values and duplicates are ignored; invalid values produce warnings. Lookups precede search results. max_items also limits this list (default 100); increase it to process the full list.

## `provider_type` (type: `string`):

Individual (NPI-1), organization (NPI-2), or either type. Applies to search, not explicit NPI lookups.

## `address_purpose` (type: `string`):

any matches any published address, including mailing; PRIMARY restricts to the primary practice address; SECONDARY to secondary practices; LOCATION to either practice; MAILING to mailing.

## `use_first_name_alias` (type: `boolean`):

Include first-name aliases in name searches.

## `max_items` (type: `integer`):

Maximum unique providers across lookups, searches and cursor requests, including NPI lists (default 100). Unprocessed NPI numbers produce a warning and partial output. Increase this limit to process the full list. Free users receive at most 10 providers.

## `split_large_searches` (type: `boolean`):

Split full searches into US ZIP prefixes to retrieve more than the NPPES 1200-record window. A full exact ZIP remains incomplete and produces a warning.

## `cursor` (type: `string`):

Continuation token from the previous response. Keep all other input values unchanged. Large requests return this token before the request budget expires.

## Actor input object example

```json
{
  "npi_numbers": [
    "1003000126"
  ],
  "provider_type": "any",
  "address_purpose": "any",
  "use_first_name_alias": false,
  "max_items": 100,
  "split_large_searches": false
}
```

# Actor output Schema

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

One row per delivered provider.

## `output` (type: `string`):

Counts, warnings and continuation information.

# 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 = {
    "npi_numbers": [
        "1003000126"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/npi-registry").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 = { "npi_numbers": ["1003000126"] }

# Run the Actor and wait for it to finish
run = client.actor("s-r/npi-registry").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 '{
  "npi_numbers": [
    "1003000126"
  ]
}' |
apify call s-r/npi-registry --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/npi-registry"
        }
    }
}
```

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/zUTzTQLU74HSy4lvV/builds/KXMph3AlI2GBRnROw/openapi.json
