# WebMD Doctor Scraper - NPI, Ratings, Phones & Reviews (`bovi/webmd-scraper`) Actor

Scrape WebMD doctors by specialty and location: NPI, specialties, star rating, review counts, written reviews, biography, licenses, education, conditions and procedures, insurance plans, hospital affiliations, every practice location with phone, hours and geo. No login.

- **URL**: https://apify.com/bovi/webmd-scraper.md
- **Developed by:** [Vitalii Bondarev](https://apify.com/bovi) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.35 / 1,000 webmd doctor scraper - npi, ratings, phones & reviews

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

## WebMD Doctor Scraper - NPI, Ratings, Phones & Reviews

Scrape the **WebMD physician directory ([doctor.webmd.com](https://doctor.webmd.com))** by specialty and location and get a
rich, structured record for every healthcare provider: NPI, name and degrees, specialties, WebMD star rating and review
counts, written patient reviews, biography, education, state licenses, conditions treated and procedures performed (with
patient counts), accepted insurance plans, hospital affiliations, FAQs, and **every practice location with phone, opening
hours and geo-coordinates**.

No login, no API key, no browser - the actor reads the provider data WebMD embeds in its own pages.

> This actor is an independent tool and is not affiliated with or endorsed by WebMD LLC.

### What it collects

| Group | Fields |
|---|---|
| Identity | `providerId`, `npi`, `name`, `firstName`, `middleName`, `lastName`, `prefix`, `degrees`, `gender`, `photoUrl`, `url` |
| Specialty | `primarySpecialty`, `specialties` (name, practicing name, slug, primary flag) |
| Reputation | `rating`, `reviewCount`, `textReviewCount`, `reviewSnippet`, `patientPerspective`, `keyInsights`, `reviews` |
| Background | `biography`, `experienceSummary`, `medicalSchool`, `education`, `graduationYear`, `yearsOfExperience`, `licenses`, `languages` |
| Clinical focus | `conditionsTreated`, `proceduresPerformed` (with patient counts), `faqs`, `waitTimeMinutes` |
| Coverage | `insurancePlans`, `hospitalAffiliations`, `acceptingNewPatients` |
| Contact | `practiceName`, `address`, `city`, `state`, `zipCode`, `phone`, `latitude`, `longitude`, `locationCount`, `locations` (address, phone, hours, geo, new-patient / Medicare / Medicaid flags) |

Fields WebMD leaves empty for a provider (for example insurance plans or written reviews) come back as empty lists or `null`.

### Input

| Field | Description |
|---|---|
| `specialties` | WebMD specialty slugs (`cardiology`, `family-medicine`, `dermatology`, `pediatrics`, `dentistry`...) or friendly names (`Cardiologist`, `Dentist`, `OB-GYN`). |
| `locations` | `state/city` (`texas/austin`), `City, ST` (`Austin, TX`) or a whole state (`texas`, `TX`). Every specialty is combined with every location. |
| `startUrls` | Optional profile URLs (`/doctor/...-overview`) or directory URLs (`/providers/specialty/...`). |
| `includeProviderDetails` | Open each profile for the full record (default `true`). Off = faster card-only data. |
| `includeReviews` | Attach the written reviews embedded in the profile (default `true`). |
| `acceptingNewPatientsOnly`, `minRating`, `gender` | Filters. |
| `maxResultsPerSearch` | Cap per specialty x location (default 100). |
| `maxResults` | Total cap on saved providers (default 50). |
| `proxyConfiguration` | Optional Apify proxy settings. |

Example input:

```json
{
  "specialties": ["cardiology"],
  "locations": ["texas/austin"],
  "maxResults": 50
}
```

### Example output (one provider, lists shortened)

```json
{
  "providerId": "e42b86d5-64d8-4a1b-80ad-e9970ad68a68",
  "npi": "1417932120",
  "name": "Dr. David Whitten Terreson, MD",
  "firstName": "David",
  "middleName": "Whitten",
  "lastName": "Terreson",
  "prefix": "Dr.",
  "degrees": [
    "MD"
  ],
  "gender": "male",
  "primarySpecialty": "Cardiology",
  "rating": 5.0,
  "reviewCount": 71,
  "reviewSnippet": "With 40 years focused on interventional cardiology, Dr. David Terreson brings deep expertise in diagnosing and treating heart and vascular conditions.",
  "graduationYear": 1986,
  "yearsOfExperience": 40,
  "profileType": "Basic",
  "photoUrl": "https://mdxvitals-res.cloudinary.com/private_images/h_150,w_150,c_fill,g_face,f_auto,dpr_auto/professionals/1520827/photo.jpg",
  "practiceName": "Cardio Texas",
  "address": "1015 E 32nd St Ste 508",
  "city": "Austin",
  "state": "TX",
  "zipCode": "78705",
  "phone": "(512) 807-3140",
  "latitude": 30.289476,
  "longitude": -97.724156,
  "acceptingNewPatients": true,
  "url": "https://doctor.webmd.com/doctor/david-terreson-e42b86d5-64d8-4a1b-80ad-e9970ad68a68-overview",
  "specialties": [
    {
      "name": "Cardiology",
      "practicingName": "Cardiologist",
      "slug": "cardiology",
      "isPrimary": true
    }
  ],
  "textReviewCount": 0,
  "biography": "With 40 years focused on interventional cardiology, Dr. David Terreson brings deep expertise in diagnosing and treating heart and vascular conditions. He sees p...",
  "experienceSummary": null,
  "medicalSchool": "University Of Mississippi School Of Medicine",
  "education": [
    {
      "type": "Residency",
      "institution": "Baylor College Of Medicine",
      "graduationYear": null
    }
  ],
  "languages": [
    "English"
  ],
  "licenses": [],
  "conditionsTreated": [
    {
      "name": "Kidney Transplant Rejection",
      "patientCount": 2
    }
  ],
  "proceduresPerformed": [
    {
      "name": "Protein Urine Test",
      "patientCount": 4
    }
  ],
  "insurancePlans": [
    "AARP"
  ],
  "hospitalAffiliations": [
    {
      "name": "Saint Davids Medical Center",
      "url": "https://doctor.webmd.com/hospital/saint-davids-medical-center-bacdba5e-586b-406e-8596-f951fc3ee6ed"
    }
  ],
  "patientPerspective": [
    "Explained conditions and treatments"
  ],
  "keyInsights": [
    "5.0 rating"
  ],
  "faqs": [
    {
      "question": "What conditions does Dr. David Terreson treat?",
      "answer": "Dr. David Terreson most often treats Kidney Transplant Rejection."
    }
  ],
  "waitTimeMinutes": 30.0,
  "locationCount": 8,
  "locations": [
    {
      "practiceName": "Cardio Texas",
      "medicalGroup": null,
      "address": "1015 E 32nd St Ste 508",
      "city": "Austin",
      "state": "TX",
      "zipCode": "78705",
      "phone": "(512) 807-3140",
      "latitude": 30.289476,
      "longitude": -97.724156,
      "hours": {
        "Mon": "8:30 am - 5:00 pm",
        "Tue": "8:30 am - 5:00 pm",
        "Wed": "8:30 am - 5:00 pm",
        "Thu": "8:30 am - 5:00 pm",
        "Fri": "8:30 am - 3:00 pm"
      },
      "acceptingNewPatients": true,
      "acceptsMedicare": true,
      "acceptsMedicaid": true,
      "practiceUrl": "https://doctor.webmd.com/practice/cardio-texas-1ca5e6c7-4703-e211-a42b-001f29e3eb44"
    }
  ],
  "reviews": [],
  "searchSpecialty": "cardiology",
  "searchLocation": "texas/austin",
  "scrapedAt": "2026-10-17T05:51:51.086295+00:00"
}
```

### Pricing

Pay per result: every provider record saved to the dataset is one billable result, and you are never charged for
providers removed by your filters. The current price per result is shown on the actor's Pricing tab. A typical
city + specialty search (for example cardiologists in Austin, TX - about 285 providers) costs only a few cents to a
couple of dollars depending on how many providers you keep.

### Tips

- City-level searches return the most precise lists; a whole state returns the state directory pages.
- Use `maxResultsPerSearch` to spread a budget evenly across many cities.
- Turn off `includeProviderDetails` when you only need names, NPIs, ratings and the nearest address.

# Actor input Schema

## `specialties` (type: `array`):

Medical specialties to browse on doctor.webmd.com, combined with every location. Use WebMD slugs (cardiology, family-medicine, dermatology, pediatrics, psychiatry, dentistry, obstetrics-gynecology...) or friendly names (Cardiologist, Dentist, OB-GYN).

## `locations` (type: `array`):

Where to search: <code>state/city</code> (<code>texas/austin</code>), <code>City, ST</code> (<code>Austin, TX</code>) or a whole state (<code>texas</code>, <code>TX</code>). Leave empty to browse the nationwide specialty page.

## `startUrls` (type: `array`):

Optional direct doctor.webmd.com URLs: provider profiles (<code>/doctor/...-overview</code>) or directory pages (<code>/providers/specialty/...</code>). Used in addition to specialties + locations.

## `includeProviderDetails` (type: `boolean`):

Open every provider profile for the full record: biography, all practice locations with phones and hours, licenses, education, conditions and procedures with patient counts, insurance plans, hospital affiliations, FAQs. Turn off for a faster card-only run.

## `includeReviews` (type: `boolean`):

Attach the written patient reviews WebMD embeds in each profile (rating, text, date, reply, helpful count). Requires full provider profiles.

## `acceptingNewPatientsOnly` (type: `boolean`):

Only keep providers that WebMD marks as accepting new patients at one of their locations.

## `minRating` (type: `integer`):

Only keep providers with at least this WebMD star rating (1-5). 0 = no minimum.

## `gender` (type: `string`):

Filter providers by gender.

## `maxResultsPerSearch` (type: `integer`):

Maximum providers to collect per specialty x location combination (or per directory start URL).

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

Maximum number of providers to save across all searches.

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

Optional proxy. The default Apify datacenter proxy is usually enough; switch to residential if WebMD starts blocking.

## Actor input object example

```json
{
  "specialties": [
    "cardiology"
  ],
  "locations": [
    "texas/austin"
  ],
  "includeProviderDetails": true,
  "includeReviews": true,
  "acceptingNewPatientsOnly": false,
  "minRating": 0,
  "gender": "any",
  "maxResultsPerSearch": 100,
  "maxResults": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Dataset with one record per WebMD provider.

# 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 = {
    "specialties": [
        "cardiology"
    ],
    "locations": [
        "texas/austin"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("bovi/webmd-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 = {
    "specialties": ["cardiology"],
    "locations": ["texas/austin"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("bovi/webmd-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 '{
  "specialties": [
    "cardiology"
  ],
  "locations": [
    "texas/austin"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call bovi/webmd-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bovi/webmd-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/w9HKh8JqHwnZH3tGL/builds/Jp5i4LRutEGEUSmA7/openapi.json
