# US Healthcare Providers (NPI Registry) Scraper (`hexadatalabs/us-healthcare-providers-npi-scraper`) Actor

Use this when you need US healthcare organizations or practitioners from the official NPI Registry (NPPES): clinics, hospitals, pharmacies, dentists by specialty, city, state or ZIP, with address, phone, taxonomy and NPI. No key; large areas split automatically. Pay per result.

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

## Pricing

$1.50 / 1,000 provider (result)s

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

## US Healthcare Providers (NPI Registry) Scraper

**US Healthcare Providers (NPI Registry) Scraper** returns healthcare organizations from the official NPI Registry (NPPES, run by CMS) as clean JSON: clinics, hospitals, pharmacies, dental and medical practices, labs and home-health agencies filtered by specialty (taxonomy), name, city, state or ZIP code, with practice address, phone, fax, taxonomy code, license and NPI number. It uses the official NPPES API (no key), splits large areas automatically so a whole state fits in one run, and you **pay per result**. Individual practitioners are included only when you ask for them.

### What you get

One item per provider, same field names as every Hexadata Actor:

| Field | Type | Description |
| --- | --- | --- |
| `id` / `npi` | string | NPI number (10 digits), unique |
| `name` | string | Organization name, or "First Last, Credential" for individuals |
| `enumerationType` / `isOrganization` | string, boolean | `NPI-2` organization or `NPI-1` individual |
| `organizationName` | string | null | |
| `firstName` / `lastName` / `credential` / `gender` / `soleProprietor` | mixed | Individuals only (with `includeIndividuals`) |
| `organizationalSubpart` / `parentOrganization` | boolean | null, string | null | Subpart of a larger organization |
| `otherNames` | string\[] | Doing-business-as and former names |
| `status` | string | `active` or `deactivated` |
| `enumerationDate` / `lastUpdated` | string | null | NPI issue date and last record update (`YYYY-MM-DD`) |
| `taxonomy` / `taxonomyCode` / `taxonomyGroup` | string | null | Primary specialty, e.g. "Dentist, General Practice" / `1223G0001X` |
| `licenseNumber` / `licenseState` | string | null | License of the primary taxonomy |
| `taxonomies` | object\[] | All taxonomies: code, description, primary, state, license |
| `address` / `address2` / `city` / `state` / `postalCode` / `country` | string | null | Practice location (ZIP+4 as `78746-7759`) |
| `phone` / `fax` | string | null | Practice location, formatted `512-327-3631` |
| `mailingAddress` | string | null | Mailing address in one line |
| `practiceLocationsCount` | integer | Additional practice locations (details in `raw`) |
| `url` | string | Provider page on npiregistry.cms.hhs.gov |
| `source`, `scrapedAt` | string | Attribution and extraction timestamp |

With `includeContacts: true` organizations also carry `authorizedOfficialName`, `authorizedOfficialTitle` and `authorizedOfficialPhone`. With `includeRaw: true` the original NPPES record is attached as `raw`.

### Use cases

- **Sales teams selling to clinics and practices** (dental supplies, medical devices, practice software, billing, staffing) build territory lists by specialty and ZIP prefix with a phone number for every organization.
- **Healthtech and pharma marketing teams** pull every pharmacy, urgent-care center or dialysis clinic in a state to size a market or seed a CRM, deduplicated by NPI.
- **Healthcare recruiters and locum agencies** map hospitals, group practices and FQHCs in a metro area, with `parentOrganization` to see which belong to a health system.
- **Payers, credentialing and compliance teams** verify NPIs, taxonomy codes, license numbers and `status` in bulk against the official source.
- **AI agents and RAG pipelines** call the Actor as an MCP tool ("list physical-therapy clinics in ZIP 787 with their phone numbers") and get structured results instead of scraping web directories.

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `taxonomies` | string\[] | `[]` (prefill `["Dentist"]`) | NPPES taxonomy descriptions, e.g. `Dentist`, `Family Medicine`, `Pharmacy`, `Clinic/Center`; trailing `*` wildcard (`Dent*`). Searched one after another. |
| `organizationName` | string | – | Organization name, trailing `*` allowed (`Mayo*`). |
| `city` | string | – (prefill `Austin`) | Practice-location city. |
| `state` | select | any (prefill `TX`) | Two-letter state; must be combined with another filter (NPPES rule). |
| `postalCodes` | string\[] | `[]` | ZIP codes (`78701`) or prefixes of two or more digits (`787`, `78`). |
| `country` | string | `US` | Two-letter country code of the practice location. |
| `includeIndividuals` | boolean | `false` | Also return individual practitioners (NPI-1). |
| `enumeratedFrom` | date | – | Only NPIs issued on or after this date (new providers). |
| `onlyNewSinceLastRun` | boolean | `false` | For schedules: skip NPIs delivered by earlier runs (state in the named store `hexadata-us-healthcare-providers-npi`). |
| `maxResults` | integer | `100` | Hard cap on results and cost. |
| `includeContacts` | boolean | `false` | Add the authorized official of each organization. |
| `includeRaw` | boolean | `false` | Attach the original NPPES record. |
| `proxyConfiguration` | object | off | Not needed. |

At least one of `taxonomies`, `organizationName`, `city` or `postalCodes` is required. Invalid input (bad state code, wildcard too short, malformed date) stops the run before the first request, so it costs nothing.

**How large areas work:** NPPES returns at most 1,200 providers per query. When a query hits that cap, the Actor splits it by ZIP-code prefix (`00*`–`99*`, then `780*`… as needed) and deduplicates by NPI, so `taxonomies: ["Dentist"], state: "TX", maxResults: 10000` simply works; in a saved test it returned 1,300 Texas dentists in 84 API requests.

### Output example

A real item from the run saved in `tests/test1_taxonomy_city` (`taxonomies: ["Dentist"]`, `city: "Austin"`, `state: "TX"`, 2026-10-27):

```json
{
  "id": "1154494250",
  "npi": "1154494250",
  "name": "360 DENTAL CARE P.A.",
  "enumerationType": "NPI-2",
  "isOrganization": true,
  "organizationName": "360 DENTAL CARE P.A.",
  "firstName": null,
  "lastName": null,
  "credential": null,
  "gender": null,
  "soleProprietor": null,
  "organizationalSubpart": false,
  "parentOrganization": null,
  "otherNames": ["MICHAEL B. NUSSBAUM D.D.S."],
  "status": "active",
  "enumerationDate": "2006-11-16",
  "lastUpdated": "2020-08-22",
  "taxonomy": "Dentist, General Practice",
  "taxonomyCode": "1223G0001X",
  "taxonomyGroup": "193400000X - Single Specialty Group",
  "licenseNumber": "16292",
  "licenseState": "TX",
  "taxonomies": [{ "code": "1223G0001X", "description": "Dentist, General Practice", "primary": true, "state": "TX", "license": "16292" }],
  "address": "3660 STONERIDGE RD STE B101",
  "address2": null,
  "city": "Austin",
  "state": "TX",
  "postalCode": "78746-7759",
  "country": "US",
  "phone": "512-327-3631",
  "fax": "512-327-2234",
  "mailingAddress": "3660 STONERIDGE RD STE B101, Austin, TX, 78746-7759, US",
  "practiceLocationsCount": 0,
  "url": "https://npiregistry.cms.hhs.gov/provider-view/1154494250",
  "source": "NPPES NPI Registry, Centers for Medicare & Medicaid Services (CMS)",
  "scrapedAt": "2026-10-27T12:51:27.903Z"
}
```

### Pricing & cost examples

**$1.50 per 1,000 providers** (pay per event, charged only for items saved to the dataset; duplicates and failed runs are never billed). `maxResults` is a hard cost cap and Apify platform usage is included.

- A first look: `maxResults: 50` ≈ **$0.08**.
- All pharmacies in the Austin area (`postalCodes: ["787"]`, about 600) ≈ **$0.90**.
- Every dental practice in Texas (about 10,000 organizations) ≈ **$15**; the whole US for one specialty (100,000+) ≈ $150+.

### Use with AI agents (MCP)

Every Apify Actor is available as a tool through the [Apify MCP server](https://mcp.apify.com). Add this server to Claude, Cursor, VS Code or any MCP client (OAuth sign-in on first use, or an `Authorization: Bearer <APIFY_TOKEN>` header):

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=hexadatalabs/us-healthcare-providers-npi-scraper"
    }
  }
}
```

Then ask, for example:

> "Give me the physical-therapy clinics in ZIP codes starting with 787 with their phone numbers, newest registrations first."

The agent calls the Actor with `{"taxonomies":["Physical Ther*"],"postalCodes":["787"],"maxResults":200}` and sorts by `enumerationDate`. The Actor description and every input field start with "Use this when…" so tool selection works without extra prompting.

#### Pay with USDC (x402, no account needed)

AI agents can pay for this Actor directly with USDC through Apify's x402 support, with no Apify account: the agent buys a prepaid token from Apify AGI with a [Coinbase Agentic Wallet](https://docs.cdp.coinbase.com/agentic-wallet/cli/welcome) (USDC on Base, minimum $1) and uses that token as a normal API token. This Actor runs with **limited permissions**, which is what makes it eligible. Current steps are in [Apify's x402 guide](https://docs.apify.com/integrations/x402):

```bash
npx -y awal auth login <email> && npx awal auth verify <code>   # one-time wallet setup; then fund it with USDC and a little ETH on Base
TOKEN=$(npx awal x402 pay 'https://agi.apify.com/protocols/x402/prepaid-tokens?amount=1&currency=usd' --max-amount 1000000 --json | jq -r .token)
curl -s -X POST "https://api.apify.com/v2/acts/hexadatalabs~us-healthcare-providers-npi-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"taxonomies":["Dentist"],"city":"Austin","state":"TX","maxResults":50}'
```

Cost: **$1 USDC ≈ 666 providers** at this Actor's price; the token balance is a hard spending cap, and the token expires 14 days after purchase.

### API & integrations

```bash
curl -X POST "https://api.apify.com/v2/acts/hexadatalabs~us-healthcare-providers-npi-scraper/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"taxonomies":["Dentist"],"city":"Austin","state":"TX","maxResults":50}'
```

```python
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("hexadatalabs/us-healthcare-providers-npi-scraper").call(run_input={
    "taxonomies": ["Pharmacy"], "state": "TX", "postalCodes": ["787"], "includeContacts": True, "maxResults": 1000,
})
for p in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(p["npi"], p["name"], p["phone"], p["postalCode"])
```

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('hexadatalabs/us-healthcare-providers-npi-scraper').call({
    taxonomies: ['Clinic/Center'], state: 'FL', enumeratedFrom: '2026-01-01', onlyNewSinceLastRun: true, maxResults: 5000,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((p) => `${p.enumerationDate} · ${p.name} · ${p.city}`).join('\n'));
```

**Schedules and webhooks:** create a weekly Schedule in Apify Console with `onlyNewSinceLastRun: true` (and optionally `enumeratedFrom`) to receive only providers you have not seen before, then add a webhook or integration (e-mail, Slack, Google Sheets, Make, Zapier, HTTP) on the `ACTOR.RUN.SUCCEEDED` event.

### Limitations & legal

- **Source:** the official NPPES NPI Registry API v2.1 (`npiregistry.cms.hhs.gov/api`), which needs no key; the Actor identifies itself with a User-Agent and pauses between requests. NPPES data is public information released by CMS under the Freedom of Information Act; keep the attribution in `source`. Hexadata is not affiliated with CMS.
- **Organizations by default:** NPI-2 records (clinics, hospitals, pharmacies, group practices). Individual practitioners (NPI-1) are named persons and are returned only with `includeIndividuals: true`; the authorized official of an organization only with `includeContacts: true`.
- **Taxonomy names must match NPPES wording** ("Dentist", "Family Medicine", "Pharmacy", "Clinic/Center", "Physical Therapist"); use a trailing `*` to widen. Full list at taxonomy.nucc.org.
- **No sorting or total count** in NPPES: results come in the API's order, and `onlyNewSinceLastRun` works by remembering delivered NPIs (up to 50,000 per account store), not by date. Use `enumeratedFrom` to keep only recently issued NPIs.
- **Address of the practice location** is used for `city`, `state` and ZIP filters, as in NPPES; `mailingAddress` is given for reference.
- If NPPES changes its response format and three consecutive pages lack the mandatory fields, the run fails with `SITE_LAYOUT_CHANGED` and nothing is charged.

### Changelog

- **0.1.0** (2026-10-27): first release. Taxonomy, name, city, state, ZIP and country filters; automatic ZIP-prefix splitting past the 1,200-result cap; organizations by default; incremental mode; dataset table view; MCP-ready descriptions.

### Support

Open an issue in the **Issues** tab of this Actor (or e-mail Hexadata through the Apify profile). Issues are answered within 24 hours and confirmed bugs are fixed in a `beta` build within 48 hours.

#### En español

**US Healthcare Providers (NPI Registry) Scraper** extrae organizaciones de salud de EE.UU. (clínicas, hospitales, farmacias, consultorios dentales y médicos) del registro oficial NPI (NPPES, de CMS) mediante su API, sin clave. Filtra por especialidad, nombre, ciudad, estado o código postal y devuelve dirección, teléfono, fax, código de taxonomía, licencia y NPI en JSON limpio; cuando un área supera el tope de 1,200 resultados de NPPES, el actor la divide automáticamente por prefijo postal. Precio: **$1.50 por cada 1,000 resultados**; `maxResults` limita el costo. Solo organizaciones por defecto; los profesionales individuales solo si se piden.

# Actor input Schema

## `taxonomies` (type: `array`):

NPPES taxonomy descriptions, one per line, e.g. "Dentist", "Family Medicine", "Pharmacy", "Physical Therapist", "Clinic/Center". A wildcard \* at the end matches sub-specialties ("Dent\*" = Dentist, Dental Hygienist...; at least two characters before the \*). Full list: https://taxonomy.nucc.org/

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

Filter by organization name, wildcard \* at the end allowed, e.g. "Mayo\*", "CVS\*". Organizations only.

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

City of the practice location, e.g. "Austin". NPPES matches the city name as registered (usually upper case, exact word).

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

Two-letter US state or territory code of the practice location, e.g. TX. Must be combined with another filter.

## `postalCodes` (type: `array`):

ZIP codes ("78701") or prefixes of at least two digits ("787" = all of Austin area, "78" = central Texas). Use prefixes to cover a region without naming every city.

## `country` (type: `string`):

Two-letter country code of the practice location. NPPES is a US registry; a few providers abroad (e.g. MX, CA) are registered too.

## `includeIndividuals` (type: `boolean`):

Off: only organizations (NPI-2: clinics, hospitals, pharmacies, group practices). On: also individual practitioners (NPI-1: physicians, dentists, nurses), which are named persons; turn on only if you have a lawful basis to use their public practice data.

## `enumeratedFrom` (type: `string`):

Only providers whose NPI was issued on or after this date (YYYY-MM-DD), e.g. new clinics since 2026-01-01. Applied after download, so the run still scans the area.

## `onlyNewSinceLastRun` (type: `boolean`):

Use this on a schedule: the Actor remembers the NPIs it delivered (shared store "hexadata-us-healthcare-providers-npi" in your account) and returns only providers it has not delivered before. The first run saves everything that matches.

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

Stop after this many providers. NPPES returns at most 1,200 per query; the Actor splits larger areas by ZIP prefix automatically, so a whole state is possible.

## `includeContacts` (type: `boolean`):

Add the organization's authorized official (name, title, phone) as published in NPPES. Off by default because it names an individual.

## `includeRaw` (type: `boolean`):

Attach the original NPPES API record under "raw" (all addresses, identifiers, endpoints, practice locations).

## `proxyConfiguration` (type: `object`):

NPPES is an open API that does not need a proxy; leave it off.

## Actor input object example

```json
{
  "taxonomies": [
    "Dentist"
  ],
  "city": "Austin",
  "state": "TX",
  "country": "US",
  "includeIndividuals": false,
  "onlyNewSinceLastRun": false,
  "maxResults": 50,
  "includeContacts": false,
  "includeRaw": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "taxonomies": [
        "Dentist"
    ],
    "city": "Austin",
    "state": "TX",
    "maxResults": 50,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("hexadatalabs/us-healthcare-providers-npi-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 = {
    "taxonomies": ["Dentist"],
    "city": "Austin",
    "state": "TX",
    "maxResults": 50,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("hexadatalabs/us-healthcare-providers-npi-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 '{
  "taxonomies": [
    "Dentist"
  ],
  "city": "Austin",
  "state": "TX",
  "maxResults": 50,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call hexadatalabs/us-healthcare-providers-npi-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hexadatalabs/us-healthcare-providers-npi-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/fhc6y9BnO12oqbRLE/builds/73tsXlh1AoKBl6mz1/openapi.json
