# Doctoralia Scraper | 2$ / 1k Cheap (`trev0n/doctoralia-scraper`) Actor

Scrape doctors from the whole Doctoralia network — doctoralia.es/.com.br/.com.mx and 9 more sites incl. ZnanyLekarz, MioDottore, Doktortakvimi and Jameda. Profiles, license numbers, services with prices, GPS locations and every patient review. Incremental monitoring for cheap recurring runs.

- **URL**: https://apify.com/trev0n/doctoralia-scraper.md
- **Developed by:** [Paweł](https://apify.com/trev0n) (community)
- **Categories:** Developer tools, Lead generation, Automation
- **Stats:** 6 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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 — Doctors, Reviews & Prices (11 Countries)

🎯 **Extract complete doctor profiles, patient reviews, consultation prices and clinic locations from the entire Doctoralia network — 11 countries, one scraper.**

This scraper collects rich, structured data about doctors and specialists from Doctoralia and its sister marketplaces: **doctoralia.es** (Spain), **doctoralia.com.br** (Brazil), **doctoralia.com.mx** (Mexico), **znanylekarz.pl** (Poland), **miodottore.it** (Italy), **doktortakvimi.com** (Turkey), **jameda.de** (Germany), **znamylekar.cz** (Czechia), plus Chile, Colombia and Peru. For every doctor you get their name, specializations, medical license number, star rating, patient reviews, services with prices, payment methods and every practice location with GPS coordinates.

### 🚀 What Does It Do?

This scraper automatically searches any Doctoralia-family site by specialization and city and collects **structured, ready-to-use data** about every doctor found. No manual browsing needed — just set your filters and hit Start.

💡 **Two modes of operation:**

1. **🔍 Discovery Mode** — pick a country, one or more specializations and cities; the scraper walks the search results and collects every doctor.
2. **📋 Direct URL Mode** — paste any search-results or doctor-profile URLs from any of the 11 supported sites; they are detected and handled automatically.

### 👥 Who Is This For?

| 🏢 Use Case                          | 💬 How It Helps                                                                                                    |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------ |
| 📊 **Healthcare market researchers** | Map the competitive landscape of any specialty in any city — who practices where, at what price, with what ratings |
| 🎯 **Medical sales & pharma teams**  | Build targeted lead lists of specialists with locations, clinics and service portfolios                            |
| 🏥 **Clinics & hospital groups**     | Benchmark consultation prices and patient satisfaction against local competitors                                   |
| 💬 **Reputation & review analysts**  | Collect thousands of dated, rated patient reviews for sentiment analysis                                           |
| 🗺️ **Health-tech startups**          | Bootstrap provider directories with names, specializations, license numbers and GPS-tagged locations               |
| 📈 **Investors & consultants**       | Track telemedicine adoption, pricing trends and provider density across 11 markets                                 |

### ✨ Features

- 🌍 **11 countries, one scraper** — the whole Doctoralia / ZnanyLekarz / MioDottore / Doktortakvimi / Jameda network
- 🩺 **Full doctor profiles** — name, title, specializations, license/registration number, biography and photo
- ⭐ **Patient reviews** — dated, star-rated, with author and reviewed service; collect 10, 50 or ALL reviews per doctor
- 💶 **Consultation prices** — every listed service with parsed price and currency, per clinic
- 📍 **GPS-tagged locations** — every practice address with latitude/longitude, postal code and clinic name
- 💳 **Payment methods** — cash, card, online payment availability per location
- 🖥️ **Telemedicine detection** — spot online-only doctors and online consultation offers
- 📡 **Incremental monitoring** — recurring runs emit only what changed (new doctors, new reviews, price changes) — typically 80–95% cheaper
- 🎛️ **Smart Filters** — country, any number of specializations × cities, review depth, result caps
- ⚡ **Fast & Scalable** — hundreds of doctor profiles per run, ~20 doctors per search page
- 🧹 **Deduplication** — every doctor appears exactly once, even across overlapping searches
- 📤 **Export Anywhere** — Download results as JSON, CSV, Excel, or push to Google Sheets, Zapier, Make, or your CRM

### 🎛️ Filters & Options

| Option                            | What It Does                                                                            |
| --------------------------------- | --------------------------------------------------------------------------------------- |
| 🌍 **Country**                    | Choose which of the 11 country sites to search                                          |
| 🩺 **Specializations**            | One or more medical specialties, exactly as they appear in the site's URLs              |
| 🏙️ **Cities**                     | One or more cities — or `online` for telemedicine-only doctors, or empty for nationwide |
| 📄 **Fetch full doctor profiles** | Full record per doctor (license, bio, prices, reviews) — or fast card-only mode         |
| ⭐ **Max reviews per doctor**     | How many patient reviews to collect — set 0 for ALL of them                             |
| 🔢 **Max doctors**                | Hard cap on the number of records per run                                               |
| 📑 **Max search pages**           | How deep to paginate each search                                                        |
| 📡 **Incremental monitoring**     | Only emit new/changed doctors on recurring runs                                         |
| 🔗 **Direct URLs**                | Optionally provide specific search or profile URLs to scrape                            |

### 📦 What You Get (Output Fields)

Every doctor record includes:

#### 👤 Doctor Identity

| Field           | Example                                                                                       |
| --------------- | --------------------------------------------------------------------------------------------- |
| doctorId        | `157981`                                                                                      |
| name            | `Magdalena Szymanska Bueno`                                                                   |
| namePrefix      | `Dra.`                                                                                        |
| url             | `https://www.doctoralia.es/magdalena-szymanska-bueno-4/dermatologo-medico-estetico/barcelona` |
| specialization  | `Dermatólogo`                                                                                 |
| specializations | `[{ "name": "Dermatólogo", "url": "/dermatologo/barcelona" }]`                                |
| licenseNumber   | `080861069`                                                                                   |
| licenseLabel    | `Núm. Colegiado`                                                                              |
| about           | `Consulta dermatológica particular con un trato personalizado…`                               |
| image           | `https://s3-eu-west-1.amazonaws.com/doctoralia.es/doctor/bd53…_square.jpg`                    |

#### ⭐ Ratings & Reviews

| Field        | Example                                                                                          |
| ------------ | ------------------------------------------------------------------------------------------------ |
| rating       | `5`                                                                                              |
| reviewCount  | `191`                                                                                            |
| totalReviews | `191`                                                                                            |
| reviews      | `[{ "author": "Míriam", "rating": 5, "body": "…", "publishedAt": "2026-06-30T22:23:32+02:00" }]` |

#### 📍 Locations & Prices

| Field                      | Example                                                                               |
| -------------------------- | ------------------------------------------------------------------------------------- |
| addresses                  | `[{ "clinicName": "Clínica GMA - Barcelona", "street": "Avinguda Diagonal 489", … }]` |
| addresses[].postalCode     | `08029`                                                                               |
| addresses[].latitude       | `41.3920326`                                                                          |
| addresses[].longitude      | `2.1434593`                                                                           |
| addresses[].services       | `[{ "name": "Visita Dermatología", "price": 100, "priceCurrency": "€" }]`             |
| addresses[].paymentMethods | `["Efectivo", "Tarjeta de crédito"]`                                                  |
| addressCities              | `Barcelona`                                                                           |
| isOnlineOnly               | `false`                                                                               |
| isPromoted                 | `true`                                                                                |

#### 🧾 Metadata

| Field       | Example                                                        |
| ----------- | -------------------------------------------------------------- |
| countryCode | `es`                                                           |
| searchUrl   | `https://www.doctoralia.es/dermatologo/barcelona`              |
| changeType  | `NEW` (incremental mode: NEW / UPDATED / REAPPEARED / EXPIRED) |
| scrapedAt   | `2026-07-06T14:48:31.466Z`                                     |

### 📊 Example Output

```json
{
    "doctorId": "157981",
    "name": "Magdalena Szymanska Bueno",
    "namePrefix": "Dra.",
    "url": "https://www.doctoralia.es/magdalena-szymanska-bueno-4/dermatologo-medico-estetico/barcelona",
    "specialization": "Dermatólogo",
    "specializations": [
        { "name": "Dermatólogo", "url": "/dermatologo/barcelona" },
        { "name": "Médico estético", "url": "/medico-estetico/barcelona" }
    ],
    "licenseNumber": "080861069",
    "licenseLabel": "Núm. Colegiado",
    "rating": 5,
    "reviewCount": 191,
    "totalReviews": 191,
    "about": "Consulta dermatológica particular con un trato personalizado…",
    "image": "https://s3-eu-west-1.amazonaws.com/doctoralia.es/doctor/bd5397/bd53971a40dda3c65e3f1c3cc9f51a84_medium_square.jpg",
    "isPromoted": true,
    "isOnlineOnly": false,
    "addressCities": "Barcelona",
    "addresses": [
        {
            "addressId": "221688",
            "clinicName": "Clínica GMA - Barcelona",
            "street": "Avinguda Diagonal 489",
            "city": "Barcelona",
            "province": "Barcelona",
            "postalCode": "08029",
            "country": "ES",
            "latitude": 41.3920326,
            "longitude": 2.1434593,
            "services": [
                { "name": "Visita Dermatología", "price": 100, "priceCurrency": "€", "priceText": "100 €" },
                { "name": "Primera visita Dermatología", "price": 100, "priceCurrency": "€", "priceText": "100 €" }
            ],
            "paymentMethods": ["Efectivo", "Tarjeta de crédito"]
        }
    ],
    "reviews": [
        {
            "reviewId": "2009029",
            "author": "A N",
            "rating": 5,
            "body": "Punctual, kind, spoke English, described details. Good experience.",
            "publishedAt": "2026-06-30T21:08:35+02:00",
            "reviewedItem": "Clínica GMA - Barcelona Electrocoagulación o crioterapia de verrugas"
        }
    ],
    "countryCode": "es",
    "searchUrl": "https://www.doctoralia.es/dermatologo/barcelona",
    "contentHash": "1311232577",
    "scrapedAt": "2026-07-06T14:48:31.466Z"
}
````

### 📋 Dataset Views

The Apify Console gives you **4 ready-made table views** to quickly browse your results:

| View                      | What It Shows                                                                  |
| ------------------------- | ------------------------------------------------------------------------------ |
| 📊 **Overview**           | Doctor, specialization, rating, review count, license, cities and profile link |
| 🎯 **Lead generation**    | Contact-oriented view: doctor, locations, rating and profile link              |
| 📡 **Monitoring changes** | What changed since the previous run (incremental mode)                         |
| 📋 **Full Details**       | Every single field — the complete dataset                                      |

### ❓ FAQ

**🤔 Which countries are supported?**
All 11 active markets of the Doctoralia network: Spain, Brazil, Mexico, Poland (ZnanyLekarz), Italy (MioDottore), Turkey (Doktortakvimi), Germany (Jameda), Czechia (ZnamyLekar), Chile, Colombia and Peru.

**🤔 How do I know which specialization name to use?**
Open the site for your country, search for the specialty, and copy the word from the URL — e.g. `doctoralia.es/dermatologo/barcelona` → `dermatologo`. Accents and capital letters are handled automatically.

**🤔 Can I get ALL reviews for each doctor?**
Yes — set "Max reviews per doctor" to 0 and every patient review is collected, complete with date, star rating, author and the reviewed service.

**🤔 Can I monitor a specialty for new doctors or price changes?**
Yes — enable Incremental monitoring and schedule the same search daily or weekly. After the first baseline run, you only receive doctors that are new or changed (new reviews, price updates), which typically cuts costs by 80–95%.

**🤔 A search stops around page 20–25 — why?**
That's the site's own pagination limit for a single search. To capture very large markets, split the job into more specific searches (by city district, or one specialization at a time).

**🤔 Can I export the data?**
Yes — JSON, CSV, Excel, XML, HTML, RSS. You can also push data directly to Google Sheets, Zapier, Make, or any webhook/API endpoint.

**🤔 How often should I run this?**
For fresh data, run daily or weekly. You can schedule automatic runs on Apify with just a few clicks — combined with incremental monitoring, recurring runs are extremely cheap.

### 🛠️ Need Custom Filters or Features?

**I'm happy to customize this scraper for your specific needs!** 🤝

Whether you need:

- 🎯 Additional filters (insurance accepted, minimum rating, telemedicine only, nearest appointment date)
- 📊 Extra data fields or custom output formats
- 🔄 Integration with your CRM, Google Sheets, or database
- ⏰ Scheduled scraping with automatic deduplication
- 🌐 Scraping from other healthcare platforms alongside Doctoralia

👉 **Don't hesitate to reach out via private message** — I respond quickly and I'm always open to building exactly what you need. No request is too small or too specific!

### ⚖️ Legal & Ethical Use

This scraper collects **only publicly available information** from the Doctoralia network's public search results and doctor profiles. It does not access private data, bypass authentication, or collect patient information. Please use the data responsibly and in compliance with applicable laws (including GDPR where relevant) and platform terms of service.

# Actor input Schema

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

Which Doctoralia-family site to search. All 11 active countries of the network are supported.

## `specializations` (type: `array`):

One or more medical specializations, written the way they appear in the site's URLs for your chosen country — e.g. Spain: <code>dermatologo</code>, <code>psicologo</code>; Brazil: <code>dermatologista</code>; Poland: <code>dermatolog</code>; Germany: <code>hautarzt-dermatologe</code>. Free text is normalised (accents stripped, spaces → hyphens).

## `cities` (type: `array`):

Cities to search, e.g. <code>barcelona</code>, <code>madrid</code> — or <code>online</code> for telemedicine-only doctors. Leave empty to search the specialization nationwide. Free text is normalised to the site's slug (e.g. 'São Paulo' → 'sao-paulo').

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

Optional. Paste any URLs from the 11 supported sites — a search-results page (e.g. https://www.doctoralia.es/dermatologo/barcelona) or a doctor profile. Auto-classified. When provided, these REPLACE the country/specialization/city fields above.

## `fetchProfileDetails` (type: `boolean`):

When enabled (default), every doctor's profile page is opened for the full record: license/registration number, biography, services with prices, payment methods, postal codes and reviews. When disabled (cheapest), only the ~15 fields already on the search-result card are returned — one request per ~20 doctors.

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

How many patient reviews to collect per doctor (newest first). The first 10 come free with the profile page; anything above 10 is fetched in small batches of 10. Set 0 to collect ALL reviews. Requires 'Fetch full doctor profiles'.

## `maxDoctors` (type: `integer`):

Hard cap on the number of doctor records pushed to the dataset. Set 0 for unlimited.

## `maxPages` (type: `integer`):

Maximum number of search-result pages to crawl per search (~20 doctors per page). The site itself caps a single search at roughly 20–25 pages — split large jobs by city or specialization to get everything.

## `maxConcurrency` (type: `integer`):

Maximum number of parallel requests.

## `maxRequestRetries` (type: `integer`):

How many times a failed request is retried.

## `incremental` (type: `boolean`):

Track changes across runs. The first run records a baseline; later runs emit only NEW, UPDATED (e.g. new reviews, price changes) and REAPPEARED doctors — typically 80–95% cheaper for recurring monitoring of the same search.

## `stateKey` (type: `string`):

Optional. Identifier for this monitoring baseline. Leave empty to derive one automatically from the search filters. Use a fixed value to keep one baseline across config tweaks.

## `emitUnchanged` (type: `boolean`):

Incremental only. Also output doctors that did not change since the last run.

## `emitExpired` (type: `boolean`):

Incremental only. Also output doctors that disappeared from the search results since the last run, tagged EXPIRED.

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

The platform is scrape-friendly, so NO proxy is the default (cheapest). Configure a proxy only for very large runs or if your traffic gets rate-limited.

## Actor input object example

```json
{
  "country": "es",
  "specializations": [
    "dermatologo"
  ],
  "cities": [
    "barcelona"
  ],
  "fetchProfileDetails": true,
  "maxReviewsPerDoctor": 10,
  "maxDoctors": 100,
  "maxPages": 30,
  "maxConcurrency": 10,
  "maxRequestRetries": 5,
  "incremental": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `monitoring` (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 = {
    "specializations": [
        "dermatologo"
    ],
    "cities": [
        "barcelona"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("trev0n/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 = {
    "specializations": ["dermatologo"],
    "cities": ["barcelona"],
}

# Run the Actor and wait for it to finish
run = client.actor("trev0n/doctoralia-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "specializations": [
    "dermatologo"
  ],
  "cities": [
    "barcelona"
  ]
}' |
apify call trev0n/doctoralia-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=trev0n/doctoralia-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Doctoralia Scraper | 2$ / 1k Cheap",
        "description": "Scrape doctors from the whole Doctoralia network — doctoralia.es/.com.br/.com.mx and 9 more sites incl. ZnanyLekarz, MioDottore, Doktortakvimi and Jameda. Profiles, license numbers, services with prices, GPS locations and every patient review. Incremental monitoring for cheap recurring runs.",
        "version": "1.0",
        "x-build-id": "9WwcPybzKkPClWDop"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/trev0n~doctoralia-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-trev0n-doctoralia-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/trev0n~doctoralia-scraper/runs": {
            "post": {
                "operationId": "runs-sync-trev0n-doctoralia-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/trev0n~doctoralia-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-trev0n-doctoralia-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "country": {
                        "title": "Country",
                        "enum": [
                            "es",
                            "br",
                            "mx",
                            "pl",
                            "it",
                            "cl",
                            "co",
                            "pe",
                            "tr",
                            "cz",
                            "de"
                        ],
                        "type": "string",
                        "description": "Which Doctoralia-family site to search. All 11 active countries of the network are supported.",
                        "default": "es"
                    },
                    "specializations": {
                        "title": "Specializations",
                        "type": "array",
                        "description": "One or more medical specializations, written the way they appear in the site's URLs for your chosen country — e.g. Spain: <code>dermatologo</code>, <code>psicologo</code>; Brazil: <code>dermatologista</code>; Poland: <code>dermatolog</code>; Germany: <code>hautarzt-dermatologe</code>. Free text is normalised (accents stripped, spaces → hyphens).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "cities": {
                        "title": "Cities",
                        "type": "array",
                        "description": "Cities to search, e.g. <code>barcelona</code>, <code>madrid</code> — or <code>online</code> for telemedicine-only doctors. Leave empty to search the specialization nationwide. Free text is normalised to the site's slug (e.g. 'São Paulo' → 'sao-paulo').",
                        "items": {
                            "type": "string"
                        }
                    },
                    "startUrls": {
                        "title": "Start URLs (advanced — overrides filters)",
                        "type": "array",
                        "description": "Optional. Paste any URLs from the 11 supported sites — a search-results page (e.g. https://www.doctoralia.es/dermatologo/barcelona) or a doctor profile. Auto-classified. When provided, these REPLACE the country/specialization/city fields above.",
                        "items": {
                            "type": "object",
                            "required": [
                                "url"
                            ],
                            "properties": {
                                "url": {
                                    "type": "string",
                                    "title": "URL of a web page",
                                    "format": "uri"
                                }
                            }
                        }
                    },
                    "fetchProfileDetails": {
                        "title": "Fetch full doctor profiles",
                        "type": "boolean",
                        "description": "When enabled (default), every doctor's profile page is opened for the full record: license/registration number, biography, services with prices, payment methods, postal codes and reviews. When disabled (cheapest), only the ~15 fields already on the search-result card are returned — one request per ~20 doctors.",
                        "default": true
                    },
                    "maxReviewsPerDoctor": {
                        "title": "Max reviews per doctor",
                        "minimum": 0,
                        "type": "integer",
                        "description": "How many patient reviews to collect per doctor (newest first). The first 10 come free with the profile page; anything above 10 is fetched in small batches of 10. Set 0 to collect ALL reviews. Requires 'Fetch full doctor profiles'.",
                        "default": 10
                    },
                    "maxDoctors": {
                        "title": "Max doctors",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Hard cap on the number of doctor records pushed to the dataset. Set 0 for unlimited.",
                        "default": 100
                    },
                    "maxPages": {
                        "title": "Max search pages",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Maximum number of search-result pages to crawl per search (~20 doctors per page). The site itself caps a single search at roughly 20–25 pages — split large jobs by city or specialization to get everything.",
                        "default": 30
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Maximum number of parallel requests.",
                        "default": 10
                    },
                    "maxRequestRetries": {
                        "title": "Max request retries",
                        "minimum": 0,
                        "type": "integer",
                        "description": "How many times a failed request is retried.",
                        "default": 5
                    },
                    "incremental": {
                        "title": "Incremental monitoring",
                        "type": "boolean",
                        "description": "Track changes across runs. The first run records a baseline; later runs emit only NEW, UPDATED (e.g. new reviews, price changes) and REAPPEARED doctors — typically 80–95% cheaper for recurring monitoring of the same search.",
                        "default": false
                    },
                    "stateKey": {
                        "title": "Monitoring state key",
                        "type": "string",
                        "description": "Optional. Identifier for this monitoring baseline. Leave empty to derive one automatically from the search filters. Use a fixed value to keep one baseline across config tweaks."
                    },
                    "emitUnchanged": {
                        "title": "Emit unchanged doctors",
                        "type": "boolean",
                        "description": "Incremental only. Also output doctors that did not change since the last run.",
                        "default": false
                    },
                    "emitExpired": {
                        "title": "Emit removed doctors",
                        "type": "boolean",
                        "description": "Incremental only. Also output doctors that disappeared from the search results since the last run, tagged EXPIRED.",
                        "default": false
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "The platform is scrape-friendly, so NO proxy is the default (cheapest). Configure a proxy only for very large runs or if your traffic gets rate-limited.",
                        "default": {
                            "useApifyProxy": false
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
