# Indonesia Doctor Directory Scraper (Alodokter) (`fanndev/alodokter-doctor-directory-scraper`) Actor

Extract Indonesian doctor listings from Alodokter -- name, sub-specialty, hospital and address, consultation price in IDR, satisfaction rating, review count and next available schedule. Browse any specialty, optionally scoped to a city. No account or API key needed.

- **URL**: https://apify.com/fanndev/alodokter-doctor-directory-scraper.md
- **Developed by:** [Faisal Ahdan naufal](https://apify.com/fanndev) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 83.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

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

## Indonesia Doctor Directory Scraper (Alodokter)

Extract Indonesian doctor listings from **Alodokter** — specialty, hospital, consultation price, patient rating and next availability. No account, login, or API key needed.

### Why use this actor

- **Consultation prices in rupiah** on every listing row — the field most healthcare-market datasets are missing
- **Hospital and address per doctor**, including every clinic a doctor practises at (profiles routinely list two or more)
- **Patient satisfaction and review counts** as published, plus the next available appointment text ("Tersedia Hari Ini", "Jadwal Berikutnya : Besok, 16.00 Siang")
- **17 specialties** — paediatrics, obstetrics, general practice, dentistry, dermatology, cardiology, neurology, ENT, ophthalmology, internal medicine, surgery, pulmonology, nutrition, orthopaedics, urology, psychiatry
- **City targeting** — scope any specialty to Jakarta, Bali, Balikpapan and more
- **Verified inputs** — `reference` mode checks every specialty slug against the live site, so a typo returns a clear error instead of an empty run
- Stable JSON output for market research, pricing analysis or provider databases, with automatic retries

### How it works

Pick a `mode`:

1. **`specialty`** — list doctors in one or more specialties, optionally scoped to a `city`. Pages are followed automatically up to `maxItems`. Turn on `enrichProfiles` to also fetch each doctor's own page.
2. **`doctor`** — full detail for specific doctors, by address or bare slug.
3. **`reference`** — live specialty and city lists.

### Input

**Paediatricians in Jakarta:**

```json
{
  "mode": "specialty",
  "specialty": "dokter-anak",
  "city": "jakarta",
  "maxItems": 100,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
```

**Several specialties at once, with full profiles:**

```json
{
  "mode": "specialty",
  "specialties": ["dokter-jantung", "dokter-saraf", "dokter-penyakit-dalam"],
  "enrichProfiles": true,
  "maxItems": 50
}
```

**One doctor:**

```json
{
  "mode": "doctor",
  "doctorUrl": "https://www.alodokter.com/cari-dokter/dr-rifan-fauzie-spa-k"
}
```

| Field | Type | Description |
|---|---|---|
| `mode` | string | `specialty`, `doctor`, or `reference`. |
| `specialty` / `specialties` | string / array | Which specialty slug(s) to list. |
| `city` | string | Optional city slug, e.g. `jakarta`. |
| `enrichProfiles` | boolean | Also fetch each listed doctor's own page. |
| `doctorUrl` / `doctorUrls` | string / array | `doctor` mode: address or bare slug. |
| `maxItems` | integer | Max doctors per specialty (10 per page, followed automatically). |
| `maxConcurrency` | integer | Doctor pages fetched in parallel (default 4). |
| `proxyConfiguration` | object | Apify Proxy settings; Residential on by default. |

### Output

**`specialty` mode** — real output:

```json
{
  "_input": "specialty:dokter-anak/jakarta",
  "_source": "S1-jsonld",
  "_scrapedAt": "2026-09-08T06:54:15Z",
  "recordType": "DOCTOR_CARD",
  "name": "dr. Markus Mualim Danusantoso, Sp.A",
  "slug": "dr-markus-mualim-danusantoso-spa",
  "profileUrl": "https://www.alodokter.com/cari-dokter/dr-markus-mualim-danusantoso-spa?sku_id=630829fca6839d7867009974",
  "specialty": "Dokter Anak - Ahli Neonatologi",
  "hospital": "Mayapada Hospital Kuningan",
  "hospitalAddress": "Mayapada Hospital Kuningan, Setiabudi, Jakarta",
  "consultationPrice": 350000,
  "priceCurrency": "IDR",
  "rating": "89%",
  "reviewCount": 18,
  "nextSchedule": "Jadwal Berikutnya : Besok, 16.00 Siang",
  "listName": "Dokter Anak",
  "_listingScope": "specialty:dokter-anak/jakarta"
}
```

**`doctor` mode** — real output, arrays truncated:

```json
{
  "recordType": "DOCTOR_PROFILE",
  "name": "dr. Rifan Fauzie, Sp.A (K)",
  "specialty": "Pediatrics",
  "specialtyLabel": "Dokter Anak - Ahli Respirologi",
  "hospital": "RSIA Bunda Jakarta",
  "hospitals": [
    { "name": "RSIA Bunda Jakarta", "address": "Jl. Teuku Cik Ditiro No.28 Menteng Jakarta Pusat, Menteng, Gondangdia, Kota Jakarta Pusat" },
    { "name": "Brawijaya Hospital Saharjo", "address": "Jl. Dr. Saharjo No.199, Tebet Bar., Kec. Tebet, Kota Jakarta Selatan" }
  ],
  "addresses": [
    { "streetAddress": "Jl. Teuku Cik Ditiro No.28 …", "locality": "Jakarta", "region": "Daerah Khusus Ibukota Jakarta", "country": "ID" },
    "… 1 more"
  ]
}
```

| Field | Type | Description |
|---|---|---|
| `recordType` | string | `DOCTOR_CARD`, `DOCTOR_PROFILE`, `SPECIALTY`, or `CITY`. |
| `name` | string | Doctor's name with title. |
| `specialty` / `specialtyLabel` | string | Specialty as published. |
| `hospital` / `hospitalAddress` | string | Primary hospital and its address. |
| `hospitals` | array | Every hospital the doctor practises at. |
| `addresses` | array | Full postal addresses with locality and region. |
| `consultationPrice` / `priceCurrency` | integer / string | Consultation fee and currency. |
| `rating` | string | Patient satisfaction as a percentage, e.g. `"98%"`. |
| `reviewCount` | integer | Number of patient reviews. |
| `nextSchedule` | string | Next availability text. |
| `profileUrl` | string | Public doctor page. |
| `_error` / `_errorDetail` | string | Present only when a page could not be fetched. |

### Notes & limits

- **Listing pages hold 10 doctors.** `maxItems` decides how many pages are walked; an empty page ends the run.
- **Rating is a percentage, not a 5-point score** — the source publishes patient satisfaction as `"98%"`, so it is passed through as text rather than converted.
- **Prices come from listing rows.** A doctor's own page does not always repeat the fee, so run `specialty` mode (or `enrichProfiles`, which keeps both) when you need pricing.
- **Availability text is time-sensitive** — "Tersedia Hari Ini" reflects the moment of the run; schedule a recurring run if you are tracking it.
- **Specialty slugs are Indonesian** (`dokter-anak`, `dokter-jantung`…). An unknown slug returns a clear `not_found` error rather than an empty dataset.
- Only publicly published professional listings are collected; no patient data is involved.

# Actor input Schema

## `mode` (type: `string`):

"specialty" lists doctors in one or more specialties, optionally scoped to a city. "doctor" fetches full detail for specific doctor pages. "reference" verifies the specialty slugs live and lists the city facets.

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

"specialty" mode: which specialty to list.

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

"specialty" mode: several specialties to list in one run.

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

"specialty" mode: restrict to one city slug, e.g. "jakarta", "bali", "balikpapan". Leave blank for all Indonesia. Run mode=reference to see the slugs.

## `enrichProfiles` (type: `boolean`):

"specialty" mode: after listing, fetch each doctor's own page too -- adds every practice address and all hospitals they work at. Costs one extra request per doctor.

## `doctorUrl` (type: `string`):

"doctor" mode: a full alodokter.com doctor address, or just the slug (e.g. "dr-rifan-fauzie-spa-k").

## `doctorUrls` (type: `array`):

"doctor" mode: several doctors to fetch in one run.

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

"specialty" mode: max doctors per specialty. Listing pages hold 10 each and are followed automatically until this cap or the end of the list.

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

How many doctor pages to fetch in parallel ("doctor" mode, and "specialty" mode when full profiles are enabled).

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

Apify Proxy configuration. Residential is on by default; an Indonesian exit gives the most representative availability text.

## Actor input object example

```json
{
  "mode": "specialty",
  "specialty": "dokter-anak",
  "city": "jakarta",
  "enrichProfiles": false,
  "doctorUrl": "https://www.alodokter.com/cari-dokter/dr-rifan-fauzie-spa-k",
  "maxItems": 100,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

All doctor / reference records produced by this run.

# 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 = {
    "mode": "specialty",
    "specialty": "dokter-anak",
    "city": "jakarta",
    "doctorUrl": "https://www.alodokter.com/cari-dokter/dr-rifan-fauzie-spa-k",
    "maxItems": 100,
    "maxConcurrency": 4,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("fanndev/alodokter-doctor-directory-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 = {
    "mode": "specialty",
    "specialty": "dokter-anak",
    "city": "jakarta",
    "doctorUrl": "https://www.alodokter.com/cari-dokter/dr-rifan-fauzie-spa-k",
    "maxItems": 100,
    "maxConcurrency": 4,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("fanndev/alodokter-doctor-directory-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 '{
  "mode": "specialty",
  "specialty": "dokter-anak",
  "city": "jakarta",
  "doctorUrl": "https://www.alodokter.com/cari-dokter/dr-rifan-fauzie-spa-k",
  "maxItems": 100,
  "maxConcurrency": 4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call fanndev/alodokter-doctor-directory-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fanndev/alodokter-doctor-directory-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/OFMv7OeBZ5L7AagBQ/builds/jYpbJ9h4A2JDbU4zf/openapi.json
