# Us Healthcare Npi Medical Practice Lead Enricher (`arezdev/us-healthcare-npi-medical-practice-lead-enricher`) Actor

Find US healthcare providers and organizations in the official NPPES NPI Registry. Filter by specialty and location, extract public practice contacts and authorized officials, and optionally enrich confirmed websites with emails and booking signals.

- **URL**: https://apify.com/arezdev/us-healthcare-npi-medical-practice-lead-enricher.md
- **Developed by:** [Arezdev](https://apify.com/arezdev) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 npi record enricheds

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

**Find US medical practices, their authorized decision makers, and official contact details directly from the federal NPPES NPI Registry.**

Build prospect lists for dental practices, medical clinics, physical therapy centers, laboratories, and other registered healthcare organizations. Optionally confirm their public websites and collect homepage emails, social links, and booking software signals. No browser or API key is required for the federal registry search.

Best for healthcare organization research and practice enrichment. Each successful row is an NPI record. An authorized official is not necessarily the owner; use narrow geographic queries to work within the registry search limit and improve relevance.

### Ready-to-run example

The Input form includes public example values. A fresh `apify run` uses the input schema defaults. To explicitly select the small sample, including when input was saved by an earlier local run, use:

```sh
apify run --input-file .actor/input.example.json
```

You can also paste [.actor/input.example.json](.actor/input.example.json) into the JSON input editor in Apify Console. Replace the example sources with your own targets and increase the limits when you are ready.

### How to use

1. Select a specialty and a two-letter state abbreviation.
2. Optionally narrow the search by city or ZIP code. Clear City to search an entire state; omitting City retains the Austin default.
3. Keep **Organizations and practices (NPI-2)** selected for organization leads. Choose NPI-1 for individual providers.
4. Enable website enrichment if you also need public homepage contacts and booking software.
5. Set the maximum saved records, run the Actor, and download JSON, CSV, Excel, or XML from the dataset.

The prefilled sample finds three dentists in Austin, Texas, with website enrichment disabled. The specified `maxItems` default is 100; the Console prefill is 3. On an available network, the direct sample normally completes within a few seconds. Federal API outages and throttling can affect timing.

```json
{
  "taxonomyDescription": "Dentist",
  "state": "TX",
  "city": "AUSTIN",
  "enumerationType": "NPI-2",
  "enrichWebsiteAndContacts": false,
  "maxItems": 3,
  "timeoutSecs": 15
}
```

### What data can you extract?

| Data | Output fields |
| --- | --- |
| Federal provider identity | `npiNumber`, `enumerationType`, `organizationName`, `dbaName` |
| Specialty | `primaryTaxonomyCode`, `specialtyDescription` |
| Authorized official | `authorizedOfficialFullName`, `authorizedOfficialTitle`, `authorizedOfficialPhone` |
| Practice location | `practicePhone`, `practiceFax`, `streetAddress`, `city`, `state`, `zipCode` |
| Registration signals | `enumerationDate`, `isNewlyRegistered90Days` |
| Optional website contacts | `discoveredWebsite`, `primaryEmail`, `allEmails`, `instagramUrl`, `facebookUrl` |
| Booking software | `bookingWidgetDetected`: NexHealth, Zocdoc, LocalMed, Calendly, JaneApp, Mindbody |
| Result diagnostics | `status`, `scrapedAt`, `errorMessage` |

The authorized official is the person listed by NPPES, such as an owner, officer, administrator, or director. Their registry title and telephone are reported as supplied; the Actor does not assert that the number is a personal line. NPI-1 records normally have no authorized official. `organizationName` holds the individual provider's full name in those records.

The primary practice address comes exclusively from `LOCATION`, never from a mailing address. The 90-day flag uses the enumeration date and UTC extraction time, excluding future dates. Missing strings remain empty; missing collections are empty arrays. `allEmails` and `bookingWidgetDetected` are arrays in an otherwise flat record.

### Input settings

| Setting | Default | Details |
| --- | --- | --- |
| `taxonomyDescription` | `Dentist` | NPPES specialty description, 2–120 characters. Examples: `Physical Therapist`, `Clinical Medical Laboratory`, `Clinic/Center`. |
| `state` | `TX` | US state or territory abbreviation. |
| `city` | `AUSTIN` | Optional. Use `""` to remove this filter. |
| `postalCode` | Empty | Optional five-digit ZIP or ZIP+4. Clear City when searching another city. |
| `enumerationType` | `NPI-2` | `NPI-2` organizations or `NPI-1` individuals. |
| `enrichWebsiteAndContacts` | `false` | Best-effort public website discovery and homepage inspection. |
| `maxItems` | `100` | 1–5,000 saved rows, including errors; prefilled sample: 3. |
| `timeoutSecs` | `15` | 3–60 seconds per HTTP operation, including fallbacks. |
| `maxConcurrency` | `25` | 1–100 simultaneous optional enrichments. Federal pagination stays sequential. |
| `proxyConfiguration` | Automatic direct-first | Optional Apify proxy editor. See proxy behavior below. |

**MedSpa searches:** NPPES does not define one universal MedSpa taxonomy. Select the relevant registered medical specialty; providers without an NPI do not appear in the registry.

**Proxy behavior:** Federal NPPES requests always use direct access and incur no proxy traffic fees. Website requests try direct access first. HTTP 403, 429, or 503 can trigger a SHADER datacenter attempt, followed by the account's default datacenter proxy if available. Configured groups, including residential groups, are used only when `useApifyProxy: true` is explicitly selected. Custom proxy URLs are used as the selected transport. `useApifyProxy: false` with no custom proxy URLs forces direct access. Proxy availability and traffic fees depend on the account.

**Website confirmation:** Search results and public NPPES endpoint URLs supply candidates. The Actor checks up to three candidates per discovery stage and requires practice-name evidence plus a matching practice telephone or street/city/state address. Directory pages and social platforms are excluded as practice websites. Only a confirmed public website supplies contacts. No candidate is guessed or fabricated. A missing website is a supported outcome.

### Output example

This illustrative record shows the output shape. Contact details and NPI below are fictional sample data, not a live healthcare listing.

```json
{
  "npiNumber": "1234567890",
  "status": "SUCCESS",
  "enumerationType": "NPI-2",
  "organizationName": "AUSTIN EXAMPLE DENTAL PLLC",
  "dbaName": "AUSTIN EXAMPLE DENTAL",
  "primaryTaxonomyCode": "1223G0001X",
  "specialtyDescription": "Dentist, General Practice",
  "authorizedOfficialFullName": "ALEX J SMITH",
  "authorizedOfficialTitle": "OWNER",
  "authorizedOfficialPhone": "5125550101",
  "practicePhone": "512-555-0100",
  "practiceFax": "512-555-0199",
  "streetAddress": "123 MAIN ST SUITE 100",
  "city": "AUSTIN",
  "state": "TX",
  "zipCode": "787011234",
  "enumerationDate": "2026-09-01",
  "isNewlyRegistered90Days": true,
  "discoveredWebsite": "",
  "primaryEmail": "",
  "allEmails": [],
  "bookingWidgetDetected": [],
  "instagramUrl": "",
  "facebookUrl": "",
  "scrapedAt": "2026-10-20T12:00:00.000Z",
  "errorMessage": ""
}
```

`SUCCESS` means an official practice record with a valid NPI, name, and location was extracted. Optional enrichment failure preserves this status and adds a safe note such as `WEBSITE_NOT_CONFIRMED`. A successfully salvaged partial homepage can add `PARTIAL_HTML_SALVAGED`; absence of an email or booking widget then reflects only the available page prefix. `ERROR` indicates a failed registry request or incomplete official record and carries no custom event fee. A failed query produces one diagnostic row because no individual providers can be identified from an unavailable page. Zero matches produces an empty dataset.

### Use the results in Clay, n8n, Make, or your API

- **Clay:** Import the dataset as CSV or JSON. Use `npiNumber` as a stable deduplication key and map the authorized official, practice phone, and confirmed email into your enrichment table.
- **n8n:** Run the Actor using the Apify integration, retrieve the dataset after completion, filter `status` to `SUCCESS`, and send rows to your CRM.
- **Make:** Connect an Apify run-completed trigger to dataset retrieval and your destination application.
- **API:** The Actor output links to the run's default dataset. The Apify dataset items endpoint supports `format=json` and `clean=true`. Use your normal Apify connection for private datasets.

Use the overview dataset view to inspect human-readable columns before export. Potential spreadsheet formula strings are escaped, while valid telephone numbers and numeric strings retain their values.

### Pricing and limits

The custom pay-per-event event is **`practice-enriched`**. Each saved `SUCCESS` record can incur one event fee, including registry-only extraction and records with unavailable optional website enrichment. **`ERROR` rows cost $0 in custom event fees.** Both statuses count toward `maxItems` and the free-account cap.

The Store price is configured separately on Apify; this repository does not assign a live Store price. For a concrete example, at **$0.001 per successful practice**, 1,000 successful records cost **$1.00 in event fees**. A run with 900 successful records and 100 error rows costs **$0.90 in event fees** at that example rate. Actual Store event prices, platform compute/storage charges, any platform events, and optional proxy traffic can differ. Check the Actor's Pricing tab for the active rate.

Free Apify accounts can save at most **25 rows per run**. Paid accounts and local runs can save up to the requested maximum of 5,000. The Actor checks only the platform-provided paying flags and supports limited permissions without querying user profile endpoints. It stops cleanly when the custom event budget is exhausted and never applies that event to an `ERROR` row.

NPPES returns up to 200 records per request and accepts offsets through 1,000. Saturated searches are subdivided using postal prefixes, with NPIs deduplicated across pages. A ZIP that still saturates the API's 1,200-record window is reported in the logs; narrow the city or specialty to retrieve additional records. Registry coverage, upstream limits, and outages can produce fewer results than requested. Exact ZIP and ZIP+4 searches retain their original scope.

### FAQ and troubleshooting

**Why are some official or contact fields empty?** NPPES records are provider-reported. Individual providers normally have no authorized official, and some practices do not publish email addresses. The Actor does not invent missing details.

**Why was no website confirmed?** The practice may use a different brand, have an unindexed or blocked site, or publish insufficient matching identity evidence. Official registry details remain usable. Discovery and contacts are best effort, not guaranteed coverage.

**Will this find every email or booking integration?** Only public homepage content and links are inspected. Browser-rendered contacts, protected pages, hidden booking integrations, and contact-page-only emails may not appear. Detection reports a vendor signal, not an assertion that an appointment can currently be booked.

**Why is my ZIP search empty?** City defaults to Austin even when omitted. Set `city` to `""` when searching another area. Use an official NPPES specialty description; an arbitrary marketing category may not match a taxonomy.

**What do HTTP and network errors mean?** Safe codes such as `HTTP_ERROR`, `TIMEOUT`, or `CERT_HAS_EXPIRED` identify the affected public host. Per-target failures produce diagnostic rows or enrichment notes and do not crash the run. Invalid input is the only application-level reason to exit with code 1.

**Can I use the data for provider credentialing?** An NPI identifies a registered provider. It does not establish a current professional license, credentialing status, availability, or endorsement. Consult the relevant official sources for those checks.

### Local development and deployment

Use Node.js 22 or newer:

```sh
npm ci --ignore-scripts
npm run build
npm test
npm run smoke
npm run smoke:enrich
```

`npm test` uses `node:test` and sets `UV_THREADPOOL_SIZE=64`, `NODE_ENV=production`, and strict TLS in its child process. `npm run smoke` makes a real, direct, three-record NPPES request and verifies the extracted practice fields. Run it with `UV_THREADPOOL_SIZE=64` and `NODE_ENV=production` set in your shell for production-equivalent settings. Node.js receives these variables before startup. `npm start` reads the normal Apify INPUT record; with no local input it uses the documented defaults. No `.env` file is required or loaded.

The multi-stage `node:22-alpine` Dockerfile builds and tests the project, prunes development dependencies, and runs as the non-root `node` user with a 160 MB JavaScript heap ceiling. Container defaults are 256 MB memory and a 3,600-second run timeout. Publish or connect this directory through the Apify Console or CLI using the included Actor and storage schemas.

Before enabling Store monetization, register the **`practice-enriched`** event and its intended price in Apify's pay-per-event configuration. Verify the run's maximum charge in a test run. To keep error rows free of all event fees, do not configure a paid automatic default-dataset-item event. The SDK's platform pricing is the authority; unknown or inactive custom events are not charged by this Actor. Select `LIMITED_PERMISSIONS` in the Actor's deployment settings; the code requires no user-profile permission.

The implementation caps decompressed responses at 4 MB for HTML, 2 MB for JSON, and 15 MB for XML. HTML parsing has no external-entity resolution and caps nesting at 128. Public IP validation, DNS pinning, per-hop redirect checks, and TLS verification protect both direct connections and proxy tunnels. Dataset writes are serialized in batches of 100 or every five seconds. Abort, SIGTERM, and SIGINT stop network work and flush completed rows before shutdown. An ambiguous dataset write is not retried automatically, preventing duplicate billed writes; a safe terminal status reports the storage failure.

Official references: [NPPES API](https://npiregistry.cms.hhs.gov/api-page), [Apify charging manager](https://docs.apify.com/sdk/js/reference/class/ChargingManager), [Actor definition](https://docs.apify.com/platform/actors/development/actor-definition/actor-json).

# Actor input Schema

## `taxonomyDescription` (type: `string`):

Official specialty description, such as Dentist, Physical Therapist, Clinical Medical Laboratory, or Clinic/Center. MedSpas have no single NPPES taxonomy; choose the relevant medical specialty.

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

Two-letter state or territory abbreviation. Search filters apply to the practice location.

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

City name. Set an empty string to search the entire state. The Austin default also applies when this field is omitted.

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

Five-digit ZIP code or ZIP+4. Clear City when searching outside Austin.

## `enumerationType` (type: `string`):

Individual providers typically do not have an authorized official; those fields remain empty.

## `enrichWebsiteAndContacts` (type: `boolean`):

Discover a public website, confirm its practice identity, and inspect its homepage. Best effort; enrichment can be unavailable or blocked.

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

Includes successful records and free error rows. Free Apify accounts are limited to 25 saved rows per run.

## `timeoutSecs` (type: `integer`):

Total timeout for each request operation, including redirect and transport fallbacks.

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

The federal API is paginated sequentially; this controls optional website tasks.

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

The federal API always uses a direct connection. Websites use direct access first, then available datacenter proxies on HTTP 403/429/503. Configured Apify groups require explicit opt-in. Custom proxy URLs are used directly; explicitly disabling Apify proxy forces direct website requests.

## Actor input object example

```json
{
  "taxonomyDescription": "Dentist",
  "state": "TX",
  "city": "AUSTIN",
  "enumerationType": "NPI-2",
  "enrichWebsiteAndContacts": false,
  "maxItems": 3,
  "timeoutSecs": 15,
  "maxConcurrency": 25
}
```

# Actor output Schema

## `practices` (type: `string`):

Official NPPES records with optional confirmed website enrichment.

# 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 = {
    "taxonomyDescription": "Dentist",
    "state": "TX",
    "city": "AUSTIN",
    "maxItems": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("arezdev/us-healthcare-npi-medical-practice-lead-enricher").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 = {
    "taxonomyDescription": "Dentist",
    "state": "TX",
    "city": "AUSTIN",
    "maxItems": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("arezdev/us-healthcare-npi-medical-practice-lead-enricher").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 '{
  "taxonomyDescription": "Dentist",
  "state": "TX",
  "city": "AUSTIN",
  "maxItems": 3
}' |
apify call arezdev/us-healthcare-npi-medical-practice-lead-enricher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,arezdev/us-healthcare-npi-medical-practice-lead-enricher"
        }
    }
}
```

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/GoWiNf2yfdvcbvBEO/builds/pqyWrboDi9Xi7Y9Ej/openapi.json
