# NPI Registry Scraper (US Healthcare Providers) (`scrapyx/npi-registry-scraper`) Actor

US healthcare providers from the official NPPES NPI Registry: NPI number, doctor or organization name, credential, specialty, license, practice and mailing address, phone and fax. Search by specialty, name, city, state or ZIP, or look up NPI numbers.

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

## Pricing

from $0.84 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## NPI Registry Scraper (US Healthcare Providers)

US doctors, dentists, therapists, clinics and other healthcare providers from
the **official NPPES NPI Registry** run by CMS. For each provider: **NPI
number**, name (individual or organization), credential, **primary specialty**
and taxonomy code, **license number and state**, **practice address with phone
and fax**, mailing address, status, enumeration and last-update dates, and —
for organizations — the authorized official.

Uses the registry's public API. No login, no key, no browser, no proxy.

### What it is for

- **Healthcare lead lists** — every dentist in a city, every family physician in a ZIP.
- **Provider verification** — check NPI numbers, specialties and licenses.
- **Network and market mapping** by specialty and area.

### Input

```json
{
  "searches": [
    {"specialty": "dentist", "city": "Austin", "state": "TX"},
    {"specialty": "family medicine", "postalCode": "10001"}
  ],
  "npiNumbers": ["1043458821"],
  "providerType": "any",
  "maxItems": 200
}
```

Search keys: `specialty`, `firstName`, `lastName`, `organizationName`, `city`,
`state`, `postalCode`.

### Four things worth knowing

#### 1. At most 1,200 providers per search

The registry stops paging at 1,200 results. Past that it keeps returning the
**same 200 providers** again rather than an error — a naive scraper repeats
them. This Actor stops at the limit and marks the search `possiblyTruncated`
when there may be more; split it by city or ZIP code to get everyone.

#### 2. The registry never says how many matched

Its count field is only the size of each response. So the only honest signal
of a cut-off is a full last page — that's what the truncation flag reports.

#### 3. The first address isn't always the practice

Each provider has a mailing and a practice ("location") address, and their
order varies — the practice came first for only about 1 in 5 providers. The
Actor returns them as `practiceAddress` and `mailingAddress`, never "address 1".

#### 4. Errors come back looking like success

A misspelled specialty or a state on its own is answered normally, with an
error message inside. The Actor turns that into an error row with the
registry's own wording (e.g. "No taxonomy codes found with entered description").

ZIP codes are formatted as `78746-7759` (the registry sends `787467759`).

### Output

```json
{
  "recordType": "PROVIDER",
  "npi": "1154494250",
  "providerType": "organization",
  "name": "360 DENTAL CARE P.A.",
  "primarySpecialty": "Dentist, General Practice",
  "licenseNumber": "16292",
  "practiceAddress": {
    "line1": "3660 STONERIDGE RD STE B101", "city": "AUSTIN", "state": "TX",
    "postalCode": "78746-7759", "phone": "512-327-3631", "fax": "512-327-2234"
  },
  "registryUrl": "https://npiregistry.cms.hhs.gov/provider-view/1154494250"
}
```

Every row also carries the registry's complete record (all taxonomies,
identifiers, other names, practice locations, endpoints).

# Actor input Schema

## `searches` (type: `array`):

One search per entry. Keys: specialty (e.g. 'dentist', 'family medicine', 'physical therapist'), firstName, lastName, organizationName, city, state (2 letters), postalCode. A state alone is refused by the registry — add a specialty, city or name.

## `npiNumbers` (type: `array`):

Look up specific 10-digit NPI numbers.

## `providerType` (type: `string`):

Individual clinicians or organizations.

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

The registry serves at most 1,200 per search; 0 = up to that.

## `maxConcurrency` (type: `integer`):

Searches in parallel.

## `minRequestInterval` (type: `number`):

Global pacing.

## Actor input object example

```json
{
  "searches": [
    {
      "specialty": "dentist",
      "city": "Austin",
      "state": "TX"
    },
    {
      "specialty": "family medicine",
      "postalCode": "10001"
    }
  ],
  "npiNumbers": [],
  "providerType": "any",
  "maxItems": 200,
  "maxConcurrency": 3,
  "minRequestInterval": 0.4
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# 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 = {
    "searches": [
        {
            "specialty": "dentist",
            "city": "Austin",
            "state": "TX"
        },
        {
            "specialty": "family medicine",
            "postalCode": "10001"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/npi-registry-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 = { "searches": [
        {
            "specialty": "dentist",
            "city": "Austin",
            "state": "TX",
        },
        {
            "specialty": "family medicine",
            "postalCode": "10001",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/npi-registry-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 '{
  "searches": [
    {
      "specialty": "dentist",
      "city": "Austin",
      "state": "TX"
    },
    {
      "specialty": "family medicine",
      "postalCode": "10001"
    }
  ]
}' |
apify call scrapyx/npi-registry-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/npi-registry-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/xQLgCdulWqeBgm6py/builds/1ui3dafGTzErLrJny/openapi.json
