# Doctoralia Scraper (`tortuga/doctoralia-scraper`) Actor

Scrape doctors and clinics from Doctoralia, MioDottore, ZnanyLekarz and DoktorTakvimi: specialties, addresses with GPS, ratings, reviews, prices and insurances.

- **URL**: https://apify.com/tortuga/doctoralia-scraper.md
- **Developed by:** [Trevor Ortega](https://apify.com/tortuga) (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 provider (listing data)s

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## Doctoralia Scraper

Scrape doctors and clinics from Doctoralia and the other Docplanner sites (Spain, Mexico, Brazil, Colombia, Chile, Peru, Argentina, Italy's MioDottore, Poland's ZnanyLekarz, Turkey's DoktorTakvimi): specialties, addresses with GPS coordinates, ratings, review counts, listed prices, insurances and profile URLs.

Doctoralia Scraper reads the public search pages of any Docplanner directory and turns them into a clean dataset of healthcare providers. Optionally it opens each profile for the full description, languages, license number, accepted insurances, payment methods, complete price list and patient reviews (rating, date and text only). No login, no API key. Download the results as JSON, CSV or Excel, or pull them through the API into Google Sheets, a CRM or an LLM pipeline. You pay only for the providers you get.

### What data does Doctoralia Scraper extract?

#### Listing fields (every run)

| Field | Description |
|---|---|
| `id` | Docplanner numeric id of the doctor or clinic |
| `entityType` | `doctor` or `facility` (clinic, hospital, medical centre) |
| `name` | Display name as shown, e.g. `Dra. Alicia Medina Martinez` |
| `title` | Professional title prefix when shown (`Dr.`, `Dra.`, `Dott.ssa`, `lek. dent.`, `Uzm. Dt.`) |
| `nameWithoutTitle` | Name with the title stripped |
| `profileUrl` | Public profile page |
| `specialties` | List of specialties, e.g. `["Dentista"]` or `["Stomatolog", "Protetyk stomatologiczny"]` |
| `expertise` | Areas of expertise the provider lists, e.g. `["Implantología", "Periodoncia"]` |
| `rating` | Average rating 0-5 (number) |
| `reviewCount` | Number of patient reviews (integer) |
| `isVerified` | Profile confirmed by the provider |
| `isSponsored` | Listed as a paid / featured result |
| `onlineConsultation` | `true` when video consultations are offered |
| `photoUrl` | Profile photo |
| `addresses` | List of `{id, name, street, district, city, postalCode, region, fullAddress, latitude, longitude, isOnline}`; `name` is the clinic the provider works at |
| `services` | Listed services with `{name, price, priceValue}` (the listing shows the headline service and its price, e.g. `35 €`, `a partir de R$ 480`) |
| `domain`, `country` | Source site and ISO country code (`ES`, `MX`, `BR`, `CO`, `CL`, `PE`, `AR`, `IT`, `PL`, `TR`) |
| `scrapedAt` | UTC timestamp |

#### Profile fields (`includeDetails` or `includeReviews`)

| Field | Description |
|---|---|
| `about` | Provider's own description |
| `languages` | Languages spoken |
| `education` | Degrees and training entries |
| `diseases` | Conditions treated |
| `licenseNumber` | Professional registration number when displayed (e.g. Spanish "Núm. Colegiado", Brazilian CRO/CRM, clinic health-centre code) |
| `insurances` | Accepted insurance companies (empty list when the provider takes private patients only) |
| `paymentMethods` | Cash, card, transfer, financing, online payment, as listed per address |
| `addresses[]` | Enriched with `postalCode`, `district`, `countryCode` and per-address `paymentMethods` |
| `services` | Full price list from the profile, `price` is `null` when only "details" is shown |
| `reviews` | With `includeReviews`: list of `{id, rating, date, dateText, text, doctorReply}`. Reviewer names are never collected. |

### How to use Doctoralia Scraper

1. Open a Docplanner site, search for a specialty in a city and copy the URL, e.g. `https://www.doctoralia.es/dentista/madrid`, `https://www.doctoralia.com.br/dermatologista/rio-de-janeiro`, `https://www.znanylekarz.pl/ortopeda/krakow`. Paste one or more into **Start URLs**. Or fill in **Country**, **Specialty** and **City** and the Actor builds the URL for you.
2. Set **Max items** to cap the run and its cost.
3. Turn on **Include profile details** for insurances, languages, license numbers and full price lists, and **Include reviews** for patient reviews.
4. Click **Start**. Results appear in the **Dataset** tab; export from there or use the API.

### Input example

```json
{
  "startUrls": [{ "url": "https://www.doctoralia.es/dentista/madrid" }],
  "maxItems": 200,
  "includeDetails": true,
  "includeReviews": true,
  "maxReviewsPerDoctor": 20
}
```

### Output example

```json
{
  "id": 20539,
  "entityType": "doctor",
  "name": "Dra. Alicia Medina Martinez",
  "title": "Dra.",
  "nameWithoutTitle": "Alicia Medina Martinez",
  "profileUrl": "https://www.doctoralia.es/alicia-medina-martinez/dentista/madrid",
  "specialties": ["Dentista"],
  "expertise": ["Implantología", "Cirugía oral", "Periodoncia", "Diseño de sonrisa"],
  "rating": 5,
  "reviewCount": 34,
  "isVerified": true,
  "isSponsored": true,
  "onlineConsultation": false,
  "photoUrl": "https://s3-eu-west-1.amazonaws.com/doctoralia.es/doctor/186e59/186e593b2e4d99feebb281c4924db15d_large.jpg",
  "addresses": [
    {
      "id": 52575,
      "name": "Clínica Dental Dentosalud",
      "street": "Calle José María Fernández Lanseros 4",
      "district": "Ciudad Lineal",
      "city": "Madrid",
      "postalCode": "28017",
      "region": "Madrid",
      "countryCode": "ES",
      "fullAddress": "Calle José María Fernández Lanseros 4, Ciudad Lineal, 28017 Madrid",
      "latitude": 40.4314384,
      "longitude": -3.657639,
      "isOnline": false,
      "paymentMethods": ["Efectivo", "Tarjeta de crédito", "Transferencia bancaria", "Financiación"]
    }
  ],
  "services": [{ "name": "Primera visita Odontología", "price": "35 €", "priceValue": 35 }],
  "languages": ["Español", "Inglés"],
  "licenseNumber": "28009930",
  "insurances": [],
  "paymentMethods": ["Efectivo", "Tarjeta de crédito", "Transferencia bancaria", "Financiación"],
  "reviews": [
    { "id": 2014092, "rating": 5, "date": "2026-07-03", "dateText": "3 de julio de 2026", "text": "Creo que nunca he visto algo tan organizado…", "doctorReply": null }
  ],
  "domain": "doctoralia.es",
  "country": "ES",
  "scrapedAt": "2026-09-07T15:02:11Z"
}
```

### Which Doctoralia sites are supported?

All Docplanner-group directories that share the same platform: `doctoralia.es` (Spain), `doctoralia.com.mx` (Mexico), `doctoralia.com.br` (Brazil), `doctoralia.co` (Colombia), `doctoralia.cl` (Chile), `doctoralia.pe` (Peru), `doctoralia.com.ar` (Argentina), `miodottore.it` (Italy), `znanylekarz.pl` (Poland) and `doktortakvimi.com` (Turkey). One parser handles all of them, so a listing from Warsaw and one from São Paulo come out with the same fields. Search-result URLs (`/buscar?q=…&loc=…`), specialty-only URLs (`/dentista`) and district URLs (`/dentista/madrid/chamartin`) work too.

### How to scrape all dentists in a city

Paste the city listing URL (for example `https://www.doctoralia.es/dentista/madrid`) and set **Max items** high enough; the Actor walks the pagination (about 30 providers per page) until the last page or your limit. Doctoralia caps a single listing at roughly 100 pages, so for very large cities split the run by district or by sub-specialty (`/dentista/madrid/salamanca`, `/ortodoncista/madrid`) to reach everyone. Sponsored profiles repeat across pages; they are deduplicated by profile URL so you are charged once per provider.

### How to get doctor reviews from Doctoralia

Enable **Include reviews** and set **Max reviews per provider**. The first 10 reviews come free with the profile page; each further batch of 10 costs one extra request. Each review has the star rating, an ISO date, the text and the doctor's public reply when there is one. The reviewer's name or initials are intentionally not collected.

### Does it work without login or an API key?

Yes. Everything comes from the public pages any visitor can open in a browser without an account. The Actor never logs in, never books an appointment and never touches patient areas.

### Can I get phone numbers?

No. Doctoralia hides phone numbers behind a "show number" click and the Actor does not press it, so `phone` is not part of the output. You get the clinic name, full address, GPS coordinates and the profile URL, which is enough to enrich the record elsewhere.

### Pricing

Pay per provider: a listing record costs a fraction of a cent, a profile-enriched record (with or without reviews) about twice that. No subscription, no minimum; Apify's free plan is enough to try it on a few thousand providers. Reviews are nested inside the provider record, so a provider with 20 reviews is still one charged result.

### Integrations and API

Run it on a schedule to keep a directory fresh, connect it to Zapier, Make or n8n, or call it from Python or Node with the Apify client. See the **API** tab for ready-made snippets.

### Is it legal to scrape Doctoralia?

This Actor collects only publicly available business information about healthcare providers and clinics: the same data Docplanner publishes for search engines. It does not collect patient names, reviewer identities, phone numbers or anything behind a login. You are responsible for how you use the data and for complying with Docplanner's terms of use and the data-protection law that applies to you (GDPR in the EU, LGPD in Brazil, KVKK in Turkey), in particular when the data relates to individual professionals.

### Support

Found a bug or need a field added? Open an issue in the **Issues** tab; it is usually answered within a day.

# Actor input Schema

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

Doctoralia / Docplanner listing or search pages, e.g. `https://www.doctoralia.es/dentista/madrid`, `https://www.doctoralia.com.br/dermatologista/sao-paulo`, `https://www.znanylekarz.pl/stomatolog/warszawa`, `https://www.doctoralia.es/buscar?q=dentista&loc=madrid`. Supported domains: doctoralia.es, .com.mx, .com.br, .co, .cl, .pe, .com.ar, miodottore.it, znanylekarz.pl, doktortakvimi.com. Optional when Country + Specialty are filled in.

## `country` (type: `string`):

Which Docplanner site to search when building a listing URL from Specialty + City. Ignored when only Start URLs are given.

## `specialty` (type: `string`):

Specialty in the site's own language, as it appears in the site URL: `dentista`, `ginecologo`, `psicologo` (ES/MX/CL/PE), `dermatologista` (BR), `stomatolog` (PL), `dis-hekimi` (TR). Combined with Country (+ City) into a listing URL such as `https://www.doctoralia.es/dentista/madrid`.

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

City slug or name, e.g. `madrid`, `ciudad-de-mexico`, `sao-paulo`, `warszawa`. Leave empty for a country-wide specialty listing.

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

Stop after this many providers (doctors + clinics) across all start URLs. Keeps cost predictable.

## `includeDetails` (type: `boolean`):

Also open each provider's profile page to add description, languages, education, license number, accepted insurances, payment methods, full price list and postal codes. One extra request per provider; charged as a detailed result.

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

Nest patient reviews (rating, date, text, doctor's reply; never the reviewer's name) in each provider item. Implies profile details. Up to `maxReviewsPerDoctor` reviews, 10 per extra request.

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

Cap on nested reviews per provider when Include reviews is on. The first 10 come with the profile page; every further 10 cost one more request.

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

Apify Proxy is recommended for anything beyond a few hundred providers. Doctoralia currently serves plain HTTP clients without a challenge, but rotating IPs keeps large runs stable.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.doctoralia.es/dentista/madrid"
    }
  ],
  "maxItems": 100,
  "includeDetails": false,
  "includeReviews": false,
  "maxReviewsPerDoctor": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "startUrls": [
        {
            "url": "https://www.doctoralia.es/dentista/madrid"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tortuga/doctoralia-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 = {
    "startUrls": [{ "url": "https://www.doctoralia.es/dentista/madrid" }],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tortuga/doctoralia-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 '{
  "startUrls": [
    {
      "url": "https://www.doctoralia.es/dentista/madrid"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tortuga/doctoralia-scraper --silent --output-dataset

```

## MCP server setup

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