# NPI Registry Scraper - US Healthcare Providers (`dataio/nppes-npi-provider-registry`) Actor

Scrape the NPPES NPI Registry: US healthcare providers as one row per practice location, with specialty (taxonomy), license number, phone, fax and, for organizations, the authorized official. Filter by specialty, state, city and postal code for healthcare leads.

- **URL**: https://apify.com/dataio/nppes-npi-provider-registry.md
- **Developed by:** [Tom Awake](https://apify.com/dataio) (community)
- **Categories:** Lead generation, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 provider locations

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/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

### What does NPI Registry Scraper do?

US healthcare providers from the official NPI Registry — **one row per
practice location**, with specialty in plain language, licence number,
phone, fax, and the authorized official for organizations.

**No login. No API key. No proxies.**

### One row per location, not per provider

The registry returns a provider with their addresses nested inside. For a
field team that is the wrong shape: a practice operating from three sites is
**three targets, three phone numbers, three visits** — and a single row
hides two of them.

Measured on real data:

| Query | Providers | Location rows | Gain |
|---|---|---|---|
| Hospitalists, New York organizations | 23 | **40** | **+74 %** |
| Cardiology, Houston | 3 | 5 | +67 % |
| Dentists, California | 48 | 60 | +25 % |

Phone coverage runs **97–100 %** on practice locations.

Mailing addresses are skipped by default. A mailing address is often a PO box
or a billing service — the wrong door for a visit — but you can include them
with one switch when you need them for correspondence.

### The authorized official

For organizations, the registry names the person who signs for the entity —
CFO, Administrator, Owner — with their title and often a direct phone number.
That is the decision-maker, and it comes free with the record.

The **Decision makers** view in the dataset shows exactly that column set.

### Output

| Field | Example |
|---|---|
| `providerName` | ADIRONDACK MEDICAL CENTER |
| `entityType` | Organization / Individual |
| `specialty` | Dentist, General Practice |
| `taxonomyCode` | 1223G0001X |
| `otherSpecialties` | secondary taxonomies |
| `licenseNumber`, `licenseState` | 54634, CA |
| `addressType` | Practice location / Additional location / Mailing |
| `address1`, `address2`, `city`, `state`, `postalCode`, `postalCodeFull` | |
| `phone`, `fax` | 518-897-2479 |
| `authorizedOfficial`, `authorizedOfficialTitle`, `authorizedOfficialPhone` | CURTIS EADE, CFO |
| `credential`, `sex`, `status`, `soleProprietor` | |

`sex` carries what NPPES publishes — `M` or `F`, the sex recorded
on the registry application — and is empty for organisations
(`NPI-2`), which do not have one. It is named for what it holds
rather than `gender`, which the source does not claim to know.
| `enumerationDate`, `lastUpdated` | |
| `npi`, `npiUrl` | 1760813802 |

`postalCode` gives the five-digit ZIP for joins; `postalCodeFull` keeps the
ZIP+4 exactly as registered.

### Input

```json
{
  "taxonomy": "Dentist",
  "state": "CA",
  "practiceLocationsOnly": true,
  "maxItems": 500
}
```

| Field | Default | Notes |
|---|---|---|
| `taxonomy` | `Dentist` | Specialty as the registry spells it |
| `state` | `CA` | Two-letter code |
| `entityType` | `both` | Individuals, organizations, or both |
| `practiceLocationsOnly` | `true` | Skip mailing addresses |
| `onlyWithPhone` | `false` | Keep only locations with a phone number |
| `maxItems` | `500` | Counts locations, not providers |
| `city`, `postalCode` | — | Narrow geographically |
| `organizationName`, `firstName`, `lastName` | — | Search by name |

**The registry refuses a search on state alone.** Keep a specialty, city,
postcode or name alongside it — the Actor says so plainly instead of
returning an empty file.

### Use cases

- **Medical device and pharma field sales** — territory lists by specialty
  and postcode, one row per site to visit.
- **Healthcare staffing** — practices in a specialty and area, with phone.
- **Provider network building** — who practises where, with licence numbers.
- **Market sizing** — count providers by specialty across states.
- **Data cleaning** — verify an NPI, its current specialty and address.

### Limits, honestly

- **Specialty is matched on the registry's own wording.** "Cardiology"
  matches several taxonomies including "Pharmacist, Cardiology"; a narrow
  query may return adjacent specialties. Check `specialty` and
  `taxonomyCode` on the rows.
- Licence numbers are present on roughly a third to a half of rows,
  depending on specialty — organizations often have none.
- The registry reflects what providers self-report and can lag a move or a
  retirement. `lastUpdated` tells you how stale a record is.
- This is provider directory data, not patient data, and contains no
  clinical information.
- Requests are paced out of courtesy to a free public service.
- Not affiliated with CMS or the NPI Registry.

### How much does it cost?

You pay per provider location returned: **$0.006 each**, that is $6.00 per 1,000. There is no start fee, and subscription plans pay less per provider location.

The example input below asks for up to 200 provider locations, so it costs **$1.20 at most**.

If a run reaches the spending limit you set, the output stops at that limit and never goes past it. You are never charged for rows that were not delivered.

### Use NPI Registry Scraper as an API

Call it from your own code with the Apify client, here in Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("DataIO/nppes-npi-provider-registry").call(run_input={
    'taxonomy': 'Dentist',
    'state': 'CA',
    'maxItems': 200,
    'practiceLocationsOnly': True,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

It also works from JavaScript, Make, Zapier, n8n, and from AI agents through the Apify MCP server.

### Other actors you might like

- [FDA 510(k) Scraper](https://apify.com/DataIO/openfda-510k-device-clearances): Device Clearances Data
- [FDA Recalls Scraper](https://apify.com/DataIO/openfda-recalls-enforcement): openFDA Enforcement
- [CMS Open Payments Scraper](https://apify.com/DataIO/cms-open-payments-physicians): Physician Payments

### FAQ

#### Is it legal to use this data?

The actor reads public data from its official source, without logging in and without bypassing any access control. What you do with the data, for example contacting people listed in it, is your responsibility under the laws that apply to you, such as GDPR in Europe.

#### Can I run it on a schedule?

Yes. Create a schedule in Apify Console, daily or weekly for example, and each run delivers a fresh dataset, which you can send by email, webhook or integration.

#### Can AI agents use it?

Yes. It is available through the Apify MCP server, and every input field is described in its input schema, so an agent can call it directly.

# Actor input Schema

## `taxonomy` (type: `string`):

Plain-language specialty as the registry spells it — for example Dentist, Cardiology, Physical Therapist, Pharmacy, Nurse Practitioner, Orthopaedic Surgery.

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

Two-letter US state code, for example CA, TX, NY. The registry refuses a search on state alone, so keep a specialty or a city alongside it.

## `entityType` (type: `string`):

Individuals are practitioners. Organizations are practices, clinics and hospitals — those carry an authorized official, which is the person who signs.

## `onlyWithPhone` (type: `boolean`):

Recommended when building a call list.

## `practiceLocationsOnly` (type: `boolean`):

Keeps practice locations only. A mailing address is often a PO box or a billing service, which is the wrong door for a field visit.

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

One row per practice location, so a provider with three sites yields three rows. Counts locations, not providers.

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

For example "San Diego".

## `postalCode` (type: `string`):

Five-digit ZIP, for example 92101.

## `organizationName` (type: `string`):

For example "Kaiser".

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

Individual practitioners only.

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

Individual practitioners only.

## Actor input object example

```json
{
  "taxonomy": "Dentist",
  "state": "CA",
  "entityType": "both",
  "onlyWithPhone": false,
  "practiceLocationsOnly": true,
  "maxItems": 500
}
```

# Actor output Schema

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

Every row produced by the run, in JSON.

# 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 = {
    "taxonomy": "Dentist",
    "state": "CA",
    "maxItems": 500
};

// Run the Actor and wait for it to finish
const run = await client.actor("dataio/nppes-npi-provider-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 = {
    "taxonomy": "Dentist",
    "state": "CA",
    "maxItems": 500,
}

# Run the Actor and wait for it to finish
run = client.actor("dataio/nppes-npi-provider-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 '{
  "taxonomy": "Dentist",
  "state": "CA",
  "maxItems": 500
}' |
apify call dataio/nppes-npi-provider-registry --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dataio/nppes-npi-provider-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/h3hG3gFTNkrzEH1mU/builds/Wsz70QkqvQEWtsDbX/openapi.json
