# Dental & Clinic Enricher: Insurance, New Patients (`emulative_capeskin/dental-practice-enricher`) Actor

accepting_new_patients, insurance_accepted, accepts_medicaid, online_booking_url, hours, services, languages, providers, with evidence quotes for the key facts. Dental, ortho, chiro, vet, med spa, PT, optometry, derm, mental health. $0.02 per practice; free plan: 3 per run without a key.

- **URL**: https://apify.com/emulative_capeskin/dental-practice-enricher.md
- **Developed by:** [Sniper Search](https://apify.com/emulative_capeskin) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$20.00 / 1,000 enriched practices

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

## Dental & Clinic Enricher

`accepting_new_patients`, `insurance_accepted`, `accepts_medicaid`, `online_booking_url`, `hours`, `services`, `languages`, `providers`: one JSON row per practice, with an evidence quote from the practice's own website behind each key fact, for dental, orthodontic, chiropractic, veterinary, med spa, physical therapy, optometry, dermatology and mental health practices. $0.02 per enriched practice; the free Apify plan enriches the first 3 practices of a run; add your own Anthropic key for the rest.

Registries like NPPES tell you a provider exists. Google Maps gives you a pin and a phone number. Neither tells you whether the practice is in-network with Delta Dental, takes Trupanion for pets, or has a new-patient form. This Actor reads the practice's own website (homepage plus the insurance, new-patient, appointment and contact pages) and extracts those facts with Claude into clean JSON.

Works as a tool for AI agents through Apify's MCP server, as an API, or as a batch enrichment step after any NPI or Google Maps scraper.

### Example output (one practice)

A dental practice; every practice type returns the same fields.

```json
{
  "status": "ok",
  "website": "https://brightsmilefamilydentistry.com/",
  "practice_name": "Bright Smile Family Dentistry",
  "is_practice_own_site": true,
  "accepting_new_patients": "yes",
  "insurance_accepted": ["Delta Dental PPO", "Cigna", "MetLife", "Most PPO plans"],
  "accepts_medicaid": "no",
  "in_house_membership_plan": "yes",
  "financing_options": ["CareCredit"],
  "online_booking": "yes",
  "online_booking_url": "https://www.zocdoc.com/practice/bright-smile-12345",
  "phone": "(512) 555-0100",
  "address": "123 Main St, Austin, TX 78701",
  "hours": [{ "day": "Monday", "hours": "8:00 AM - 5:00 PM" }, { "day": "Saturday", "hours": "Closed" }],
  "open_saturday": "no",
  "emergency_same_day": "yes",
  "languages": ["Spanish"],
  "services": ["Cleanings", "Fillings", "Crowns", "Invisalign", "Emergency care"],
  "providers": ["Dr. Jane Rivera"],
  "evidence": [
    { "field": "insurance_accepted", "quote": "We are in-network with Delta Dental, Cigna and MetLife.", "url": "https://brightsmilefamilydentistry.com/insurance" },
    { "field": "accepting_new_patients", "quote": "Now welcoming new patients of all ages.", "url": "https://brightsmilefamilydentistry.com/" }
  ],
  "confidence": "high",
  "pages_read": ["https://brightsmilefamilydentistry.com/", "https://brightsmilefamilydentistry.com/insurance", "https://brightsmilefamilydentistry.com/new-patients"],
  "charged": true
}
```

Every field is "unknown", null or empty when the site doesn't say. Nothing is guessed.

Practices whose website can't be found or loaded come back with `status: "website_not_found"` or `"fetch_failed"` and are **not charged**. Neither are pages that turn out to be a directory or a different business (`status: "not_practice_site"`), practices where the extraction itself failed (`status: "extraction_failed"`, or `"error"` for any other unexpected failure; the row's `error` says why), practices after the first 3 of a run on the free Apify plan without your own Anthropic key (`status: "skipped_free_plan"`, see Pricing), practices not started because the Actor's own Claude key ran out of budget or became invalid (`status: "extraction_unavailable"`; the run then ends as failed, so try again later, resurrect the run, or pass your own `anthropicApiKey`; a resurrected run retries these practices), or practices not started because most of the earlier ones, on the Actor's own key, turned out not to be the practices' own sites (`status: "skipped_unusable_websites"`; check the `website` values or pass your own `anthropicApiKey`).

Directory, listing and social network sites are never read as the practice: a `website` on one of them (Yelp, Facebook, Zocdoc, ...) is not read at all, and the practice comes back as `status: "not_practice_site"`, not charged. If booking happens in a widget embedded in the site, `online_booking` is `"yes"` and `online_booking_url` is the site page with the widget's `#anchor`.

In the Apify Console the dataset has two table views: Overview (status, insurance, Medicaid, new patients, booking, phone, address) and Details (hours, services, providers, languages, financing, evidence quotes, pages read).

### Practice types

Set `practiceType` once per run to say what kind of practices the list holds. It tunes what "insurance", "new patients" and "booking" mean; the output fields are the same for every type.

| `practiceType` | Type | What it looks for |
| --- | --- | --- |
| `dental` (default) | Dental | Dental plans (Delta Dental, Cigna Dental, ...) |
| `orthodontics` | Orthodontics | Dental plans with orthodontic benefits; in-house payment plans as financing; braces and aligners as services |
| `chiropractic` | Chiropractic | Health plans, plus Medicare, workers' comp and auto / personal-injury claims |
| `veterinary` | Veterinary | Pet insurers the clinic names or bills directly (Trupanion, Nationwide, Healthy Paws); "new clients" count as new patients; wellness plans as membership plans; `accepts_medicaid` is always `"unknown"` |
| `med_spa` | Med spa | Insurance only if the site names it; financing such as Cherry, CareCredit or PatientFi; membership programs; booking on Boulevard, Vagaro or Mindbody |
| `physical_therapy` | Physical therapy | Medicare, workers' comp, auto / personal injury; "no referral needed" or "direct access" as a service |
| `optometry` | Optometry | Vision plans (VSP, EyeMed, Davis Vision, Spectera) and medical plans |
| `dermatology` | Dermatology | Medical insurance, including Medicare; cosmetic services are often self-pay, so only what the site states |
| `mental_health` | Mental health / therapy | Insurance panels; out-of-network (superbill); "accepting new clients"; booking on SimplePractice, Headway or Alma; telehealth as a service |

### Three ways to give it practices

1. **Names and websites.** `{ "name": "Seattle Sound Dental", "website": "https://seattlesounddental.com/" }`. The cheapest and most reliable way: the Actor reads the site you give it. Add `city`/`state` to help confirm the site is the practice's own.
2. **Names and city/state.** `{ "name": "Seattle Sound Dental", "city": "Seattle", "state": "WA" }`. The Actor looks the practice up on Google Maps (Google Maps Scraper runs in your Apify account) and uses the website of the listing that matches the name and city, or the phone number (add `phone` for practices that changed their name). Closed places and directory sites such as Facebook, Yelp or Psychology Today are skipped. A practice needs a `city` or a 10-digit `phone` to be looked up, and a `state`, if you give one, has to be a US state or DC, written as `WA` or `Washington`: a practice that doesn't meet that is not looked up, costs nothing on Google Maps, and its `error` says what is missing. With no match the practice comes back as `website_not_found`, not charged, and `error` says why.
3. **Rows from Google Maps Scraper.** Pass the items of a [Google Maps Scraper](https://apify.com/compass/crawler-google-places) (`compass/crawler-google-places`) run as they are, `null` values included. `title`, `website`, `phone`, `address`, `city`, `state` and `placeId` are mapped, and the reviews and images are dropped. A listing with no website comes back as `website_not_found`, not charged, with the error "The Google Maps listing has no website."; it is not looked up again.

### Input

```json
{
  "practices": [
    { "name": "Seattle Sound Dental", "website": "https://seattlesounddental.com/", "city": "Seattle", "state": "WA" },
    { "name": "Revive Dental Group", "website": "https://www.revivedentalgroup.com/", "city": "Bellevue", "state": "WA" }
  ]
}
```

- `practices` (required): name plus either `website` or `city`/`state`, or rows from Google Maps Scraper (see above). Without a `website` the Actor looks the practice up on Google Maps by name and `city`/`state`; with one, `city`/`state` help confirm the site is the practice's own. Any extra fields (`npi`, `phone`, `address`) are passed through in `input`.
- `practiceType`: `dental` (default), `orthodontics`, `chiropractic`, `veterinary`, `med_spa`, `physical_therapy`, `optometry`, `dermatology` or `mental_health`. One type per run.
- `anthropicApiKey`: your own Anthropic API key, billed to you by Anthropic. Leave it empty on paid plans. On the free Apify plan the first 3 practices of a run are enriched on the Actor's key, reading at most 2 pages per site and 8,000 characters per page whatever the other settings say, and the rest come back as `skipped_free_plan`, so add your key to enrich all of them. It is also needed for Sonnet and Opus and for more than 5 pages per site, more than 15,000 characters per page or a higher reasoning effort. Without it the Actor runs Haiku on its own key, with `maxPagesPerSite` capped at 5, `maxCharsPerPage` at 15,000 and `effort` at `low`.
- `model`: `claude-haiku-5-5` (default), `claude-sonnet-5-5`, or `claude-opus-5-5` (most thorough). Sonnet and Opus run only with your own key in `anthropicApiKey`; without one the Actor uses Haiku.
- `effort`: `low` (default) / `medium` / `high`.
- `maxPagesPerSite` (default 4), `maxCharsPerPage` (default 12000), `searchForWebsite` (default true: look up missing websites on Google Maps; see Pricing), `concurrency` (default 3), `proxyConfiguration`.

### Use it from an AI agent

Published Actors are available as tools through [Apify's MCP server](https://mcp.apify.com). Ask your agent: *"Which of these three dentists in Austin take Cigna and accept new patients?"* and it can call this Actor with the practice list and read the answer.

### Pricing

$0.02 per enriched practice. Practices whose website couldn't be found or read, sites that turn out not to be the practice's own, and practices where the extraction fails are free. If Apify restarts a run (a server migration, or Resurrect), practices that already have a row are skipped and not charged again. On the free Apify plan, the first 3 practices of a run are enriched on the Actor's own key (Haiku, reading at most 2 pages per site and 8,000 characters per page) and billed like any other enriched practice; the rest come back as `status: "skipped_free_plan"` with an explanation; add your own Anthropic key (`anthropicApiKey`) to enrich all of them. Paid Apify plans don't need a key.

**Finding missing websites costs extra, and only for practices that need it.** When a practice has no website, the Actor looks it up on Google Maps by running Google Maps Scraper in your Apify account: up to 3 places at $0.004 each on the free plan (less on paid plans), so at most $0.012 per practice looked up, billed by that Actor on top of this Actor's price. Practices that come with a website, and rows from Google Maps Scraper (which are not searched again), cost nothing extra. Turn the lookup off with `searchForWebsite: false`.

### How accurate is it?

Tested on every dental practice with a findable website in King County, WA (about 600 practices), extracted once with Haiku and once with Opus from the same pages:

- The two models agreed on new-patient status for 93% of practices, on the insurance list for 88%, on phone for 99% and on the booking link for 91%.
- Checking 20 of the disagreements by hand against the pages, and counting answers where the two models agree as correct, Haiku's key facts were right about 86% of the time and Opus's about 89%, within the margin of a 20-row check.
- The key facts (insurance, new patients, booking, hours) come with a verbatim quote and the page it was taken from, so you can verify them.

These numbers were measured on dental practices only. The other practice types are not benchmarked yet.

### Typical uses

- Patient-facing agents and chatbots answering "find me a dentist (or a vet, chiropractor or therapist) that takes my insurance".
- Lead lists: filter NPI or Google Maps exports by insurance network, membership plans, or Saturday hours.
- Insurance networks and DSOs checking what practices publicly advertise.
- Directory sites keeping "accepting new patients" and booking links current.

### Notes

- Reads only public pages of the practice's own site and keeps to a handful of pages per site.
- The Google Maps lookup runs only on the Apify platform. Run elsewhere, practices without a website come back as `website_not_found`.
- Sites whose pages have no readable text (built entirely in JavaScript, or behind a bot check) come back as `fetch_failed` and are not charged.
- Extraction quality depends on what the site states. The `evidence` array tells you where the key facts came from so you can verify them.

# Actor input Schema

## `practices` (type: `array`):

Practices to enrich. Each item needs a name and either a website or a city/state so the website can be found. Extra fields (phone, npi, address) are passed through to the output. Rows from Google Maps Scraper (compass/crawler-google-places) work as they are; title, website, phone, address, city, state, placeId are mapped.

## `practiceType` (type: `string`):

What kind of practices the list holds. Tunes what insurance, new patients and booking mean (e.g. pet insurance for veterinary). Output fields are the same for every type.

## `anthropicApiKey` (type: `string`):

Leave empty on paid plans. On the free Apify plan the first 3 practices of a run are enriched on the Actor's key and the rest are skipped, so add your own key (billed to you by Anthropic) to enrich all of them. Sonnet, Opus, more than 5 pages per site, more than 15,000 characters per page or a higher reasoning effort also need your own key; without it the Actor runs Haiku within those limits.

## `model` (type: `string`):

Model used for extraction. Haiku is the default: on 600+ real practices it matched Opus on key facts within the margin of a hand check, at about 1/30 of the cost. Sonnet and Opus run only with your own key in anthropicApiKey; without one the Actor uses Haiku.

## `effort` (type: `string`):

How hard the model thinks per practice. Low is enough for extraction; raise it for messy sites.

## `maxPagesPerSite` (type: `integer`):

Pages read per site, homepage included: the homepage plus the most relevant subpages (insurance, new patients, appointments, contact, hours).

## `maxCharsPerPage` (type: `integer`):

Text from each page is cut at this length before extraction.

## `searchForWebsite` (type: `boolean`):

When a practice has no website, look it up on Google Maps by name, city and state, by running Google Maps Scraper in your Apify account: up to 3 places at $0.004 each on the free plan (less on paid plans), so at most $0.012 per practice looked up, billed by that Actor on top of this Actor's price. Maps rows are not searched again.

## `concurrency` (type: `integer`):

Practices processed in parallel.

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

Proxies used to fetch practice websites. Residential proxies are not available on the Actor plan: RESIDENTIAL is removed from the proxy groups and Apify Proxy uses its datacenter groups instead. Your own proxy URLs are used as given.

## Actor input object example

```json
{
  "practices": [
    {
      "name": "Seattle Sound Dental",
      "website": "https://seattlesounddental.com/",
      "city": "Seattle",
      "state": "WA"
    },
    {
      "name": "Revive Dental Group",
      "website": "https://www.revivedentalgroup.com/",
      "city": "Bellevue",
      "state": "WA"
    }
  ],
  "practiceType": "dental",
  "model": "claude-haiku-5-5",
  "effort": "low",
  "maxPagesPerSite": 4,
  "maxCharsPerPage": 12000,
  "searchForWebsite": true,
  "concurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All rows in the default dataset, one per processed practice.

# 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 = {
    "practices": [
        {
            "name": "Seattle Sound Dental",
            "website": "https://seattlesounddental.com/",
            "city": "Seattle",
            "state": "WA"
        },
        {
            "name": "Revive Dental Group",
            "website": "https://www.revivedentalgroup.com/",
            "city": "Bellevue",
            "state": "WA"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("emulative_capeskin/dental-practice-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 = {
    "practices": [
        {
            "name": "Seattle Sound Dental",
            "website": "https://seattlesounddental.com/",
            "city": "Seattle",
            "state": "WA",
        },
        {
            "name": "Revive Dental Group",
            "website": "https://www.revivedentalgroup.com/",
            "city": "Bellevue",
            "state": "WA",
        },
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("emulative_capeskin/dental-practice-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 '{
  "practices": [
    {
      "name": "Seattle Sound Dental",
      "website": "https://seattlesounddental.com/",
      "city": "Seattle",
      "state": "WA"
    },
    {
      "name": "Revive Dental Group",
      "website": "https://www.revivedentalgroup.com/",
      "city": "Bellevue",
      "state": "WA"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call emulative_capeskin/dental-practice-enricher --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,emulative_capeskin/dental-practice-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/3Md1AD4cT6cT7l9DK/builds/rCMfXwHqq9EJvCAJf/openapi.json
