Florida Medical License Scraper — DOH MQA Verification
Pricing
$3.00 / 1,000 per licensee record returneds
Florida Medical License Scraper — DOH MQA Verification
Primary-source verification and bulk extraction of Florida's 3.48M health care licenses from the DOH/MQA portal: physicians, nurses, dentists, pharmacists and 32 more boards. Paste license numbers to verify, or filter by board, profession, county or ZIP. Status, address, expiry, discipline.
Pricing
$3.00 / 1,000 per licensee record returneds
Rating
0.0
(0)
Developer
Scrapers Delight
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Every licensed health care practitioner in Florida, from the state's own primary source. Paste a list of license numbers and get them verified one by one, or pull a whole board, profession or county in bulk. One row per licensee: license number, name, profession, board, license status, address of record, original issue date, expiration date, days-until-expiry, controlled-substance prescriber flag, cannabis-order authority, and the full disciplinary and public-complaint history with case numbers and document IDs — plus e-mail, specialty board certifications, hospital staff privileges, Medicaid participation and other-state licenses on physicians. $0.003 per licensee — $3 per 1,000. No login, no API key, no CAPTCHA, no proxy needed.
Source: the Florida Department of Health's Medical Quality Assurance license verification portal — the state's designated primary source for license verification, which is the standard a credentialing file has to meet.
3,481,761 license records across 36 boards and 237 professions, measured 2026-08-12 as the sum of the portal's own authoritative per-board totals — not quoted from a marketing page. Filter by board, profession, county, city, ZIP, last name, first name, business name or license status.
{"board": "15","profession": "1501","county": "13","detailLevel": "license","maxItems": 100}
Click Try for free and hit Start — that is the input the Actor ships with. Measured 2026-08-12: 100 practicing Bay County physicians, full license depth, 29 seconds, coverage verified 100.0% against the portal's own roster, $0.30.
Calling it from the API, an MCP client or an agent with an empty input ({}) does not fail: the
run falls back to that same sample search — capped at 100 licensees, $0.30 — and the log and run
status name the fields to set for your own search. Nothing is charged when a search matches nothing.
What this Actor does
Florida MQA licenses essentially every regulated health care occupation in the state — physicians, osteopaths, physician assistants, registered and practical nurses, CNAs, APRNs, dentists, dental hygienists, pharmacists, pharmacy technicians and pharmacy facilities, massage therapists, physical and occupational therapists, psychologists, clinical social workers, marriage and family therapists, mental health counselors, chiropractors, optometrists, podiatrists, acupuncturists, speech-language pathologists and audiologists, respiratory therapists, dietitians, athletic trainers, EMTs and paramedics, EMS provider organizations, clinical laboratory personnel, opticians, orthotists and prosthetists, genetic counselors, midwives, electrologists, hearing aid specialists, nursing home administrators, radiation-control licensees, 911 telecommunicators and out-of-state telehealth providers.
It serves two jobs from one input form:
- Primary-source verification. Paste the license numbers you already hold. Each resolves straight to its own DOH verification page, all statuses searched, so a revoked or null-and-void license still verifies. Numbers that match nothing are named in the log, written to the key-value store, and never charged.
- Bulk extraction. Pick a board, profession and location and pull the slice — at roster depth the whole slice arrives in a single request.
Why scrape MQA yourself when this exists?
Every one of these is a measured behaviour of the live portal, not a hypothetical:
- The portal's CSV export truncates silently. Over a certain slice size it returns HTTP 200, a
correct
text/csvcontent-type, a valid header row — and zero data rows. A naive scraper reports that as a successful empty run. Numbers below. - The obvious pagination fix is the bug. The results grid offers a "sort by license number" link and pinning it looks like the way to make offset paging stable. The portal discards that re-sorted set after about a minute and reverts to name order mid-walk, silently dropping licensees.
- Neither county nor license status partitions the data. Filtering by all 67 counties reaches 55.3% of physicians; the state's own two status buckets reach 99.78%. Split a big slice on either axis and you lose rows without being told.
- Search results live in the session, not the query string —
/IndexPaged?page=Nis driven by a cookie, so a concurrent second search corrupts the first one's walk. - A profession code only works with its own board, and a mismatched pair returns no result count at all rather than an error.
- Address of record is withheld on non-practicing licenses and the portal substitutes a "contact the Department" notice in the same slot — parse it naively and you ship that sentence as a street address.
- Deceased licensees carry no address block at all, a different shape again.
- Dates arrive as both
M/D/YYYYandMM/DD/YYYY, and the verification page prints some statuses with a dangling separator ("Null And Void/") where the CSV export prints "Null And Void". - Discipline lives on a separate lazy-loaded tab, keyed by an internal
LicIndyou only get from the results grid, and the document PDFs are behind a POST with an opaque base64 document key. - Some professions have no practitioner profile at all. Florida publishes it for physicians, PAs and ARNPs only — a scraper that promises e-mails on nurses is promising a field the state does not publish.
Quick start
- Open the Actor and click Try for free.
- Either paste license numbers into License numbers to verify, or leave the input exactly as it ships (Board of Medicine → Medical Doctor → Bay County → license depth → 100 rows).
- Hit Start. The default run finishes in about 30 seconds.
- Open the Dataset tab and export as JSON, CSV, Excel, XML or JSONL.
Time to first data: under a minute, no coding.
Verify one license in a single HTTP call (Python)
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("scrapersdelight/florida-medical-license-scraper").call(run_input={"licenseNumbers": ["ME58861", "RN9268431", "ME68270"],"detailLevel": "profile",})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row["licenseNumber"], row["licenseStatus"], row["licenseExpirationDate"],row["disciplineOnFile"], row["email"])
Bulk pull (Node.js / TypeScript)
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });const run = await client.actor('scrapersdelight/florida-medical-license-scraper').call({profession: '1711', // Advanced Practice Registered Nursecounty: '23', // Miami-DadelicenseStatus: 'ACT',detailLevel: 'license',maxItems: 2000,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(`${items.length} practicing Miami-Dade APRNs`);
cURL
curl -X POST "https://api.apify.com/v2/acts/scrapersdelight~florida-medical-license-scraper/runs?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"board":"17","profession":"1701","city":"ORLANDO","detailLevel":"roster","maxItems":5000}'
The killer one-liner: synchronous single-license verification
curl -X POST "https://api.apify.com/v2/acts/scrapersdelight~florida-medical-license-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"licenseNumber":"ME58861","detailLevel":"profile"}'
The finished record comes back in the HTTP response. That is a credentialing check as a single API call, billed at $0.003, with no polling and no webhook.
The wedge: this is the primary source, and it carries the discipline file
Every commercial provider-data product — Healthgrades, Vitals, Doximity, an NPI-derived list — is a secondary source. A credentialing file that has to withstand an audit needs the state board itself. This Actor reads the board itself, and it returns the two things the aggregators do not have:
1. The disciplinary and public-complaint file, structured. Every discipline case, emergency action and public complaint on file, each with its case number, the action taken, and the portal's own document key:
"disciplinaryActions": [{ "type": "Discipline Case", "caseNumber": "201816816","actionTaken": "Obligation(s) Satisfied", "documentId": "Mzg5Mzk4NDQ=" },{ "type": "Public Complaint", "caseNumber": "201816816","actionTaken": "AC Filed", "documentId": "MzcxMzc3MzI=" }]
Actions seen across the measured runs: AC Filed · Obligation(s) Satisfied · Obligations Imposed ·
Revocation · Voluntary Surrender · Suspension Satisfied · Fine · Letter of Concern. documentId is
the portal's own key — POST it as id to /MQASearchServices/Document to pull the signed order PDF.
Measured rarity: 7 of 100 practicing Bay County physicians and 3 of 200 practicing Gainesville physicians carried at least one enforcement entry; on a 300-licensee all-statuses Bay County run, 26 of 300 did. A discipline flag is rare, which is exactly why the buyers who need it cannot sample for it — they need the whole file.
2. The status and expiry that decide whether someone may legally work today. licenseStatus,
isPracticing, licenseExpirationDate and daysUntilExpiry were 100% filled on both measured runs.
That is a renewal-reminder product and a network-integrity product in four fields.
Read this before you buy rows
1. An address of record exists only for practicing licenses. Florida withholds it for
Null-and-Void, Retired, Revoked, Deceased and Voluntarily-Relinquished licenses — and for a small
number of otherwise-active ones — and prints a "contact the Department" notice instead. This Actor
never passes that notice off as a street address: it sets addressWithheld: true and leaves the
address fields null. DOH uses two wordings for that notice ("further information is needed…" and
"This practitioner does not have an address of record on file with the department…"); both are
detected as of 2026-08-19. The 300-licensee table below was measured before the second wording was
handled, so its address column counts a handful of notice rows as addresses — the 100-row table in
the next section is the post-fix measurement.
Measured on a full 300-licensee Bay County physician run, all statuses:
| rows | address | ZIP | expiry date | |
|---|---|---|---|---|
Practicing (Clear/Active etc.) | 183 | 100% | 97% | 100% |
| Non-practicing (Null & Void, Deceased, Retired, Revoked…) | 117 | 9% | 8% | 65% |
That is why License status defaults to Practicing only. Switch it to All statuses when you are credentialing and need to see the bad ones — a license-number lookup always searches all statuses anyway, so a revoked license still verifies.
2. A county filter silently excludes about 45% of licensees. Only about 55% of Florida licensees
have a Florida county on file; the rest hold a Florida license at an out-of-state address. Measured:
the 67 counties sum to 96,534 of 174,569 physicians = 55.3%. Filter by county only when you
actually mean "practises in this county". county is echoed onto each row when you filter by it —
DOH prints no county anywhere in its output, so the field is null otherwise (measured 0% on the
unfiltered Gainesville run).
3. The practitioner profile — e-mail, specialty, hospitals — exists only for physicians. Florida
publishes it for MDs, DOs, PAs and ARNPs, not for nurses, dentists or pharmacists. On those,
detailLevel: "profile" costs nothing extra and simply leaves those fields null.
4. lastName and firstName are null on two kinds of row, deliberately. On the license-number
path, the verification page prints the name in display order only ("PATRICIA LIPFORD ABBITT") with no
comma to split on, and this Actor will not guess a surname out of "JOHN VAN DER BERG". On facility
licenses the comma is a corporate suffix — "Holiday CVS, LLC" is a company, not a person called LLC.
In both cases name holds exactly what DOH printed. Search-driven runs on people (board /
profession / county) do get the comma form and were split 100% on both measured runs.
5. board and boardCode are null when you did not filter by board. DOH does not print the
board on the verification page; it is known only from the search you ran. The profession is always
present and is the finer-grained field anyway.
What you get — one row per licensee
Identity
| Field | Type | Notes |
|---|---|---|
licenseNumber | string | e.g. ME58861, RN9268431. The dedupe key, with professionCode. |
name | string | Exactly as DOH printed it. LAST, FIRST MIDDLE on search runs, display order on license-number lookups. |
lastName / firstName | string | null | Split only when DOH supplies the comma form — see gotcha 4. |
profession | string | e.g. Medical Doctor, Registered Nurse. |
professionCode | string | e.g. 1501, 1701. |
board / boardCode | string | null | Populated when you filtered by board. |
Status and dates — all dates are ISO-8601 YYYY-MM-DD
| Field | Type | Notes |
|---|---|---|
licenseStatus | string | Clear/Active, Null And Void, Retired, Revoked, Probation/Active, Military Active, Obligations/Active, Conditional/Active, Clear/Inactive, Vol Relinquish, Delinquent, Deceased… |
isPracticing | boolean | True for the five statuses the portal itself counts as practicing. |
licenseOriginalIssueDate | date | |
licenseExpirationDate | date | |
daysUntilExpiry | integer | Negative when already expired. Computed at scrape time. |
Address of record
| Field | Type | Notes |
|---|---|---|
addressLine1 / addressLine2 | string | null | |
city / state / zip | string | null | |
county | string | null | Echoed from your filter; DOH never prints it. |
addressWithheld | boolean | true = DOH published a "contact the Department" notice instead of an address. |
Regulatory
| Field | Type | Notes |
|---|---|---|
disciplineOnFile / publicComplaint | boolean | The portal's own flags. |
disciplinaryActions | array | null | {type, name, license, profession, city, state, caseNumber, actionTaken, documentId} |
controlledSubstancePrescriber | boolean | Chronic non-malignant pain prescriber flag. |
authorizedToOrderCannabis | boolean | null | Null means the portal did not render the row at all — see limits. |
qualifications | string | null | e.g. Dispensing Practitioner. |
Practitioner profile (physicians, PAs and ARNPs only; detailLevel: "profile")
| Field | Type | Notes |
|---|---|---|
email | string | null | The address the practitioner published for contact. |
specialtyCertifications | array | null | {specialtyBoard, certification, dateCertified} |
hospitalPrivileges | array | null | {institution, city, state} |
otherStateLicenses | array | null | {state, profession} |
medicaidParticipant | boolean | null | |
practiceAddress | string | null | |
yearBeganPracticing | string | null | As DOH prints it on the profile — usually a full date (07/01/1996), sometimes blank. |
profileAvailable | boolean | Whether DOH publishes a profile for this licensee at all. |
Provenance
| Field | Type | Notes |
|---|---|---|
licenseVerificationUrl | string | The exact DOH page this row came from — put it in the credentialing file. |
sourceUrl / scrapedAt | string | ISO-8601 UTC timestamp. |
detailLevel | string | The depth this row was actually built at. |
Key-value store artifact: NOT_FOUND_LICENSE_NUMBERS — the license numbers from a batch run that
matched nothing. Written only when there are some.
Field fill — measured, not estimated
Every run prints its own measured fill in the log. These two tables are from real runs on 2026-08-12.
A. License depth — 100 practicing Bay County physicians (29 s)
| Field | Fill |
|---|---|
licenseNumber, name, lastName, firstName, profession, professionCode, board, boardCode, county | 100% |
licenseStatus, isPracticing, licenseExpirationDate, licenseOriginalIssueDate, daysUntilExpiry | 100% |
city | 100% |
disciplineOnFile, publicComplaint, controlledSubstancePrescriber, addressWithheld, profileAvailable | 100% |
addressLine1, zip, state | 98% |
addressLine2 | 32% |
qualifications | 22% |
disciplinaryActions | 7% |
authorizedToOrderCannabis | 6% |
email, specialtyCertifications, hospitalPrivileges, otherStateLicenses, medicaidParticipant | 0% (license depth does not fetch the profile) |
Boolean breakdown on the same 100 rows: controlledSubstancePrescriber 29 true / 71 false ·
disciplineOnFile 6 true / 94 false · publicComplaint 6 true / 94 false · addressWithheld 2 true
/ 98 false. Seven rows carried at least one enforcement entry.
B. Profile depth — 200 practicing Gainesville physicians (67 s)
| Field | Fill |
|---|---|
Identity, status, dates, addressLine1, city, practiceAddress | 100% |
zip, state | 98% |
email | 88% |
medicaidParticipant | 66% |
yearBeganPracticing | 63% (re-measured 2026-08-19 on 30 Gainesville physicians; 0% before that build — see changelog) |
hospitalPrivileges | 57% |
specialtyCertifications | 50% |
otherStateLicenses | 50% |
addressLine2 | 48% |
qualifications | 28% |
disciplinaryActions | 2% |
authorizedToOrderCannabis | 0% |
county | 0% (no county filter was applied) |
medicaidParticipant on those 200: 56 true, 76 false, 68 null — null means DOH rendered no Medicaid
statement, which is not the same as "does not participate".
The headline that could mislead you: e-mail is a physician field, not a Florida field. 88% on practicing Gainesville physicians; 0% on nurses, dentists, pharmacists and every other board, because Florida does not publish a practitioner profile for them. Plan against the table that matches the board you are actually pulling.
Three depths
detailLevel | Requests | What you get |
|---|---|---|
roster | 1 for the whole slice | license number, name, profession, city, status |
license (what the form ships prefilled with) | ~1 per licensee | + address of record, original issue date, expiry, days-until-expiry, controlled-substance flag, cannabis-order authority, qualifications, disciplinary actions & public complaints |
profile | ~2 per licensee | + e-mail, specialty board certifications, hospital staff privileges, Medicaid participation, other-state licenses, practice address (physicians, PAs and ARNPs only) |
The price per licensee is identical at all three depths. Depth buys you fields and costs you time, never money.
roster reads the portal's own bulk export, so 13,853 Miami physicians came back in a single
request — verified 100% against the portal's authoritative count. Use it to size a job or to build
a license-number list, then re-run the interesting subset at license or profile depth.
How to run it
Verify a batch of licenses you already hold
{"licenseNumbers": ["ME58861", "RN9268431", "ME68270"],"detailLevel": "profile"}
One search request per number, all statuses. Measured 2026-08-12: 4 numbers in, 3 resolved, 1 bogus
number reported and not charged, 7 seconds. Verifying 500 numbers in one run costs exactly the
same as 500 single-number runs and takes a fraction of the wall time — but maxItems caps the
batch as well as a search, and it ships at 100, so raise it to at least the length of your list
("maxItems": 500) or the run stops at the cap and says so in the log.
Pull a profession statewide, cheaply
{ "profession": "1711", "licenseStatus": "ACT", "detailLevel": "roster", "maxItems": 70000 }
Every practicing APRN in Florida — 69,531 of them as of 2026-08-12 — in one request at roster depth.
Leave board on "Any board": a profession is unique across boards, so the board filter adds nothing.
maxItems has no wildcard: set it above the slice size you want, and the run stops at whichever
comes first.
Slice a metro at full depth
{ "board": "15", "profession": "1501", "county": "23", "licenseStatus": "ACT","detailLevel": "license", "maxItems": 2000 }
10,903 practicing Miami-Dade physicians match (measured 2026-08-12); this takes the first 2,000.
Renewal monitoring on a schedule
{ "profession": "1701", "county": "58", "licenseStatus": "ACT", "detailLevel": "license","maxItems": 5000 }
Then filter on daysUntilExpiry between 0 and 90 in your own pipeline, and put the run on an Apify
Schedule. daysUntilExpiry is computed at scrape time, so it is only as fresh as the run.
Facility licenses rather than people
{ "profession": "2205", "businessName": "CVS", "licenseStatus": "ACT", "detailLevel": "license" }
27,040 pharmacy-facility licenses exist, of which 11,036 are practicing; a businessName of CVS
narrows that to 780 (all measured 2026-08-12). Those rows carry a business name in name and no
person name.
Sample rows
License depth, with a discipline file — a real row from the default run
{"licenseNumber": "ME68270","name": "ADELBERG, JONATHAN MICHAEL","lastName": "ADELBERG","firstName": "JONATHAN MICHAEL","profession": "Medical Doctor","professionCode": "1501","board": "BOARD OF MEDICINE","boardCode": "15","licenseStatus": "Clear/Active","isPracticing": true,"licenseOriginalIssueDate": "1995-05-08","licenseExpirationDate": "2027-01-31","daysUntilExpiry": 171,"addressLine1": "2424 Frankford Avenue","addressLine2": "Unit A","city": "PANAMA CITY","state": "FL","zip": "32405","county": "BAY","addressWithheld": false,"controlledSubstancePrescriber": true,"authorizedToOrderCannabis": null,"qualifications": "Dispensing Practitioner","disciplineOnFile": true,"publicComplaint": true,"disciplinaryActions": [{ "type": "Discipline Case", "name": "ADELBERG, JONATHAN MICHAEL", "license": "68270","profession": "Medical Doctor", "city": "PANAMA CITY", "state": "FL","caseNumber": "201816816", "actionTaken": "Obligation(s) Satisfied","documentId": "Mzg5Mzk4NDQ=" },{ "type": "Public Complaint", "name": "ADELBERG, JONATHAN MICHAEL", "license": "68270","profession": "Medical Doctor", "city": "PANAMA CITY", "state": "FL","caseNumber": "201816816", "actionTaken": "AC Filed","documentId": "MzcxMzc3MzI=" }],"profileAvailable": true,"detailLevel": "license","licenseVerificationUrl": "https://mqa-internet.doh.state.fl.us/MQASearchServices/HealthCareProviders/LicenseVerification?LicInd=59151&ProCde=1501","scrapedAt": "2026-08-13T02:05:12.772Z"}
Profile depth — a real row from the batch verification run
{"licenseNumber": "ME58861","name": "PATRICIA LIPFORD ABBITT","lastName": null,"firstName": null,"profession": "Medical Doctor","professionCode": "1501","board": null,"boardCode": null,"licenseStatus": "Clear/Active","isPracticing": true,"licenseOriginalIssueDate": "1990-12-17","licenseExpirationDate": "2028-01-31","daysUntilExpiry": 536,"addressLine1": "DEPT OF RADIOLOGY - UF COM","addressLine2": "1600 SW ARCHER RD - RM G-304","city": "GAINESVILLE","state": "FL","zip": "32610","addressWithheld": false,"controlledSubstancePrescriber": false,"disciplineOnFile": false,"publicComplaint": false,"disciplinaryActions": null,"email": "abbitp@radiology.ufl.edu","medicaidParticipant": true,"specialtyCertifications": [{ "specialtyBoard": "AMERICAN BOARD OF RADIOLOGY","certification": "DR - DIAGNOSTIC RADIOLOGY", "dateCertified": null }],"hospitalPrivileges": [{ "institution": "SHANDS HOSPITAL AT THE UNIVERSITY OF FLO","city": "GAINESVILLE", "state": "FLORIDA" }],"otherStateLicenses": [{ "state": "VIRGINIA", "profession": null }],"practiceAddress": "PATRICIA LIPFORD ABBITT, DEPT OF RADIOLOGY - UF COM, 1600 SW ARCHER RD - RM G-304, GAINESVILLE, FL 32610","yearBeganPracticing": null,"detailLevel": "profile","licenseVerificationUrl": "https://mqa-internet.doh.state.fl.us/MQASearchServices/HealthCareProviders/LicenseVerification?LicInd=49786&ProCde=1501"}
Fields people misread:
lastName: nullon this row is the license-number path, not missing data —nameis complete.board: nullmeans you did not filter by board, not that the licensee has none.authorizedToOrderCannabis: nullmeans the portal rendered no such row;falsemeans it rendered one saying no. They are different facts.medicaidParticipant: nullmeans DOH published no Medicaid statement, not "does not participate".daysUntilExpiryis negative for an already-expired license.disciplinaryActions[].licenseis the bare number DOH prints in the enforcement table (68270), without theMEprefix thatlicenseNumbercarries.
Input
Fifteen fields in six groups, every one of them carrying a default, in the same order as the form. Two things worth separating: the form ships prefilled with Board of Medicine → Medical Doctor → Bay County → license depth → 100 rows, which is the run you get by pressing Start; the Default column below is what applies when a field is simply omitted from an API call.
| Field | Type | Default | What it does |
|---|---|---|---|
licenseNumbers | string list | [] | Batch primary-source verification. One request per number, all statuses. Unmatched numbers are logged, saved to NOT_FOUND_LICENSE_NUMBERS and never charged. |
licenseNumber | text | "" | Single lookup — identical to one entry above. The run-sync API path. |
board | select (36) | Any | Florida MQA board or council. Sizes in the table below. |
profession | select (237) | Any | Each option is labelled with the board that owns it. Unique across boards, so it can be used alone. |
professionCustom | text | "" | Escape hatch — a profession name or code not in the dropdown. Overrides it. |
county | select (67) | Any | Costs you ~45% of the population — see gotcha 2. |
city | text | "" | Exact match on DOH's spelling, e.g. GAINESVILLE. |
zipCode | text | "" | 5-digit ZIP. Tightest geographic filter, and the cheapest way to keep a deep run small. |
lastName | text | "" | Prefix match. Also the axis the Actor splits oversized slices on. |
firstName | text | "" | Prefix match. |
businessName | text | "" | Prefix match for facility licenses (pharmacies, labs, EMS providers). |
detailLevel | select | roster | roster · license · profile. Same price at every depth. The form is prefilled with license. |
licenseStatus | select | ACT | Practicing only, non-practicing only, or all. Ignored on license-number lookups, which always search all statuses. |
maxItems | integer | 100 | Row cap and your billing cap. 0 is not a wildcard — set a number. |
proxyConfiguration | proxy | off | Leave off. Measured ladder below. |
The 36 boards, with the size of each (measured 2026-08-12)
| Code | Board | Records |
|---|---|---|
| 17 | BOARD OF NURSING | 1,573,814 |
| 22 | BOARD OF PHARMACY | 272,596 |
| 15 | BOARD OF MEDICINE | 269,685 |
| 25 | BUREAU OF EMERGENCY MEDICAL SERVICES | 258,162 |
| 76 | RADIATION CONTROL | 179,419 |
| 14 | BOARD OF MASSAGE THERAPY | 152,118 |
| 52 | BOARD OF CSW/MFT/MHC | 122,492 |
| 7 | BOARD OF DENTISTRY | 105,285 |
| 66 | BOARD OF CLINICAL LABORATORY PERSONNEL | 77,360 |
| 55 | BOARD OF PHYSICAL THERAPY PRACTICE | 62,806 |
| 30 | SPEECH-LANGUAGE PATHOLOGY AND AUDIOLOGY | 50,979 |
| 57 | BOARD OF RESPIRATORY CARE | 44,975 |
| 96 | OUT-OF-STATE TELEHEALTH PROVIDERS | 43,552 |
| 56 | BOARD OF OCCUPATIONAL THERAPY PRACTICE | 38,928 |
| 5 | BOARD OF CHIROPRACTIC MEDICINE | 37,149 |
| 19 | BOARD OF OSTEOPATHIC MEDICINE | 35,258 |
| 26 | EMS PROVIDERS | 29,739 |
| 24 | PUBLIC SAFETY TELECOMMUNICATIONS | 22,688 |
| 20 | BOARD OF OPTICIANRY | 17,563 |
| 61 | DIETETICS AND NUTRITION PRACTICE COUNCIL | 15,682 |
| 27 | BOARD OF PSYCHOLOGY | 11,666 |
| 18 | BOARD OF OPTOMETRY | 10,538 |
| 65 | ELECTROLYSIS COUNCIL | 8,951 |
| 21 | BOARD OF PODIATRIC MEDICINE | 8,296 |
| 10 | BOARD OF ATHLETIC TRAINING | 7,859 |
| 8 | NURSING HOME ADMINISTRATORS | 5,706 |
| 36 | BOARD OF HEARING AID SPECIALISTS | 5,549 |
| 38 | BOARD OF ACUPUNCTURE | 4,750 |
| 31 | BOARD OF ORTHOTISTS AND PROSTHETISTS | 2,326 |
| 41 | BOARD OF SCHOOL PSYCHOLOGY | 2,025 |
| 60 | ADVISORY COUNCIL OF MEDICAL PHYSICIST | 1,981 |
| 53 | GENETIC COUNSELING | 982 |
| 32 | COUNCIL OF LICENSED MIDWIFERY | 524 |
| 62 | HEALTH CARE SERVICES POOLS | 279 |
| 16 | BOARD OF NATUROPATHIC MEDICINE | 56 |
| 54 | CERTIFIED SOCIAL WORKERS | 23 |
Total: 3,481,761.
The professions worth knowing the size of (measured 2026-08-12)
| Code | Profession | All statuses | Practicing |
|---|---|---|---|
| 1701 | Registered Nurse | 790,880 | 395,219 |
| 4401 | Certified Nursing Assistant | 484,858 | 152,572 |
| 1702 | Licensed Practical Nurse | 213,475 | 62,469 |
| 1501 | Medical Doctor | 174,575 | 91,039 |
| 2501 | Emergency Medical Technician | 161,484 | 50,538 |
| 2208 | Registered Pharmacy Technician | 137,615 | 59,709 |
| 1401 | Massage Therapist | 107,519 | 36,723 |
| 1711 | Advanced Practice Registered Nurse | 82,864 | 69,531 |
| 2502 | Paramedic | 65,416 | 39,928 |
| 2201 | Pharmacist | 60,144 | 37,204 |
| 5501 | Physical Therapist | 41,387 | 21,678 |
| 702 | Dental Hygienist | 32,905 | 19,225 |
| 701 | Dentist | 30,279 | 18,638 |
| 2205 | Pharmacy (facility) | 27,040 | 11,036 |
| 5601 | Occupational Therapist | 25,482 | 12,996 |
| 3001 | Speech-Language Pathologist | 24,868 | 13,924 |
| 1512 | Physician Assistant | 23,833 | 15,673 |
| 1901 | Osteopathic Physician | 22,892 | 13,122 |
| 501 | Chiropractic Physician | 14,964 | 7,583 |
| 2701 | Psychologist | 11,262 | 7,009 |
| 1801 | Optometrist | 6,627 | 4,247 |
| 2101 | Podiatric Physician | 4,418 | 1,853 |
The dropdown carries all 237. Note how far "all statuses" sits above "practicing": more than half of every registry in Florida is historical. The default keeps you on the practicing half.
Pricing
$0.003 per licensee returned — $3 per 1,000. Charged on the licensee-scraped event. No monthly
platform fee from this Actor.
The same rate applies at every depth: a roster row, a license row with the full disciplinary file,
and a profile row with e-mail and hospital privileges all cost $0.003. Depth costs the Actor
requests, not you money.
| Run | Licensees | Cost |
|---|---|---|
| The default first click (Bay County physicians) | 100 | $0.30 |
| Every practicing physician in Bay County | 460 | $1.38 |
| Every practicing physician in Gainesville | 2,326 | $6.98 |
| Every practicing physician in Miami-Dade | 10,903 | $32.71 |
| Every practicing physician in Florida | 91,039 | $273.12 |
| Every practicing APRN in Florida | 69,531 | $208.59 |
What you are not charged for:
- License numbers in a batch that match nothing. No row, no charge — and they are named in
NOT_FOUND_LICENSE_NUMBERSso you know which. - Duplicates. Rows are deduplicated on
licenseNumber+professionCodebefore anything is pushed, so the dataset and your bill never hold the same licensee twice. - The Actor's own retries, roster cross-checks, refinement splits, or the repair lookups it runs to reach 100% coverage. Those are requests, and requests are free to you.
- Rows above your cap.
maxItemsis a hard ceiling on both rows and spend.
Rows are charged as they are pushed (Actor.pushData(items, 'licensee-scraped')), so if you hit a
budget cap you get whole rows and a stop, never a half-billed dataset.
Honest limits
- No e-mail addresses outside physicians. Florida publishes a practitioner profile for MDs, DOs,
PAs and ARNPs only. Measured 88% e-mail fill on 200 practicing Gainesville physicians and 0% on
every other board — not because the scrape failed, but because the state does not publish it.
If you need contactable nurses, dentists or pharmacists, this is not the product; take the
name+city+licenseNumberfrom here and enrich elsewhere. - No phone numbers, for anyone. MQA publishes an address of record and, for physicians, an e-mail. There is no phone field on the portal, so there is none here, and nothing can produce one from this source.
- Address is a mailing address of record, not a practice location. It is frequently a hospital
department, a university mailroom, a billing service or a home.
practiceAddresson profile-depth physician rows is closer to a practice location, but it is self-reported. - Non-practicing licensees are mostly blank. 9% address fill, 8% ZIP, 65% expiry, measured on 117 rows. That is DOH withholding, not a scraping failure. It also means a run with License status = All statuses returns a great many thin rows, and you are billed for them.
- A county filter reaches 55.3% of the population. Detailed above. Not a bug, a property of the state's data.
authorizedToOrderCannabisis null on the overwhelming majority of rows — 94 of 100 on the Bay County run and 199 of 200 on the Gainesville run — because the portal renders that row only for the licensees it applies to. Do not read null as "not authorised".- Counts drift daily. DOH refreshes nightly, and two reads of the same slice hours apart on 2026-08-12 returned 174,569 and 174,575 physicians. Treat every count on this page as accurate to the day it was measured, not to the row.
rosterdepth cannot be filtered on anything the roster does not carry. It returns license number, name, profession, city and status; if you need to filter on expiry or discipline you must pay forlicensedepth first.- No login, no API key, no CAPTCHA solving, no browser automation. The Actor reads public pages and the portal's own CSV export. It does not attempt any authenticated area, and there is nothing behind a login that it works around.
How it works, and what was measured
The whole data path is public and unauthenticated:
| Step | Endpoint | Purpose |
|---|---|---|
| 1 | GET /HealthCareProviders | Session cookie, __RequestVerificationToken, and the live board / county / status dropdowns |
| 2 | POST /HealthCareProviders | Returns "Search Results Total: N" — the authoritative count, and binds the session to this result set |
| 3 | GET /ExportToCsvLVP?jsonModel={…} | Stateless bulk export — the whole result set as CSV in one request (174,569 rows / 13.7 MB in 31 s measured) |
| 4 | GET /IndexPaged?page=N | 20 rows per page, session-bound; yields the internal LicInd the detail pages are keyed by |
| 5 | GET /LicenseVerification?LicInd=&ProCde= | Address, issue and expiry dates, flags |
| 6 | GET /LoadEnforcementActionsTab?… | Discipline cases, emergency actions, public complaints |
| 7 | GET /Details?LicInd=&ProCde= | Practitioner profile (physicians only) |
The board, county and profession lists are re-read from the live form on every run, so a code
change on DOH's side cannot silently mis-map a search. The Actor keeps two separate cookie jars: the
search session drives /IndexPaged, and detail pages — which need neither cookie nor token — get
their own jar so nothing goes near the fragile paged walk.
Transport ladder — 18 identical calls per rung, measured through Apify
| Route | Success | Time |
|---|---|---|
| Direct, no proxy | 18/18 = 100% | 28 s |
| Apify automatic proxy | 16/18 = 88.9% | 298 s |
| Apify RESIDENTIAL, US, pinned session | 18/18 = 100% | 98 s |
The portal is public and unwalled. Proxying it only adds a failure mode — the two automatic-proxy
failures were proxy responded with 590 UPSTREAM502 — and 3.5× the latency. So the default is no
proxy at all, which is also the cheapest rung there is. Detail pages run at concurrency 5, measured
30/30 successful at that level.
The silent-truncation trap
ExportToCsvLVP has an undocumented size ceiling and blows it silently: HTTP 200, correct
text/csv content-type, valid header row, zero data rows. Measured:
| Slice | Authoritative count | Rows the export returned |
|---|---|---|
| Medical Doctor, statewide | 174,569 | 174,569 ✅ |
| All of Dentistry | 105,284 | 105,284 ✅ |
| All of Pharmacy | 272,593 | 0 ❌ |
| Registered Nurse | 790,875 | 0 ❌ |
| All of Nursing | 1,573,806 | 0 ❌ |
So the row count is never trusted on its own. Every run reads the authoritative "Search Results Total" first and reconciles against it. A short read is retried — a partial file is often just server load; one slice came back 7,622 of 12,340 and then 6 of 6 clean retries returned all 12,340 — and if the slice is genuinely oversized it is split by last-name prefix, with every leaf re-verified against its own authoritative total.
Last name is the only axis that actually partitions the data. A–Z sums to 174,561 of 174,569 physicians (100.00%) and 790,805 of 790,875 registered nurses (99.99%), where county sums to 55.3% and the state's own status buckets to 99.78% (ACT 91,034 + PREV 83,150 = 174,184 — four statuses, Clear/Inactive among them, sit in neither bucket).
Pagination: the obvious fix is the bug
The results grid offers /IndexSorted?fieldToSort=1 to order by license number, and the instinct is
to pin it so offset paging is stable. On this portal that is exactly backwards — the re-sorted result
set is a transient the server discards after about a minute, silently reverting to name order
mid-walk. Measured over one complete 38-page slice, 5 s between pages to imitate hydration latency,
checked against the CSV export of the same slice:
| fetched | unique | lost | |
|---|---|---|---|
| Sort pinned | 758 | 743 | 15 licensees |
| Default order (what this Actor uses) | 758 | 758 | 0 |
A fast walk hides it entirely — eight pages back-to-back produce zero duplicates either way — which is what makes it a trap.
Uniqueness and coverage
Rows are deduplicated on licenseNumber + professionCode before they are pushed, so a duplicate is
never delivered and never billed. Beyond that, license and profile runs do something most
scrapers do not: they reconcile the license numbers they hydrated against the authoritative CSV
roster for the same slice, and repair any straggler by direct license-number lookup.
Measured 2026-08-12 on contiguous page walks:
| Run | Expected | Emitted | Duplicates | Verified coverage |
|---|---|---|---|---|
| 100 practicing Bay County physicians, license depth | 100 | 100 | 0 | 100.0% |
| 200 practicing Gainesville physicians, profile depth | 200 | 200 | 0 | 100.0% |
That verified-coverage line is printed by every license and profile run whose slice was small
enough to cross-check against a complete CSV roster. A roster run stopped by maxItems prints the
cap it stopped at instead, and a license-number batch prints its own accounting — the resolved count
and the unmatched numbers by name. Across runs there is no cross-run dedupe — re-running the
same slice returns the same licensees. Use lastName prefixes or ZIP to partition a large job into
non-overlapping runs.
When a run fails
The Actor is built to fail loudly rather than hand you a green, empty dataset:
- Zero rows throws. If the portal reported matches and the Actor extracted none, the run errors with the reported total instead of finishing successfully on an empty dataset.
- A batch where nothing resolves throws, and says so: "None of the N license numbers matched a
Florida DOH/MQA licensee", with the reminder that DBPR numbers (
CGC…,CFC…,SL…) belong to a different agency. - A missing verification token throws rather than submitting a search that cannot work: "The page layout has changed — the Actor cannot submit a search without it."
- An unknown board, profession or county throws with the live list of valid values, read from the portal in that same run. An ambiguous partial name throws with the candidates it matched.
- A profession that does not belong to the selected board does not throw — the board is dropped with a warning, because the result set is provably identical either way.
- A short read warns loudly with the exact shortfall and tells you which filter to narrow.
- A slice that stays short after three retries and three levels of prefix refinement throws rather than shipping a partial directory as if it were complete.
- Unmatched license numbers are never silent: named in the log and written to
NOT_FOUND_LICENSE_NUMBERSin the key-value store.
Who buys this
- Provider credentialing and primary-source-verification platforms — Verifiable, Medallion,
Certify, Silversheet and every hospital medical-staff office.
licenseStatus, both dates,disciplinaryActionsandlicenseVerificationUrlare the PSV packet, and the URL is the citation the auditor asks for. - Payors and provider-network integrity teams —
licenseStatusplusdisciplinaryActionsplusmedicaidParticipantis a monthly network sanction sweep. 6% of the practicing physicians in the measured run carried a discipline flag. - Healthcare staffing, travel nursing and locum agencies — 395,219 practicing registered nurses and 69,531 practicing APRNs, sliceable by county and city, with expiry dates for renewal timing.
- Medical device and pharma field teams — the 29% of measured physicians flagged as controlled-substance prescribers, and the 57% with hospital staff privileges naming the institution, are a targeting layer Google Maps cannot give you.
- Malpractice and professional-liability underwriters — years since original issue, discipline history with case numbers, and other-state licensure on 50% of profile rows.
- Healthcare M&A and market researchers — practitioner density by county and profession, from a registry of 3,481,761 records with a measured population per board.
- Legal and investigative teams — the case numbers and
documentIdkeys lead to the signed order PDFs on the state's own document endpoint.
Which of our Florida / healthcare Actors do you need?
| Actor | What it is | Why you would use it instead |
|---|---|---|
| This one | Florida DOH / MQA — health care practitioners | Doctors, nurses, dentists, pharmacists, therapists. Discipline file. Primary source. |
| Florida Contractor License Scraper — DBPR | Florida DBPR — the other Florida licensing agency | Contractors, real estate, cosmetology, CPAs. A CGC… or SL… number belongs there, not here. |
| NPI Registry Scraper | The federal NPPES/NPI registry, all 50 states | You need providers nationwide, or you need an NPI. MQA does not publish NPIs. |
| Healthgrades Scraper | Consumer directory — doctors and dentists | You want ratings, reviews and phone numbers. Not a primary source, but it has the phone this one does not. |
| Wellness.com Provider Scraper | Consumer directory — practices and providers | Practice-level contact data and specialties. |
The short version: Healthgrades is where you go for a phone number; this is where you go for the license status, the expiry date and the disciplinary file.
Integrations
The dataset exports as JSON, CSV, Excel, XML and JSONL, and the Apify API serves it directly:
- Google Sheets —
IMPORTDATAagainst the dataset's CSV endpoint for a live credentialing sheet. - Make / Zapier / n8n — trigger on run finished, iterate items, push rows whose
daysUntilExpiry < 90into a renewal queue. - Postgres / BigQuery / Snowflake — load
licenseNumberas the natural key;scrapedAtgives you the as-of timestamp every compliance table needs. - Salesforce / HubSpot — match on
licenseNumber, writelicenseStatusandlicenseExpirationDateback onto the provider record. - Slack / Teams alerts — webhook on any row where
disciplineOnFileflipped totruesince your last pull. - Scheduling — put a county or profession slice on an Apify Schedule and diff against your own store; the Actor has no monitor mode of its own.
This Actor versus the alternatives
| This Actor | Manual portal lookup | Your own scraper | A paid credentialing API | |
|---|---|---|---|---|
| Setup | Minutes | None | Days, plus the seven traps above | Contract + onboarding |
| Bulk extraction | Yes, whole boards | No, one at a time | Yes, if you solve truncation and pagination | Usually per-lookup only |
| Disciplinary file | Structured, with document IDs | Manual tab-clicking | Extra work | Sometimes |
| Cost per 1,000 | $3.00 | Staff time | Dev + proxy + maintenance | Typically per-seat or per-verification |
| Primary source | Yes — DOH itself | Yes | Yes | Often an aggregated copy |
FAQ
Does this need an account, a login or an API key? No. Every endpoint it reads is public and unauthenticated. There is no login and no CAPTCHA solving.
Does it need a proxy? No, and it ships with the proxy off. Measured 18/18 direct versus 16/18 through Apify's automatic proxy, at a third of the latency. Turn one on only if your own network policy needs a fixed egress IP.
Can I verify a list of license numbers I already have?
Yes — that is what licenseNumbers is for. One search request per number, all statuses searched, and
numbers that match nothing are listed in NOT_FOUND_LICENSE_NUMBERS and never charged.
Is this the primary source, or a copy?
It reads the Florida Department of Health's own MQA verification portal, which is the state's
designated primary source. Every row carries the exact licenseVerificationUrl it came from.
Can I get the whole registry in one run? Not in one run, no. The whole index is 3,481,761 records across 36 boards, and the portal's CSV export truncates silently on big slices: the largest that came back complete was 174,569 rows and the smallest that came back empty was 272,593, so the ceiling sits somewhere between the two. The Actor splits oversized slices by last-name prefix automatically, but a sane job is one board or one profession at a time.
Why is the e-mail field empty on my nurses? Because Florida does not publish a practitioner profile for nurses. It publishes one for physicians, PAs and ARNPs — measured 88% e-mail fill there, 0% everywhere else.
Why do so many rows have no address? You are looking at non-practicing licenses. Florida withholds the address of record on Null-and-Void, Retired, Revoked and Deceased licenses: 9% address fill on those versus 100% on practicing ones.
Do I get charged for rows my filters removed, or for the Actor's retries?
No. You are billed per licensee actually delivered, on the licensee-scraped event. Retries, roster
cross-checks, refinement splits and repair lookups are requests, and requests are free to you.
Two runs — will I get duplicates?
Within a run, never: rows are deduplicated on licenseNumber + professionCode before they are
pushed, so a duplicate is never delivered or billed. Across runs there is no memory — re-running the
same slice returns the same licensees. Partition with lastName prefixes or ZIP.
Will a run ever succeed with zero rows? No. If the portal reported matches and nothing was extracted, the run throws with the reported total rather than finishing green on an empty dataset. A batch where no number resolves throws too.
How fresh is the data? It is read live from the portal at run time. DOH refreshes its public database nightly; two reads of the same slice hours apart on 2026-08-12 differed by six rows.
What is documentId for?
It is the portal's own document key for a disciplinary order. POST it as id to
/MQASearchServices/Document to retrieve the signed PDF.
Does it cover Florida contractors, realtors or cosmetologists? No — those are licensed by DBPR, a different agency. Use our Florida Contractor License Scraper (DBPR).
Something looks wrong — how do I debug it? A search run logs its criteria, the portal's authoritative match count, per-page progress and — when the slice was small enough to cross-check against a full roster — the verified coverage percentage. A license-number batch logs the resolved count and every unmatched number by name instead. Every run ends with a per-field fill line. Compare those against the numbers on this page; if they diverge, open an issue on the Issues tab with the run ID.
Legal and fair use
This Actor reads public records published by the Florida Department of Health, Division of Medical Quality Assurance, under Florida's public-records law. It reads only pages the portal serves to any anonymous visitor: the search form, the search results, the portal's own CSV export, the license verification page, the enforcement-actions tab and the practitioner profile. It does not log in, it holds no credentials, it solves no CAPTCHAs, and it collects nothing behind any authentication.
Rows describe identifiable people and include names, mailing addresses, license history and, for
physicians, e-mail addresses and disciplinary records. You are responsible for complying with the
Florida Department of Health's terms and with how you use the data, including CAN-SPAM and TCPA if
you contact anyone, GDPR/UK GDPR if any data subject is in scope, and your own regulator's rules on
provider outreach. Disciplinary records are public record; using them in a decision about an
individual's credit, insurance, employment or housing may bring you under the FCRA, and this output
is not a consumer report. License status can change the moment after a row is scraped — every row
carries licenseVerificationUrl and scrapedAt so you can re-verify at the source before acting.
This Actor is an independent tool. It is not affiliated with, endorsed by, or operated by the Florida Department of Health or the State of Florida.
Changelog
| Version | Date | Change |
|---|---|---|
| 0.2.10 | 2026-08-20 | Cost-limit handling. The run now reads your "Maximum cost per run" up front and lowers its own row cap to what that budget pays for, so no licensee is ever scraped that could not be delivered — and it reads the charge result of every push, so it stops the moment the platform reports the cap reached instead of scraping on into a wall you are paying compute for. Rows returned and rows charged are the same number in every case; the run says which limit stopped it (cost or time), never both. Proof: a run capped at $0.05 returned 16 rows and charged 16 ($0.048), SUCCEEDED in 9.4 s with "Stopped at this run's maximum total charge with 16 licensee(s) delivered". Memory right-sized 4096 MB -> 512 MB. Compute bills linearly with memory, so this cuts the compute cost of every run by 8x at no change to the data. Peak memory measured across the heaviest runs (full 174,569-row statewide CSV; three 120-second unbounded runs) was 200.0 MiB — 2.6x headroom. |
| 0.2.6 | 2026-08-19 | Address fix. DOH publishes the address-withheld notice in two wordings and only one was detected, so rows carrying "This practitioner does not have an address of record on file with the department…" shipped that sentence as addressLine1 with addressWithheld: false (and "NOT PRACTICING" as addressLine2). Both wordings are now detected. Measured on the same 100-row Bay County slice: addressLine1 100% -> 98%, addressLine2 34% -> 32%, addressWithheld 0 true -> 2 true, notice-in-address rows 2 -> 0. yearBeganPracticing fix. Its selector expected a bare <dd>; the profile page uses <dd class="col-md-9">, so it never matched — 0% on every profile run ever shipped. Now 63% (19/30 Gainesville physicians). The key is also declared on the record template, so every row carries the same field set. |
| 0.2 | 2026-08-12 | Batch licenseNumbers verification with unmatched-number reporting. Board, profession and county became dropdowns read from the live portal (36 / 237 / 67). Default depth is now license, default cap 100. lastName/firstName are null instead of wrong on license-number lookups. Field-fill, board-size and profession-size tables re-measured. |
| 0.1 | 2026-08-12 | First release. Verified against the live portal on 2026-08-12. |
Keywords
Florida medical license lookup · Florida DOH license verification · MQA license search · Florida nurse license lookup · Florida RN license verification · Florida physician license lookup · Florida medical license scraper · primary source verification Florida · Florida provider credentialing data · Florida license expiration data · Florida disciplinary actions physicians · Florida board of medicine data · Florida board of nursing data · Florida board of dentistry · Florida board of pharmacy · Florida APRN list · Florida CNA license lookup · Florida pharmacist license verification · Florida dentist license lookup · Florida physical therapist license · Florida massage therapist license · Florida paramedic EMT license · Florida psychologist license · Florida chiropractor license · Florida optometrist license · Florida podiatrist license · Florida speech-language pathologist · Florida occupational therapist license · Florida healthcare provider list · Florida healthcare leads · Florida medical staffing data · locum tenens Florida · Miami-Dade physicians list · Broward physicians · Orlando nurses list · Tampa healthcare providers · Jacksonville physicians · Gainesville physicians · healthcare credentialing API · license verification API · provider network integrity · Medicaid participation Florida · controlled substance prescriber Florida · hospital privileges data
Support
Found a missing field, want a new filter, or need a board we do not surface well? Open an issue on the Issues tab with your run ID and we will look at it.
If this Actor saved you time, a rating on the store page helps other people find it.