# RateMDs Scraper — Doctor Leads, Phone + Rating & Reviews (`scrapersdelight/ratemds-scraper`) Actor

Scrape the RateMDs directory by city and specialty — doctor name, specialty, phone, full street address, postal code, star rating, review count and the latest patient reviews. US + Canada. Public data, no login. Export JSON/CSV/Excel.

- **URL**: https://apify.com/scrapersdelight/ratemds-scraper.md
- **Developed by:** [Scrapers Delight](https://apify.com/scrapersdelight) (community)
- **Categories:** Lead generation, Automation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.70 / 1,000 per doctor returneds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## RateMDs Scraper — doctor leads with phone, rating & patient reviews

Turn the [RateMDs](https://www.ratemds.com) directory into a clean lead list. Pick a **specialty**
and a **city**, and get one row per doctor: name, specialty, **office phone**, full street address
and postal code, **star rating and review count**, and the latest **patient reviews** (author, star
rating, date, text) — plus GPS coordinates where RateMDs publishes them.

Covers the United States and Canada. Public data, no login, no API key.

### What you get (one row per doctor)

| Field | Example |
|---|---|
| `name` | `Dr. Gary Weinstein` |
| `specialty` | `family-gp` (the RateMDs specialty you searched) |
| `telephone` | `(416) 485-9044` |
| `streetAddress` / `city` / `region` / `postalCode` | `2401 Yonge Street, Suite 210` / `Toronto` / `ON` / `M4P 3H1` |
| `country` | `CA` |
| `latitude` / `longitude` | `43.70…` / `-79.39…` (present on some profiles) |
| `ratingValue` / `reviewCount` / `bestRating` | `4.75` / `282` / `5` |
| `reviews[]` | latest patient reviews: `author`, `rating`, `datePublished`, `body`, author city/region |
| `reviewsIncluded` | how many review objects are attached to this row |
| `imageUrl` | profile photo, if any |
| `doctorId` | the numeric RateMDs id, or the canonical profile URL for id-less profiles — the dedupe key |
| `profileUrl` | canonical RateMDs profile URL |
| `searchSpecialty`, `searchLocation`, `sourceListingUrl`, `scrapedAt` | provenance |

### Input

```json
{
  "specialties": ["family-gp", "dentist"],
  "locations": ["Toronto, ON", "Los Angeles, CA"],
  "maxItems": 200,
  "maxPagesPerSearch": 5,
  "includeReviews": true,
  "maxReviewsPerDoctor": 10,
  "minRating": "0",
  "minReviewCount": 0,
  "requirePhone": false,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

- **specialties** — everyday name (`Family Doctor`, `Dentist`, `Dermatologist`) or the exact URL
  slug. Common slugs: `family-gp`, `dentist`, `dermatologist`, `gynecologist-obgyn`, `pediatrician`,
  `cardiologist`, `psychiatrist`, `psychologist`, `optometrist`, `ophthalmologist`, `chiropractor`,
  `physical-therapist-physiotherapist`, `ear-nose-and-throat-ent`, `orthodontist`, `urologist`,
  `neurologist`. Each specialty is crossed with each location.
- **locations** — `City, ST` (e.g. `Toronto, ON`, `Los Angeles, CA`). A city is required; RateMDs
  organizes listings by city. US states and Canadian provinces are both supported.
- **startUrls** — optionally paste RateMDs URLs directly: `/best-doctors/…` listing pages (enumerated
  and paginated for you) or `/doctor-ratings/…` profile pages (scraped directly).
- **Filters** — `minRating`, `minReviewCount`, `requirePhone` drop rows that don't qualify (you're
  only billed for rows actually delivered).

### How it works

1. For each city × specialty it opens the RateMDs listing page
   `https://www.ratemds.com/best-doctors/{state}/{city}/{specialty}/` and follows `?page=N`
   pagination, collecting each doctor's profile URL. (Listings genuinely differ per city+specialty —
   `toronto/family-gp` and `toronto/dentist` return disjoint doctor sets.)
2. Each profile page carries a `schema.org` **Physician** JSON-LD block; the actor reads name, phone,
   address, aggregate rating and the review array from that structured object — never a regex over
   the page.
3. Rows are **deduplicated** on the doctor id, so a doctor reachable from two searches is billed once.

RateMDs sits behind Cloudflare, so the actor runs over Apify **RESIDENTIAL** proxy with automatic
retry (measured 20/20 profiles clean); datacenter / no-proxy runs hit intermittent 403s.

### Pricing

Pay-per-result: **$0.0027 per doctor row** delivered (deduplicated). No charge for pages that fail
or for duplicates.

### Legality & responsible use

This actor returns publicly published professional-directory data. Doctor names and office contact
details are business/professional records; patient reviews are user-generated content published on
RateMDs. **You are responsible for using the output lawfully** — B2B outreach, market research,
reputation monitoring — and in line with RateMDs' Terms of Use and any applicable privacy and
marketing laws (e.g. CAN-SPAM, CASL, GDPR) in your jurisdiction. Personal data handling is the
user's responsibility.

# Actor input Schema

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

One or more RateMDs specialties. Use the everyday name ("Family Doctor", "Dentist", "Dermatologist", "Psychiatrist") or the exact URL slug. Common slugs: family-gp, dentist, dermatologist, gynecologist-obgyn, pediatrician, cardiologist, psychiatrist, psychologist, optometrist, ophthalmologist, chiropractor, physical-therapist-physiotherapist, ear-nose-and-throat-ent, orthodontist, urologist, neurologist. Every specialty is crossed with every location below.

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

"City, ST" — e.g. "Toronto, ON", "Los Angeles, CA", "New York, NY". RateMDs organizes listings by city, so a city is required (a bare state won't build a listing URL). Both US states and Canadian provinces are supported.

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

Paste RateMDs URLs directly, in addition to the grid above. Either listing pages (https://www.ratemds.com/best-doctors/on/toronto/family-gp/) whose doctors will be enumerated + paginated, or individual doctor profile pages (https://www.ratemds.com/doctor-ratings/45045/Dr-Gary-Weinstein-Toronto-ON.html/) which are scraped directly.

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

Stop after this many doctor rows in total (across all searches). Set 0 for no limit.

## `maxPagesPerSearch` (type: `integer`):

RateMDs returns 10 doctors per listing page (a big city + specialty can run to hundreds of pages). This caps how deep each city × specialty goes.

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

ON (default): attach the latest patient reviews from each profile (author, star rating, date, review text). OFF: keep rating/review-count summary only, no review bodies.

## `maxReviewsPerDoctor` (type: `integer`):

Cap how many patient reviews to keep per doctor (the profile page exposes about 10). 0 = keep none. Ignored when "Include patient reviews" is off.

## `minRating` (type: `string`):

Drop doctors rated below this. Unrated doctors are dropped when a floor is set. "Any rating" keeps everyone.

## `minReviewCount` (type: `integer`):

Drop doctors with fewer patient ratings than this. 0 = keep everyone.

## `requirePhone` (type: `boolean`):

Drops rows with no listed office phone number.

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

RateMDs sits behind Cloudflare — Apify RESIDENTIAL proxy is required and is the default (measured 20/20 profiles vs intermittent 403s on datacenter/no-proxy). Leave as-is unless you know what you're doing.

## Actor input object example

```json
{
  "specialties": [
    "family-gp"
  ],
  "locations": [
    "Toronto, ON"
  ],
  "startUrls": [],
  "maxItems": 100,
  "maxPagesPerSearch": 5,
  "includeReviews": true,
  "maxReviewsPerDoctor": 10,
  "minRating": "0",
  "minReviewCount": 0,
  "requirePhone": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `records` (type: `string`):

The dataset of scraped RateMDs doctors, one item per doctor.

# 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": [
        "family-gp"
    ],
    "locations": [
        "Toronto, ON"
    ],
    "maxItems": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapersdelight/ratemds-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": ["family-gp"],
    "locations": ["Toronto, ON"],
    "maxItems": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("scrapersdelight/ratemds-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": [
    "family-gp"
  ],
  "locations": [
    "Toronto, ON"
  ],
  "maxItems": 100
}' |
apify call scrapersdelight/ratemds-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapersdelight/ratemds-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/0pGXMWOGdLu3qMSRL/builds/8whklaIhf4bt2usuM/openapi.json
