# DentalPlans.com Dentist Scraper — US Dental Provider Directory (`memo23/dentalplans-scraper`) Actor

Scrape DentalPlans.com to extract US dentist listings by ZIP code — practice name, provider name, specialties, phone, address, coordinates, plans accepted, smile points, and online booking availability. Filter by radius, gender, language, specialty, and booking. JSON or CSV out.

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

## Pricing

from $3.00 / 1,000 results

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

## DentalPlans.com Dentist Scraper

![How it works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-dentalplans.png)

Scrape US dentist directory listings from **DentalPlans.com** by ZIP code. Get provider names, practice names, specialties, phone numbers, addresses, GPS coordinates, plans accepted, smile points, and online booking availability — all from DentalPlans' structured API behind Cloudflare.

### Why Use This Actor

- **Lead generation teams**: Build dentist contact lists by ZIP code with phone numbers, addresses, and specialties for cold outreach and CRM enrichment.
- **Market researchers**: Map dental provider density across US regions, analyze specialty distribution, and track which practices accept discount plans.
- **Healthcare analysts**: Monitor online booking availability and plan acceptance patterns across geographic areas.
- **Data engineers**: Feed analytics pipelines with clean, structured JSON records ready for ETL, dashboards, and reporting.

### Overview

DentalPlans.com is a US dental discount plan directory where patients search for in-network dentists by ZIP code. This actor queries the site's WordPress REST API directly, returning structured dentist records with 20+ fields per result. It handles Cloudflare's managed challenge automatically via Apify Unblocker.

### Supported Inputs

- **ZIP codes** — one or more 5-digit US ZIP codes to search (primary mode)
- **Search radius** — 5, 10, 20, or 50 miles from each ZIP
- **Dentist/practice name** — filter results by name
- **Gender** — male or female
- **Language** — English or Spanish
- **Specialty** — General Dentistry, Endodontics, Oral Surgery, Orthodontics, Pedodontics, Periodontics, Prosthodontics
- **Online booking only** — filter to dentists with appointment booking
- **Direct URLs** — dentist profile URLs or search URLs with `?zip=XXXXX`
- **Full details** — enrich each record with office hours, bio, and languages from the profile page

### Use Cases

- Build a nationwide dentist contact database by running batches of ZIP codes
- Find dental practices with online booking in a specific metro area
- Filter by specialty to build targeted lists (e.g. all orthodontists in California)
- Enrich existing lead lists with phone numbers and addresses
- Monitor changes in plan acceptance or booking availability over time

### How It Works

1. You provide one or more ZIP codes (or direct URLs).
2. The actor solves Cloudflare's challenge via Apify Unblocker.
3. It queries DentalPlans' REST API for each ZIP, returning all dentists within the radius in a single call.
4. Results are deduplicated by dentist ID across ZIP codes.
5. If full details are enabled, each dentist's profile page is fetched for office hours, bio, and languages.
6. Clean JSON records are pushed to the dataset, ready for download as JSON or CSV.

### Input Configuration

| Parameter | Type | Default | Description |
|---|---|---|---|
| `zipCodes` | array | `["90210"]` | One or more 5-digit US ZIP codes to search |
| `radius` | string | `"10"` | Search radius: 5, 10, 20, or 50 miles |
| `searchTerm` | string | `""` | Filter by dentist or practice name |
| `dentistGender` | string | `""` | Filter by gender: male or female |
| `dentistLanguage` | string | `""` | Filter by language: english or spanish |
| `dentistSpeciality` | array | `[]` | Filter by specialty IDs 1-7 |
| `acceptsBooking` | boolean | `false` | Only dentists with online booking |
| `startUrls` | array | `[]` | Direct profile or search URLs |
| `maxItems` | integer | `100` | Maximum records to return (0 = unlimited, free plan: 5) |
| `fetchDetails` | boolean | `false` | Enrich with office hours, bio, languages |
| `proxy` | object | UNBLOCKER | Proxy configuration (UNBLOCKER recommended) |

### Output Overview

Each record is a dentist listing with provider identity, practice details, location, contact info, and booking metadata.

#### Output Samples

```json
{
  "dentist_id": 205615,
  "grouping_id": 42577,
  "full_name": "Dr. Brett Brayley",
  "first_name": "Brett",
  "last_name": "Brayley",
  "name_prefix": "Dr.",
  "practice_name": "Windham Dental Associates",
  "specialties": ["General Dentistry"],
  "phone": "2078932001",
  "detail_url": "https://www.dentalplans.com/dentists/maine/windham/04062/dr-brett-brayley-42577/",
  "street_address": "4 Commons Ave Ste 2",
  "city": "Windham",
  "state": "ME",
  "postal_code": "04062",
  "latitude": "43.824",
  "longitude": "-70.4343",
  "plans_accepted": 1,
  "smile_points": 700,
  "online_booking_available": false,
  "search_zip": "04062",
  "total_records": 7,
  "scraped_at": "2026-10-23T06:41:31.822Z"
}
```

### Key Output Fields

| Field | Type | Description |
|---|---|---|
| `dentist_id` | number | Unique dentist identifier |
| `grouping_id` | number | Practice grouping identifier |
| `full_name` | string | Provider full name with prefix |
| `first_name` | string | Provider first name |
| `last_name` | string | Provider last name |
| `practice_name` | string | Practice or office name |
| `specialties` | array | Dental specialty labels |
| `phone` | string | Contact phone number |
| `detail_url` | string | DentalPlans profile URL |
| `street_address` | string | Practice street address |
| `city` | string | City |
| `state` | string | State code |
| `postal_code` | string | ZIP code |
| `latitude` | string | GPS latitude |
| `longitude` | string | GPS longitude |
| `plans_accepted` | number | Number of discount plans accepted |
| `smile_points` | number | DentalPlans smile points metric |
| `online_booking_available` | boolean | Online appointment booking |
| `booking_system` | string | Booking system identifier |
| `search_zip` | string | ZIP code used for the search |
| `total_records` | number | Total dentists matching the search |
| `scraped_at` | string | ISO timestamp |

With `fetchDetails: true`, records also include `about`, `office_hours`, `languages_spoken`, and `photo_url` from the profile page.

### FAQ

**How many dentists does a ZIP return?** It depends on the area. A dense ZIP like 90210 with a 10-mile radius returns ~1,800 dentists. Rural ZIPs may return fewer than 10.

**Can I scrape the entire US?** Yes. Provide a list of ZIP codes covering the areas you want. The actor processes them sequentially, deduplicating by dentist ID.

**Does it handle Cloudflare?** Yes. The actor uses Apify Unblocker which solves Cloudflare's managed challenge server-side. No browser or manual cookie management needed.

**What's the difference between the search result and full details?** The search API returns 20+ fields per dentist in a single call. Full details adds office hours, bio, and languages by fetching each dentist's profile page (one extra request per dentist).

**Is there a free tier limit?** Yes, free plan runs are capped at 5 records per run.

### Support

If you run into issues, use the **Issues** tab on the actor's Apify Console page. Include the input you used (with sensitive values redacted), the run ID, and a short description of what you expected versus what happened.

### Additional Services

Need custom filtering, a specific output format, or integration with your CRM? Reach out through the actor's Apify Console for custom work.

### Explore More Scrapers

Check out other actors in the portfolio for healthcare directories, lead generation, and business data scraping.

### For AI Agents & LLM Apps

This actor accepts a JSON input with `zipCodes` (array of 5-digit strings), `radius`, `maxItems`, and optional filters. Output is a flat JSON array of dentist records in the default dataset. Use the Apify API or MCP server to start runs and fetch results programmatically.

```json
{
  "zipCodes": ["90210", "10001"],
  "radius": "10",
  "maxItems": 50,
  "fetchDetails": false
}
```

### Disclaimer

This actor scrapes publicly available data from DentalPlans.com for legitimate business purposes including market research, lead generation, and data analysis. Users are responsible for ensuring their collection and downstream use complies with applicable laws, regulations, and the target site's terms of service. This actor is not affiliated with or endorsed by DentalPlans.com.

### SEO Keywords

dentalplans scraper, dentist scraper, dental provider directory, US dentist listings, dental lead generation, dentist phone numbers, dental practice data, ZIP code dentist search, dental discount plans, healthcare provider scraper, dentist contact data, dental office leads, provider directory scraper

# Actor input Schema

## `zipCodes` (type: `array`):

One or more 5-digit US ZIP codes to search. The actor queries the DentalPlans API for each ZIP and returns all dentists within the radius. Example: \["90210", "10001"].

## `radius` (type: `string`):

Distance from each ZIP code to search. Allowed values: 5, 10, 20, 50.

## `searchTerm` (type: `string`):

Filter results to dentists or practices matching this name. Leave blank for all providers in the area.

## `dentistGender` (type: `string`):

Filter by dentist gender. Leave blank for any.

## `dentistLanguage` (type: `string`):

Filter by language spoken. Leave blank for any.

## `dentistSpeciality` (type: `array`):

Filter by dental specialty. Enter one or more of: 1 (General Dentistry), 2 (Endodontics), 3 (Oral Surgery), 4 (Orthodontics), 5 (Pedodontics), 6 (Periodontics), 7 (Prosthodontics).

## `acceptsBooking` (type: `boolean`):

When true, return only dentists that offer online appointment booking.

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

Direct DentalPlans dentist profile URLs or search URLs with ?zip=XXXXX to scrape. Profile URLs fetch full details; search URLs extract the ZIP and run a standard search.

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

Maximum number of dentist records to return across all ZIP codes. Set to 0 for unlimited. Free plan: 5 per run.

## `fetchDetails` (type: `boolean`):

Visit each dentist's profile page to enrich the record with office hours, accepted plans list, bio, education, and languages. One extra request per dentist, so runs with many records are slower. Charged as an extra event per enriched record.

## `proxy` (type: `object`):

DentalPlans.com is protected by Cloudflare. The actor uses Apify Unblocker (default) which solves the challenge server-side. Switch to residential if you prefer, but Unblocker is the most reliable path.

## Actor input object example

```json
{
  "zipCodes": [
    "90210"
  ],
  "radius": "10",
  "searchTerm": "",
  "dentistGender": "",
  "dentistLanguage": "",
  "dentistSpeciality": [],
  "acceptsBooking": false,
  "startUrls": [],
  "maxItems": 100,
  "fetchDetails": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ]
  }
}
```

# Actor output Schema

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

The scraped dentist records in the default dataset.

# 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 = {
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "UNBLOCKER"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/dentalplans-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 = { "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["UNBLOCKER"],
    } }

# Run the Actor and wait for it to finish
run = client.actor("memo23/dentalplans-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 '{
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "UNBLOCKER"
    ]
  }
}' |
apify call memo23/dentalplans-scraper --silent --output-dataset

```

## MCP server setup

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