Doctolib Practitioners Scraper (FR, DE, IT)
Pricing
from $0.59 / 1,000 practitioner profiles
Doctolib Practitioners Scraper (FR, DE, IT)
Scrape healthcare professionals from Doctolib France, Germany and Italy by speciality and city, or the whole directory: name, speciality, address with GPS, phone, RPPS, sector, payment means, languages, fees, opening hours, visit motives, photo. Public professional data only.
Pricing
from $0.59 / 1,000 practitioner profiles
Rating
0.0
(0)
Developer
Nice Dev
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
13 hours ago
Last modified
Categories
Share
🔎 What is Doctolib Practitioners Scraper?
Doctolib Practitioners Scraper extracts the public directory of healthcare professionals on Doctolib — France, Germany and Italy — : name, specialities, practice address with GPS coordinates and Google Maps link, phone number, RPPS / ADELI legal ids, sector (conventionnement), Carte Vitale, payment means, languages spoken, fees, opening hours, skills, diplomas, presentation, photo, every bookable visit motive, and the next available appointment with the open slots of the week, for individual practitioners and establishments (clinics, health centres, laboratories).
Pick one or several specialities (dentiste, Médecin généraliste, zahnmedizin, odontoiatra…) and one or several cities (Paris, Lyon, paris-75009, Berlin, Milano, or the whole country), or paste Doctolib search / profile URLs, click Start, and download the results in JSON, CSV or Excel. No login: about 100 full profiles a minute, at a low price.
Scope: what Doctolib shows to any anonymous visitor — the professional profile and, on request, the open appointment slots of its booking calendar. Never patient data, and nothing behind a login.
📋 What data can you extract from Doctolib?
One item per Doctolib profile (a practitioner or an establishment, deduplicated), 78 fields, listed one by one under Output:
| Category | What you get |
|---|---|
| 👤 Who | name, title, gender, practitioner or establishment (clinic, health centre, laboratory), team of an establishment |
| 🩺 Speciality | main speciality and every other one, skills and procedures, diplomas, career, presentation |
| 📍 Where | practice address, postcode, city, department, GPS, Google Maps link, distance from the searched city, every practice location |
| 📞 Contact | practice phone (also in international format), website, practice name |
| 🪪 Legal ids | RPPS, ADELI, SIRET (France, when published) |
| 💶 Fees and payment | sector (conventionnement) and its label, Carte Vitale, third-party payer, insurance sector (Germany, Italy), payment means, fees per act |
| 🗣️ Practice | languages spoken, opening hours, home visits, telehealth, accessibility, floor, lift, public transport, parking, photos |
| 📅 Booking | online booking or directory only, accepting new patients, visit motives and agendas, next available appointment, days to wait, open slots of the week |
| 🔎 Search | the search that found the profile, its results page, scrape date |
Detail fields (phone, rpps, bio, fees, openingHours, skills, specialities, places, practitioners, accessibility) are filled when Extract details is on (default, one request per profile). Turn it off for a search-card-only scrape that is much faster (one request per 20 profiles): name, speciality, address, GPS, sector, payment means, languages, photo. visitMotives, visitMotiveNames and agendas need Include every visit motive (one more request per bookable profile, same price). The slot fields need Next available appointment (one more request per bookable profile, two without a search card; appointment-slots per profile saved with an open slot) and stay null without it.
✅ Why use Doctolib Practitioners Scraper?
- 🚀 Fast: about 100 profiles with full details in a minute at the default rate, a few thousand per hour.
- 🌍 France, Germany and Italy in the same Actor: pick the Country, or paste URLs of the three sites together.
- 🗂️ Several searches in one run: specialities × cities, with a cap per search so that one big city cannot eat the whole budget.
- 🔔 Monitoring built in: tick Only new profiles, schedule the Actor, and each run returns (and charges) only the practitioners it has never delivered before — new doctors in your area, week after week.
- 📚 Whole directory: the sitemaps source walks Doctolib's public sitemaps (≈ 615 000 French profiles), in several runs if you want.
- 🧾 Complete profiles: RPPS, GPS, fees, opening hours, languages, payment means, all practice locations, accessibility and public transport, establishment teams, every visit motive — fields other scrapers leave empty because they read the HTML.
- 📅 Next available appointment: the first open slot (even beyond the week, when Doctolib names it), the days to wait and the open slots of the week — waiting times by speciality and city, or only the practitioners with a slot within N days.
- 🎯 Filters: sector (secteur 1, secteur 2, OPTAM, non conventionné, establishments…), insurance sector in Germany (public / private), languages spoken, with a phone number only, accepting new patients only, available within N days, excluded words, and a suppression list of profiles never to deliver (by id, slug or URL). Sector, insurance and language filters are applied by Doctolib's own search engine (also on the search URLs you paste: they add to the filters written in the URL, and the URL's own value wins), so you only pay for the profiles you asked for; on a pasted profile URL, sector and language are checked by the Actor instead (insurance sector cannot be judged on a profile and is ignored); the other filters are applied by the Actor on every profile it reads, and each profile they check is charged a filter fee, kept or not.
- 🔌 API, scheduling, integrations (Make, Zapier, n8n, Google Sheets…) and JSON/CSV/Excel export via the Apify platform.
🚀 How to scrape Doctolib
- Create a free Apify account.
- Open Doctolib Practitioners Scraper, choose the Country, type a Speciality (e.g.
dentiste) and a Location (e.g.Paris) — add more in More specialities / More locations. - Or paste your own URLs into Start URLs: Doctolib results pages (filters set on the site are kept) or single profile pages, from doctolib.fr, doctolib.de or doctolib.it.
- Set Max practitioners (100 by default, 0 = no limit) — and Max profiles per search when you run several searches — then click Start.
- Download the dataset in JSON, CSV, Excel or via API. The Contact sheet view gives one clean line per practitioner with legal id, practice phone and address.
💰 How much does it cost to scrape Doctolib?
This Actor uses pay per event pricing: you pay for each profile, and for the appointment slots or a filter only when you ask for them.
| Apify plan | Profile (details and visit motives included) | Next available appointment | Card checked by a filter | Profile read for a filter |
|---|---|---|---|---|
| Free | $0.62 | $0.99 | $0.058 | $0.32 |
| Bronze | $0.61 | $0.98 | $0.048 | $0.31 |
| Silver | $0.60 | $0.97 | $0.038 | $0.30 |
| Gold | $0.59 | $0.96 | $0.028 | $0.29 |
Prices per 1,000, plus $0.01 per run start ($1 per 100 runs). Platform usage (compute, proxy) is included in the price. Example: all dentists in Paris (about 8 100 profiles) ≈ $5; a weekly run that returns the 50 new GPs of a city ≈ $0.04.
- Profiles already delivered (Only new profiles) are not charged.
- Next available appointment (event
appointment-slots) is charged per profile saved with an open slot (a next slot, or a slot in the week); a profile without any slot costs nothing more. Available within (days) switches it on: the profiles it keeps come with their slots and are charged the same way. - The filters the Actor applies itself are charged on every profile they check, kept or not: event
filter-checkper search card checked by Exclude keywords, Accepting new patients only or the suppression list; eventdetail-filter-checkper profile read for With a phone number only, Available within (days) (and the sector / language filters of the sitemaps source or of a pasted profile URL), or for any filter on a profile without a search card (sitemaps source, pasted profile URL).
⚙️ Input
{"speciality": "Ophtalmologue","location": "Lyon","regulationSector": ["CONTRACTED_1", "CONTRACTED_2_WITH_OPTAM"],"languages": ["gb"],"maxItems": 200,"extractDetails": true}
Several specialities and cities, a cap per search, phone numbers only, every visit motive, only the practitioners not delivered before:
{"speciality": "dentiste","searchQueries": ["medecin-generaliste", "pediatre"],"location": "Paris","locations": ["Lyon", "Marseille"],"maxItemsPerQuery": 50,"requirePhone": true,"includeVisitMotives": true,"onlyNew": true,"stateKey": "big-cities-monthly"}
General practitioners of Bordeaux with an appointment slot within 3 days, with the next slot and the open slots of the week:
{"speciality": "medecin-generaliste","location": "Bordeaux","availabilitiesBefore": 3,"maxItems": 50}
Germany, through the public sitemaps, every speciality of a city:
{"country": "de","source": "sitemaps","speciality": "","location": "Berlin","maxItems": 500}
Or with your own URLs (any of the three countries):
{"startUrls": [{ "url": "https://www.doctolib.fr/dentiste/paris-75009" },{ "url": "https://www.doctolib.fr/dentiste/paris/vincent-bourasset?pid=practice-320361" },{ "url": "https://www.doctolib.it/medico-di-medicina-generale/milano/barbara-riva" }],"maxItems": 0}
| Field | Default | Notes |
|---|---|---|
startUrls | — | Doctolib search or profile pages (fr / de / it); when set, the search fields below are ignored; the sector, language and insurance filters still apply (added to those written in a search URL) |
country | fr | fr, de or it |
speciality, searchQueries | dentiste (France) | Slug or name of a Doctolib speciality / skill; several = one search each |
location, locations | Paris (France), whole country elsewhere | City, district (paris-75009, Lyon 3), department or region (search source), or empty for the whole country. With Germany or Italy, leaving the form's Paris untouched also means the whole country |
maxItems | 100 | Whole run; 0 = no limit |
maxItemsPerQuery | 0 | Cap for EACH search; 0 = none |
source | search | search (Doctolib's search engine) or sitemaps (public sitemaps) — see the FAQ |
extractDetails | true | Open each profile for phone, RPPS, fees, hours… (always on with sitemaps) |
includeVisitMotives | false | One more request per bookable profile: visitMotives, visitMotiveNames, agendas, all specialities |
scrapeAvailability | false | Next available appointment: nextAvailableSlot, nextAvailableDate, waitTimeDays, totalAvailableSlots (7 days), availabilityVisitMotive; one more request per bookable profile, two without a search card; event appointment-slots per profile saved with an open slot |
availabilitiesBefore | 0 | Keep only the profiles with an open slot within N days (0 = off); switches scrapeAvailability on (its slots and their appointment-slots event come with every profile kept) |
includeOrganizations | true | Keep establishments (clinics, centres, labs) |
regulationSector, languages | [] | France sectors, the exact code Doctolib filters on: doctors in CONTRACTED_1 (secteur 1), CONTRACTED_2, CONTRACTED_2_WITH_OPTAM, CONTRACTED_1_WITH_EXTRA, NON_CONTRACTED; CONTRACTED (no sector) is for dentists and physiotherapists — it keeps 2 general practitioners of Paris out of about 4 500 (2026-09-18); ORGANIZATION_* for establishments. Doctolib language codes (fr, gb, es, de…) |
insuranceSector | any | Germany: public (gesetzlich) or private (privat) — Doctolib France and Italy return every practitioner whatever you pick |
exactMatchOnly | false | Stop before Doctolib's "broad match" results (search source) |
requirePhone, excludeKeywords | false, [] | Phone number required; drop names / specialities / establishment types containing a word |
onlyAcceptingNewPatients | false | Only practitioners whose visit motive in the search results accepts new patients (search source) |
suppressedDoctorIds, suppressedDoctorSlugs | [] | Profiles never to deliver (e.g. a practitioner who opted out): Doctolib ids, or slugs / profile URLs |
onlyNew, stateKey, resetState | false, default, false | Only the profiles no previous run with the same memory key delivered |
proxyConfiguration | Apify Proxy | Keep the default: it is included in the price (the residential Apify proxy is not available in this Actor) |
maxConcurrency, maxRequestsPerMinute, maxRequestRetries, debugLog | 8, 120, 4, false | Advanced |
📦 Output
{"id": 1537577,"url": "https://www.doctolib.fr/dentiste/paris/vincent-bourasset?pid=practice-320361","slug": "vincent-bourasset","practiceId": 320361,"type": "practitioner","organizationType": null,"title": null,"firstName": "Vincent","lastName": "BOURASSET","fullName": "Vincent BOURASSET","gender": null,"speciality": "Chirurgien-dentiste","specialitySlug": "dentiste","specialities": [{ "id": 1, "name": "Chirurgien-dentiste", "slug": "dentiste", "kind": "medical" }],"address": "26 Rue Marbeuf","zipcode": "75008","city": "Paris","country": "fr","fullAddress": "26 Rue Marbeuf, 75008 Paris","department": "75","distanceMeters": 3659,"latitude": 48.8688803,"longitude": 2.3044131,"googleMapsUrl": "https://www.google.com/maps/search/?api=1&query=48.8688803,2.3044131","phone": "01 43 43 48 87","phoneE164": "+33143434887","website": null,"practiceName": "Cabinet 26 Rue Marbeuf, 75008 Paris","rpps": "10100726651","adeli": null,"siret": null,"regulationSector": "contracted","regulationSectorLabel": "Conventionné","acceptsInsuranceCard": true,"thirdPartyPayer": "national","homeVisit": false,"paymentMeans": ["check", "cash", "credit_card", "bank_transfer"],"languages": ["gb", "fr", "it"],"hasOnlineBooking": true,"isDirectoryOnly": false,"telehealth": false,"allowsNewPatients": true,"visitMotive": "Première consultation dentaire nouveau patient","visitMotiveFee": null,"minimumFee": null,"visitMotives": [{ "id": 11858391, "name": "Première consultation dentaire", "telehealth": false, "specialityId": 1, "practiceIds": [320361] },{ "id": 16080775, "name": "Consultation d'implantologie", "telehealth": false, "specialityId": 1, "practiceIds": [807766] }],"visitMotiveNames": ["Première consultation dentaire", "Contrôle annuel et/ou détartrage", "Urgence dentaire", "Consultation d'implantologie"],"agendas": [{ "id": 2563820, "practiceId": 320361, "specialityId": 1, "practitionerId": 81680262, "bookingDisabled": false, "phone": "01 43 43 48 87", "visitMotiveCount": 6 },{ "id": 2578019, "practiceId": 807766, "specialityId": 1, "practitionerId": 81680262, "bookingDisabled": false, "phone": "09 86 24 76 46", "visitMotiveCount": 7 }],"agendaIds": [2563820, 2578019],"availabilityVisitMotive": "Première consultation dentaire nouveau patient","nextAvailableDate": "2026-09-24","nextAvailableSlot": "2026-09-24T09:00:00.000+02:00","waitTimeDays": 7,"totalAvailableSlots": 7,"fees": [{ "name": "Contrôle et détartrage", "minPrice": 140, "maxPrice": null, "isFixed": true },{ "name": "Consultation", "minPrice": 50, "maxPrice": 140, "isFixed": false }],"bio": "Le Dr Bourasset offre à ses patients un panel complet de soins dentaires : esthétique, soins, prothèse, chirurgie, endodontie, pédodontie, parodontie.","skills": [],"formations": [{ "title": "Contention Fibrée", "establishment": "Eumeria", "year": 2025 }],"experience": [],"associations": [],"openingHours": ["Mon 09:00-13:00, 14:00-17:00", "Tue 08:30-13:00, 14:00-18:30", "Wed 08:30-13:00, 14:00-18:30", "Thu 08:30-13:00, 14:00-18:30", "Fri 09:00-13:00, 14:00-18:30"],"floor": "2ème étage avec ascenseur","elevator": true,"handicapAccess": false,"accessInformation": ["2ème étage avec ascenseur"],"stations": ["metro 1 Georges V", "metro 9/1 Franklin D. Roosevelt", "rer C Pont De L'Alma"],"parking": "Parking Marbeuf Champs-Elysées","places": [{ "id": "practice-320361", "name": "Cabinet 26 Rue Marbeuf, 75008 Paris", "address": "26 Rue Marbeuf", "zipcode": "75008", "city": "Paris", "latitude": 48.8688803, "longitude": 2.3044131, "phone": "01 43 43 48 87" },{ "id": "practice-807766", "name": "Cabinet Monceau Courcelles", "address": "38 Boulevard de Courcelles", "zipcode": "75017", "city": "Paris", "latitude": 48.8808058, "longitude": 2.3107689, "phone": "09 86 24 76 46" }],"placesCount": 2,"practitioners": [],"photo": "https://media.doctolib.com/image/upload/q_auto:eco,f_auto/yfp5k9ij8dwqv2ff0arl.jpg","pictures": ["https://media.doctolib.com/image/upload/q_auto:eco,f_auto/yfp5k9ij8dwqv2ff0arl.jpg", "https://media.doctolib.com/image/upload/q_auto:eco,f_auto/vkelgwhtaud4iaoebhcc.jpg"],"exactMatch": true,"searchSpeciality": "dentiste","searchLocation": "Paris","searchUrl": "https://www.doctolib.fr/dentiste/paris","scrapedAt": "2026-09-17T09:00:00.000Z"}
Requests that fail for good (a profile removed between the search and the detail request, a location Doctolib does not know among several searches, a network error after every retry) are listed in the FAILED_REQUESTS record of the run's key-value store, never in the dataset. A run that saves nothing while requests failed ends as FAILED, so a broken run is never mistaken for an empty search.
All 78 fields
| Fields | What you get |
|---|---|
id, url, slug, practiceId, country | 1537577, https://www.doctolib.fr/dentiste/paris/vincent-bourasset?pid=practice-320361, fr |
type, organizationType | practitioner / organization, Clinique privée |
title, firstName, lastName, fullName, gender | Dr, Vincent, BOURASSET, Vincent BOURASSET, male (search results) |
speciality, specialitySlug, specialities | Chirurgien-dentiste, dentiste, every speciality with its id and kind |
address, zipcode, city, department, fullAddress, latitude, longitude, googleMapsUrl | 26 Rue Marbeuf, 75008, Paris, 75 (France), 48.8688803, 2.3044131, map link |
distanceMeters | 3659: metres from the searched city or district to the practice, as the crow flies (search source) |
phone, phoneE164, website, practiceName | 01 43 43 48 87, +33143434887 (+49… Germany, +39… Italy) |
rpps, adeli, siret | 10100726651 (French legal ids, when published) |
regulationSector, regulationSectorLabel, acceptsInsuranceCard, thirdPartyPayer, homeVisit | contracted, Conventionné secteur 2, true, national |
insuranceSector | public / private — Germany and Italy only (always null in France) |
paymentMeans, languages | ["cash","check","credit_card","bank_transfer"], ["fr","gb","it"] |
hasOnlineBooking, isDirectoryOnly, telehealth, allowsNewPatients, visitMotive, visitMotiveFee | booking status, first bookable visit motive and its price when Doctolib shows one |
visitMotives, visitMotiveNames, agendas | every bookable visit motive (with the practices that offer it) and every agenda — option Include every visit motive |
agendaIds | Doctolib ids of the booking agendas (search results; all of them with Include every visit motive) |
nextAvailableSlot, nextAvailableDate, waitTimeDays, totalAvailableSlots, availabilityVisitMotive | 2026-09-24T09:00:00.000+02:00, 2026-09-24, 7 days to wait, 7 open slots this week, for Première consultation dentaire — option Next available appointment |
fees, minimumFee | [{ "name": "Consultation", "minPrice": 50, "maxPrice": 140, "isFixed": false }] |
bio, skills, formations, experience, associations | presentation text, procedures, diplomas, career |
openingHours, floor, elevator, handicapAccess, accessInformation, stations, parking | ["Mon 09:00-13:00, 14:00-17:00", …], metro 1 Georges V |
places, placesCount | every practice location of the profile (address, GPS, phone) |
practitioners | team of an establishment (name, speciality, profile URL) |
photo, pictures | Doctolib media URLs (never Doctolib's grey default avatar) |
exactMatch, searchSpeciality, searchLocation, searchUrl, scrapedAt | how the profile was found |
💡 Tips
How to get more results
- Big cities: Doctolib returns at most 10 000 profiles per search.
dentiste+Parisis fine (≈ 8 100); formedecin-generalistein the whole country, put the departments or cities in More locations, or use the sitemaps source. - Directory-only profiles (
isDirectoryOnly: true) are practitioners who are not Doctolib customers: address, phone and RPPS are usually present, but no fees, hours, presentation or visit motives. - Broad matches: after the exact matches, Doctolib appends practitioners from nearby towns or close specialities (
exactMatch: false). Keep them for wider lists or setexactMatchOnly.
How to reduce costs
The price is per profile, so maxItems and maxItemsPerQuery are the cost levers. With extractDetails off (search source) a run needs one request per 20 profiles: about 150 profiles in a few seconds. Only new profiles never charges the profiles it skips; a filter applied by the Actor charges each profile it checks, kept or not (see the pricing above).
Several searches in one run
Every speciality of Speciality + More specialities is searched in every city of Location + More locations (up to 500 searches). Max profiles per search caps each of them; Max practitioners caps the whole run. A practitioner found by two searches is saved once, for the search that found them first (searchUrl). A location Doctolib does not know is reported in the log and in FAILED_REQUESTS; the other searches go on.
Monitoring: only the new profiles
Tick Only new profiles and schedule the Actor (daily, weekly…): each run returns only the practitioners that no previous run with the same Memory key delivered — they are not even requested, and not charged. Give each schedule its own key. The memory lives in the named key-value store doctolib-practitioners-scraper-seen of your account (up to 700 000 profiles per key); Reset the memory starts over. Two runs at the same time on the same key may deliver a profile twice.
Whole directory with the sitemaps source
source: "sitemaps" reads Doctolib's public sitemaps (France: 123 files, ≈ 615 000 profiles; Germany and Italy too) one file at a time and keeps the profiles whose URL names the speciality and the city you asked for — leave Speciality and Location empty for everything. Combine it with Only new profiles: every run continues where the previous one stopped. Differences with the search source: exact city only (no department, no radius, no skill), no allowsNewPatients / visitMotive from a search card, and sector / language filters are checked on each profile. A district (paris-75009) reads the Paris profiles and keeps those with a practice in the district: about 50 profiles read per profile kept.
Germany and Italy
Choose Country de or it and use that site's speciality slugs (zahnmedizin, allgemeinmedizin, odontoiatra, medico-di-medicina-generale: an unknown value lists the closest ones). The sector filter (conventionnement) and the RPPS / ADELI ids only exist in France; phone numbers are converted to +49 / +39.
⚖️ Legal and privacy
This Actor collects only what Doctolib shows to any anonymous visitor: the professional identity, practice address and phone, legal ids (RPPS/ADELI are public identifiers), fees, hours, visit motives and presentation that healthcare professionals and establishments publish, and — with Next available appointment — the open slots of their public booking calendar, as a count and a first date, never who booked them. It does not access patient data or any authenticated area, and it does not download photos. Practitioners' names, phones and calendars are personal data under GDPR: you are responsible for using the data in compliance with GDPR and Doctolib's terms of use, in particular for direct marketing to professionals.
🔌 Integrations and API
Connect the Actor to Google Sheets, Slack, Make, Zapier, n8n, webhooks or your own code with the Apify API and the JavaScript / Python clients. Schedule it with Only new profiles to keep a practitioner database fresh, or call it on demand from your CRM.
🤖 Use with AI agents (MCP)
AI agents (Claude, ChatGPT, Cursor…) can find and run this Actor through the Apify MCP server, billed to their Apify account like any run. It returns one item per Doctolib profile: a practitioner or an establishment. Actor id: nice_dev/doctolib-practitioners-scraper; MCP server with this Actor only: https://mcp.apify.com/?tools=fetch-actor-details,nice_dev/doctolib-practitioners-scraper.
Smallest input, for a cheap first call:
{"speciality": "dentiste","location": "Paris","maxItems": 10}
Key output fields: url, fullName, speciality, fullAddress, city, phone, rpps, nextAvailableDate.
Cost: $0.62 per 1,000 profiles plus $0.01 per run start ($0.59 per 1,000 on the Gold plan); the appointment slots (appointment-slots) and the Actor's own filters are charged on top, see the pricing section above. Cap each call with maxItems and, through the API, with the run option maxTotalChargeUsd.
❓ FAQ
Is it legal to scrape Doctolib?
The Actor only reads what Doctolib shows publicly to any anonymous visitor about professionals: identity, speciality, practice address and phone, public legal ids, fees, hours, visit motives and, on request, the open slots of their booking calendar. It logs in to nothing, and reads no patient data. Results contain personal data, which is protected by GDPR: do not store it without a legitimate reason, and keep the practitioners who ask to be left out in Suppressed profile ids / Suppressed profile slugs. You are responsible for using the data in compliance with Doctolib's Terms of Use and applicable law. This Actor is not affiliated with Doctolib.
What is the difference between the two sources?
- search (default) returns what Doctolib's own results page shows: nearest practitioners around a place, relevance order, cities, districts, departments and regions, and the sector / insurance / language filters applied by Doctolib itself. Measured on 2026-09-17: 20 dentists of Paris 9ᵉ in 3 seconds, all 20 really in the 75009 zipcode.
- sitemaps walks the sitemaps Doctolib publishes for crawlers and the profile pages they list. It has no notion of distance or filter: it matches the city written in each profile URL, so a district search reads the whole city and throws most of it away (95 profiles read for 2 kept on Paris 9ᵉ, 2026-09-17), and one sitemap file weighs about 450 KB. Use it for the whole directory (≈ 615 000 French profiles) or to walk a country in successive runs with Only new profiles.
- The two sources give the same fields, not the same profiles. On a partial run they barely overlap, because they walk Doctolib in a different order (distance and relevance for search, file order for sitemaps): 20 dentists of Paris 9ᵉ from each on 2026-09-18, 1 in common. On a complete list they mostly agree: for the dentists of Vannes, search returned 65 practitioners (48 in Vannes, then 17 from nearby towns flagged
exactMatch: false) and sitemaps 59 profiles in Vannes, 47 of them in both. The 12 found only by sitemaps are profiles Doctolib's own search no longer shows (4 with no practice at all, most without a phone number); the one found only by search is filed under another speciality. - With the sitemaps source, the fields that come from the search card stay
null(allowsNewPatients,visitMotive,visitMotiveFee,minimumFee,insuranceSector,gender,distanceMeters) andexactMatchis alwaystrue. With Next available appointment, the slots are those of the first in-person visit motive of the practice instead of the motive the search matched (availabilityVisitMotivesays which), for one more request per profile.
Can it return appointment slots or availabilities?
Yes, with Next available appointment (scrapeAvailability). For each bookable profile the Actor asks Doctolib for the open slots of one visit motive, the way the profile page does: the motive the search matched (Première consultation dentaire…), or — for a profile found without a search card — the first in-person motive of its practice. You get nextAvailableSlot (first open slot; beyond the week when Doctolib names it), nextAvailableDate, waitTimeDays (0 = a slot today) and totalAvailableSlots over the 7 days from the run day. Available within (days) keeps only the practitioners with a slot within N days. It costs one more request per bookable profile (two without a search card), charged apart: event appointment-slots per profile saved with an open slot, nothing for a profile without any (see the cost section). Directory-only profiles (not Doctolib customers) have no calendar and keep these fields null. In Germany and Italy, a motive open to private patients only is asked for them (insurance_sector=private, as the results page does): without it Doctolib answers "not bookable". Slots change by the minute: a run is a snapshot. Reviews do not exist on Doctolib France, Germany or Italy.
Does it need a login or a proxy?
No login. The proxy is included in the price: leave the default setting (the residential proxy is not available). A request Doctolib turns away (HTTP 403 / 429) is retried at once on a new proxy session — without a proxy, after a pause of 5 seconds, doubled at each retry up to 20 seconds.
Is the data safe to open in Excel or to show on a web page?
Every phoneE164 starts with +, and a name, a speciality or a presentation is the professional's own words, copied as they are: a text can begin with -, +, = or @. Excel and Google Sheets may read such a cell of a CSV file as a formula or as a number. The Actor leaves the text as it is, so that the JSON and the API give the real value: when you open a CSV, import these columns as text. Every URL field (url, photo, pictures, website, googleMapsUrl, the profile links of practitioners) holds an http(s) URL or null, so none of them can carry a script. On a web page, escape every field like any text written by a stranger.
Known limitations
- Doctolib caps one search at 10 000 results: split big searches by city, or use the sitemaps source.
insuranceSectoronly filters on Doctolib Germany (Berlin general practitioners, 2026-09-17: 2 125 total, 796 public, 887 private). France and Italy accept the filter and return everybody. Even in Germany the field itself is filled on about half of the cards. It needs the search source: the sitemaps source refuses it, since a profile read from a sitemap carries no insurance sector.- The sitemaps source matches the city of the profile URL exactly and checks that a practice is still there. A profile without any practice (a practitioner who left Doctolib's search) is kept for a city search — its URL is the only place it gives — and dropped for a district search.
- A filter that matches (almost) nothing reads profiles until it stops: after 300 profiles in a row rejected, 2 000 extra requests, or when the run's maximum cost is reached, whichever comes first (each profile checked is charged, see Pricing).
- Detail fields are
nullor empty whenextractDetailsis off; visit motives needincludeVisitMotives; slots needscrapeAvailabilityandextractDetails(they are not read in the search-card-only mode). - Slots are those of ONE visit motive (
availabilityVisitMotive), not of every motive of the practitioner; an establishment's slots cover at most 100 of its agendas. A query Doctolib refuses leaves the slotsnull(0 means: asked, none this week). - An establishment read without its search card (sitemaps source, pasted profile URL) has no
languagesand itsspecialityis its type (Laboratoire): Doctolib's profile of an establishment has neither the speciality it was found for nor languages. A practitioner gives the same values with or without the card. onlyNewremembers which profiles were delivered, not their content: a profile whose phone changed is not returned again. Two runs sharing the samestateKeyat the same time may both return the same new profile.- Doctolib may change its pages without notice: see below what happens then.
A run the platform stops without warning (out of memory, run timeout)
- Resurrect it: it goes on from where it stood at most a minute before the stop. What it had read since is read again, and the profiles already saved are skipped: none is delivered or charged twice, and Max practitioners still counts them.
- With Only new profiles, the memory is saved after each write (at most once every 2 seconds): resurrect the stopped run and the profiles it had saved meanwhile join the memory; leave it stopped for good, and the next run may return the profiles of its last 2 seconds once more.
Something doesn't work?
The last line of the log counts the profiles saved, filtered out, already delivered by a previous run and no longer on Doctolib (removed while the run was reading them), and the requests that failed after every retry. Those requests and the removed profiles are listed, with the reason, in the FAILED_REQUESTS record of the run's key-value store. A run that saved nothing and had failed requests fails, and its last message gives the cause (a speciality Doctolib does not know says so, instead of "run it again"). A run that saved some profiles fails too when at least as many requests failed for good as were read (page 1 read, the next pages or the profile pages blocked): a green run with a short dataset would hide the outage. One failed request among many is only a warning.
If Doctolib changes its pages, you are told instead of paying for blank rows. A results page that counts practitioners but gives none the Actor can read is an error (listed in FAILED_REQUESTS), never a quiet "No profiles found". If the first 20 profiles read all lack their last name or speciality (practitioners), their city and GPS position, the visit motive of their search card, or — for a profile page — its list of practices, or — with Next available appointment — an answer to their slots query, the run saves nothing more, stops and fails, and its last message names the missing field: at most those first profiles are charged.
🛟 Support
Open an issue in the Issues tab of the Actor with a link to your run: the run log and the FAILED_REQUESTS record of the key-value store show exactly which URLs failed and why.