# AHPRA Health Practitioner Register Scraper: Bulk Check & Watch (`getascraper/ahpra-practitioner-register-monitor`) Actor

Bulk-check Australian health practitioner registrations on AHPRA's public register in one run. Get status, conditions, undertakings, reprimands, and expiry, plus a monitor mode reporting only genuine roster changes since last check. $0.005/record plus a small session fee.

- **URL**: https://apify.com/getascraper/ahpra-practitioner-register-monitor.md
- **Developed by:** [GetAScraper](https://apify.com/getascraper) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.75 / 1,000 practitioner records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 🩺 AHPRA Health Practitioner Register Scraper: Bulk Check & Watch

<table width="100%">
<tr>
<td style="padding:24px 28px;background:#EAF1FA;border:1px solid #C3D2E8;border-top:4px solid #14487A;border-radius:12px">
<span style="font-size:23px;font-weight:800;color:#1C1917;line-height:1.3">Know the moment a practitioner's registration changes, not the next time someone asks</span><br>
<span style="font-size:15px;color:#57534E;line-height:1.6">Bulk-check and monitor Australian health practitioner registrations from Ahpra's public register. Get registration status, conditions, undertakings, reprimands, and expiry for a whole roster in one run, with a recurring mode that only reports what actually changed since the last check.</span>
</td>
</tr>
</table>

<table width="100%">
<tr>
<td style="padding:14px 12px;width:25%;background:#FFFFFF;border:1px solid #C3D2E8;border-radius:10px 0 0 10px;vertical-align:top">
<span style="font-size:15px;font-weight:800;color:#14487A">📋 Whole roster, one run</span><br>
<span style="font-size:12px;color:#57534E">Check a list of names or registration numbers together instead of one Actor run per practitioner.</span>
</td>
<td style="padding:14px 12px;width:25%;background:#FFFFFF;border:1px solid #C3D2E8;border-left:none;vertical-align:top">
<span style="font-size:15px;font-weight:800;color:#14487A">🔔 Only real changes, on schedule</span><br>
<span style="font-size:12px;color:#57534E">Recurring monitor mode reports new or changed practitioners since the last check, not a full re-dump every time.</span>
</td>
<td style="padding:14px 12px;width:25%;background:#FFFFFF;border:1px solid #C3D2E8;border-left:none;vertical-align:top">
<span style="font-size:15px;font-weight:800;color:#14487A">⚠️ Status, conditions & expiry</span><br>
<span style="font-size:12px;color:#57534E">The full public record: registration status, conditions, undertakings, reprimands, endorsements, and expiry date.</span>
</td>
<td style="padding:14px 12px;width:25%;background:#FFFFFF;border:1px solid #C3D2E8;border-left:none;border-radius:0 10px 10px 0;vertical-align:top">
<span style="font-size:15px;font-weight:800;color:#14487A">🔓 No login required</span><br>
<span style="font-size:12px;color:#57534E">Reads Ahpra's own public register, the same anonymous lookup anyone can use in a browser.</span>
</td>
</tr>
</table>

Point this Actor at names or registration numbers on the [Ahpra Register of practitioners](https://www.ahpra.gov.au/Registration/Registers-of-Practitioners.aspx) and pull structured registration data, from a single check to a scheduled watch over a whole roster.

### 🔍 What does this Actor do?

Ahpra (the Australian Health Practitioner Regulation Agency) keeps the public register of every doctor, nurse, dentist, psychologist, and other registered health practitioner allowed to practise in Australia, over a million people. A registration can change after a practitioner is already placed, credentialed, or insured: a status can lapse or be suspended, a new condition or notation can appear, a registration can simply expire and not renew.

This Actor checks that register for you, in three ways. Look up one practitioner. Check a whole roster in one run. Or turn on Recurring monitor mode and let it re-check a saved roster on a schedule, only reporting practitioners that are new to the roster or whose status genuinely changed since the last check.

### 💡 Who uses this?

- **I run a healthcare staffing agency.** I placed someone six months ago. I need to know the day their registration status changes, not the day a client asks me about it.
- **I handle credentialing for a hospital or clinic.** Re-checking a roster of dozens of practitioners by hand, one search at a time, doesn't scale. I need to check the whole list in one pass.
- **I work in insurance or compliance.** A suspended or newly restricted practitioner is a liability I need to catch immediately, not discover during an audit.
- **I am building a healthcare workforce or verification tool.** I need structured, current registration data I can pull into my own system instead of screen-scraping search results by hand.

### 🚀 How to use

<table width="100%">
<tr>
<td style="padding:16px 14px;width:33%;background:#EAF1FA;border:1px solid #C3D2E8;border-radius:10px 0 0 10px;vertical-align:top">
<span style="font-size:12px;font-weight:800;color:#14487A;letter-spacing:1px">STEP 1</span><br>
<span style="font-size:14px;font-weight:700;color:#1C1917">Pick a mode</span><br>
<span style="font-size:12px;color:#57534E">Single lookup, a bulk roster list, or Recurring monitor for scheduled re-checks.</span>
</td>
<td style="padding:16px 14px;width:33%;background:#EAF1FA;border:1px solid #C3D2E8;border-left:none;vertical-align:top">
<span style="font-size:12px;font-weight:800;color:#14487A;letter-spacing:1px">STEP 2</span><br>
<span style="font-size:14px;font-weight:700;color:#1C1917">Get the full public record</span><br>
<span style="font-size:12px;color:#57534E">Status, conditions, undertakings, reprimands, endorsements, notations, and expiry per practitioner.</span>
</td>
<td style="padding:16px 14px;width:33%;background:#EAF1FA;border:1px solid #C3D2E8;border-left:none;border-radius:0 10px 10px 0;vertical-align:top">
<span style="font-size:12px;font-weight:800;color:#14487A;letter-spacing:1px">STEP 3</span><br>
<span style="font-size:14px;font-weight:700;color:#1C1917">Schedule it and watch for change</span><br>
<span style="font-size:12px;color:#57534E">Name a monitor state and run it on a schedule. Later runs report only what's new or changed.</span>
</td>
</tr>
</table>

### 📥 Input

| Field | Type | Required | Description |
|---|---|---|---|
| `mode` | enum | No | `lookup` for one practitioner, `bulk` for a roster list, or `monitor` for scheduled re-verification that only reports genuine changes. Default: `lookup`. |
| `query` | string | No | Used in Single lookup mode. A practitioner's name or Ahpra registration number. |
| `practitioners` | array of strings | No | Used in Bulk and Recurring monitor mode. One name or registration number per line, the roster to check. |
| `fetchDetails` | boolean | No | Also fetch each matched practitioner's full public record (status, conditions, undertakings, reprimands, endorsements, notations, expiry, qualifications, location), not just the name and profession summary. Default: `true`. |
| `maxRosterSize` | integer | No | Maximum roster entries processed per run in Bulk or Recurring monitor mode. Default: 10. |
| `maxResultsPerQuery` | integer | No | Maximum matched practitioners kept per individual name or number search, since a common surname can match thousands of real entries. Default: 5. |
| `stateName` | string | No | Used only in Recurring monitor mode. Names the saved history this run compares against. Use a different name per distinct roster so separate schedules never mix up their history. Default: `default`. |
| `onlyNewOrChanged` | boolean | No | Used only in Recurring monitor mode. When on, only new or genuinely changed practitioners are output. When off, every roster entry is output every run with a change label attached. Default: `true`. |
| `proxyConfiguration` | proxy | No | Keep the datacenter default; it reaches Ahpra's register without issue. |

### 📊 Data table

| Field | Type | Description |
|---|---|---|
| `registrationNumber` | string | Ahpra registration number, for example `NMW0002025776`. |
| `name` | string | Practitioner's registered name. |
| `alternativeName` | string | absent | Alternative name shown on the register, when published. |
| `profession` | string | absent | Registered profession, for example Nurse or Medical Practitioner. |
| `division` | string | absent | Division within the profession, for example Registered nurse (Division 1). |
| `registrationType` | string | absent | General, Provisional, Specialist, or Non Practising. |
| `speciality` | string | absent | Specialty field, when the practitioner holds one. |
| `registrations` | array | absent | Every division/registration-type/speciality combination on the register, for practitioners registered more than one way. |
| `locationText`, `suburb`, `state`, `postcode` | string | absent | Location shown in the search result. |
| `detailFetched` | boolean | Whether the full public record below was fetched for this row. |
| `registrationStatus` | string | absent | Current registration status, for example Registered. |
| `conditions` | string | absent | Public conditions on the registration, when any are recorded. |
| `undertakings` | string | absent | Public undertakings, when any are recorded. |
| `reprimands` | string | absent | Public reprimands, when any are recorded. |
| `dateOfFirstRegistration` | string | absent | The date this practitioner first registered in this profession. |
| `registrationExpiryDate` | string | absent | Current registration expiry date. |
| `divisionDetails` | array | absent | Per-division expiry, conditions, endorsements, notations, and registration requirements. |
| `sex` | string | absent | As published on the register. |
| `languages` | array of string | absent | Languages spoken in addition to English. |
| `qualifications` | array of string | absent | Qualifications as published on the register. |
| `principalPlaceSuburb`, `principalPlaceState`, `principalPlacePostcode`, `principalPlaceCountry` | string | absent | Principal place of practice. |
| `matchedQuery` | string | The roster entry (name or number) that produced this row. |
| `sourceUrl` | string | The Ahpra register page this data comes from. |
| `scrapedAt` | string | When this row was checked. |
| `changeType` | string | absent | Only present in Recurring monitor mode: `NEW`, `UPDATED`, or `UNCHANGED`. |

You can download the dataset in JSON, HTML, CSV, or Excel from the Output tab of any run.

### 📤 Sample output

```json
{
    "registrationNumber": "NMW0002025776",
    "name": "Mr Kabir Shrestha",
    "profession": "Nurse",
    "division": "Registered nurse (Division 1)",
    "registrationType": "General",
    "suburb": "Prestons",
    "state": "NSW",
    "postcode": "2170",
    "detailFetched": true,
    "registrationStatus": "Registered",
    "dateOfFirstRegistration": "01/03/2016",
    "registrationExpiryDate": "31/05/2027",
    "sex": "Male",
    "languages": ["Hindi", "Nepali"],
    "qualifications": ["Bachelor of Nursing, Australian Catholic University, Australia, 2015"],
    "principalPlaceSuburb": "PRESTONS",
    "principalPlaceState": "NSW",
    "matchedQuery": "Shrestha",
    "sourceUrl": "https://www.ahpra.gov.au/Registration/Registers-of-Practitioners.aspx",
    "scrapedAt": "2026-09-18T18:20:00.000Z"
}
```

### 💰 Pricing

Pricing is pay per result. You are charged only for practitioner records successfully written to your dataset. Empty runs cost nothing. There are no monthly subscriptions or minimum commitments.

Free plan runs are limited in items per run, runs per day, and a short wait between runs. These limits do not apply to paid plans.

### ⭐ Enjoying AHPRA Practitioner Register Monitor?

<table width="100%" style="display:table;width:100%">
<tr>
<td style="padding:20px 24px 14px;background:#EAF1FA;border:1px solid #C3D2E8;border-left:5px solid #14487A;border-radius:10px 10px 0 0">
<span style="font-size:20px;letter-spacing:4px">⭐ ⭐ ⭐ ⭐ ⭐</span><br>
<span style="font-size:17px;font-weight:800;color:#1C1917">One run just told you exactly what changed on your roster since last time.</span><br>
<span style="font-size:14px;color:#57534E">A 5-star rating takes 10 seconds and helps other agencies and credentialing teams find this Actor. Your feedback also tells us what to build next.</span>
</td>
</tr>
<tr>
<td style="padding:0;background:#14487A;border:1px solid #C3D2E8;border-top:none;border-radius:0 0 10px 10px;text-align:center">
<a href="https://apify.com/getascraper/ahpra-practitioner-register-monitor/reviews" style="display:block;padding:13px 16px;color:#FFFFFF;text-decoration:none;font-weight:800;font-size:15px;letter-spacing:0.3px">★&nbsp;&nbsp;Rate this Actor on Apify</a>
</td>
</tr>
</table>

### ✨ Tips

- **Search by registration number when you have it.** A registration number matches exactly one person; a common surname can match thousands of real Ahpra entries.
- **Give every monitored roster its own state name.** Use a different `stateName` per client or roster so scheduled runs never mix up their change history.
- **Raise `maxResultsPerQuery` only for a name you expect to be rare.** Otherwise a broad surname search can pull in matches that were never the practitioner you meant.
- **Turn `onlyNewOrChanged` off for a full audit snapshot.** Every roster entry is output on every run with its change label attached, useful for a point-in-time compliance record.
- **Schedule Recurring monitor mode on the Apify Scheduler.** Each run after the first reports only what actually moved.

### ❓ FAQ

##### Does this Actor need a login or an Ahpra account?

No. It reads Ahpra's public register, the same anonymous search and detail pages anyone can view in a browser without signing in.

##### How does Recurring monitor mode know what changed?

Give it a `stateName` and run it on a schedule with the same roster. Each run compares the current registration status, conditions, undertakings, reprimands, notations, and expiry against what was saved last time, and labels every practitioner `NEW`, `UPDATED`, or `UNCHANGED`.

##### What counts as a "change"?

A genuine difference in registration status, conditions, undertakings, reprimands, endorsements, notations, or expiry date. Re-checking the same, unchanged record never counts as a change.

##### How fresh is the data?

Every run reads Ahpra's register live at the moment it runs. Results reflect what the public register shows right then.

##### Is checking the Ahpra register legal?

This Actor reads publicly available register pages, the same pages Ahpra makes available to anyone without a login. It is an independent tool, not affiliated with or endorsed by Ahpra or any National Board. You are responsible for complying with Ahpra's terms of use and applicable law. For questions or custom fields, contact the author at <devanshtiwari365@gmail.com>.

### 🔗 Other actors

- [PERM Green Card Sponsor Monitor: U.S. Labor Certifications](https://apify.com/getascraper/perm-sponsor-monitor) ↗ - tracks U.S. employer sponsorship filings for change, the same recurring-monitor shape applied to a different compliance register.
- [H-1B LCA Sponsor Monitor: salaries and employers](https://apify.com/getascraper/h1b-lca-sponsor-monitor) ↗ - monitors U.S. visa sponsorship filings for salary and employer changes.
- [EPA ECHO Violation Monitor: Facility Changes](https://apify.com/getascraper/epa-echo-violation-monitor) ↗ - watches a public regulatory register for facility compliance changes.
- [Multi-state contractor license verifier](https://apify.com/getascraper/multistate-contractor-license-verifier) ↗ - bulk license-status verification across U.S. state contractor boards.
- [US licensed contractor directory](https://apify.com/getascraper/us-licensed-contractor-directory) ↗ - structured contractor licensing data pulled from public U.S. state registers.

# Changelog

This Actor's version history is a separate document: https://apify.com/getascraper/ahpra-practitioner-register-monitor/changelog.md

# Actor input Schema

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

A staffing agency, credentialing vendor, or insurer rarely just looks a practitioner up once: the real job is keeping a whole roster verified as registrations change over time. Single lookup covers the one-off case; Bulk roster check verifies a whole list in one run; Recurring monitor is built for scheduled re-verification, only reporting practitioners that are new or actually changed since the last run.

## `query` (type: `string`):

Used in Single lookup mode. Enter a practitioner's full name (for example "Jane Smith") or their AHPRA registration number (for example "MED0002057420"). A registration number is more precise: a common surname can match thousands of real register entries.

## `practitioners` (type: `array`):

Used in Bulk roster check and Recurring monitor mode. One practitioner per line, by name or by AHPRA registration number. This is the list a staffing agency or credentialing vendor is responsible for keeping current, checked together in one run instead of one Actor run per practitioner.

## `fetchDetails` (type: `boolean`):

Also open each matched practitioner's public Registration Details page for registration status, conditions, undertakings, reprimands, endorsements, notations, expiry date, qualifications, and principal place of practice, not just the name/profession summary from the search list. This is the field set that actually matters for ongoing liability (a suspension or a new condition), so it is on by default, bounded by the roster and per-query result limits below rather than switched off.

## `maxRosterSize` (type: `integer`):

Caps how many names or registration numbers from the roster (Bulk/Recurring monitor mode) are actually processed in one run. Keep this modest for scheduled monitor runs; raise it for a one-time full-roster sweep.

## `maxResultsPerQuery` (type: `integer`):

Caps how many matched practitioners are kept for a single name or number search. A precise registration number normally matches exactly one person; a common surname can match thousands of real AHPRA entries, so this protects against one imprecise roster line silently blowing out the whole run's output and runtime.

## `stateName` (type: `string`):

Used only in Recurring monitor mode. Names the saved state this run compares against to detect what changed since the last check of this exact roster. Use a different name per distinct roster or client so separate monitoring schedules never overwrite each other's history.

## `onlyNewOrChanged` (type: `boolean`):

Used only in Recurring monitor mode. When on, a scheduled run only pushes practitioners that are new to the roster or whose status, conditions, undertakings, reprimands, notations, or expiry genuinely changed since the last run under this state name, so downstream systems only see real events. When off, every roster entry is pushed on every run, each tagged with a changeType field, for buyers who want the full snapshot every time.

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

AHPRA's register is gated by a JS bot-defense challenge (Cloudflare plus F5 Distributed Cloud Bot Defense). Sustained testing against this target escalated to a hard block on both datacenter and residential proxy, so default to Australia-pinned residential: this platform's own comparable case (career-cross-scraper, also Cloudflare-class) found the defense weights geographic plausibility heavily, and an AU-market register seeing AU-origin traffic is the more defensible default. Datacenter remains selectable if you prefer.

## Actor input object example

```json
{
  "mode": "lookup",
  "query": "Smith",
  "practitioners": [],
  "fetchDetails": true,
  "maxRosterSize": 10,
  "maxResultsPerQuery": 5,
  "stateName": "default",
  "onlyNewOrChanged": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AU"
  }
}
```

# Actor output Schema

## `practitioners` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "lookup",
    "query": "Smith",
    "practitioners": [],
    "fetchDetails": true,
    "maxRosterSize": 10,
    "maxResultsPerQuery": 5,
    "stateName": "default",
    "onlyNewOrChanged": true,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "AU"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("getascraper/ahpra-practitioner-register-monitor").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": "lookup",
    "query": "Smith",
    "practitioners": [],
    "fetchDetails": True,
    "maxRosterSize": 10,
    "maxResultsPerQuery": 5,
    "stateName": "default",
    "onlyNewOrChanged": True,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "AU",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("getascraper/ahpra-practitioner-register-monitor").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": "lookup",
  "query": "Smith",
  "practitioners": [],
  "fetchDetails": true,
  "maxRosterSize": 10,
  "maxResultsPerQuery": 5,
  "stateName": "default",
  "onlyNewOrChanged": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "AU"
  }
}' |
apify call getascraper/ahpra-practitioner-register-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,getascraper/ahpra-practitioner-register-monitor"
        }
    }
}
```

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/Oqaqe6ZZKwmon0w6c/builds/0itxrmgqMB9iKtJx9/openapi.json
