# UK Pharmacist Register Scraper (`crawlerbros/uk-pharmacist-register-scraper`) Actor

Search the General Pharmaceutical Council (GPhC) public register for pharmacists, pharmacy technicians, pharmacies, and training sites in Great Britain. Get registration numbers, status, annotations, fitness-to-practise flags, addresses, and inspection info.

- **URL**: https://apify.com/crawlerbros/uk-pharmacist-register-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Lead generation, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## UK Pharmacist Register Scraper

Search the **General Pharmaceutical Council (GPhC)** public register — the official regulator for pharmacists, pharmacy technicians, pharmacies, and training sites in Great Britain (England, Scotland, and Wales). Verify a professional's registration status, look up a pharmacy's inspection history, or check whether a training site is currently approved. No login, no API key, no proxy required.

### What this actor does

- **Four registers:** pharmacists, pharmacy technicians, pharmacies (premises), and training sites
- **Two lookup modes:** search by name (or business name) and postcode/town, or look up directly by GPhC registration number
- **Fuzzy name matching:** enable the register's own phonetic "I'm not sure of the spelling" match to catch misspellings
- **Prescriber annotation filter:** narrow pharmacist searches to Independent Prescribers or Supplementary Prescribers
- **Training sector filter:** narrow training-site searches to a specific sector (Community, Hospital, Prison, Academic, Industrial, Internet, or a GP training programme) — combine with a `*` premises name to browse an entire sector
- **Full detail enrichment:** optionally fetches each result's individual registration page for registration-expiry dates, town, superintendent info, fitness-to-practise flags, and pharmacy inspection/enforcement history
- **Empty fields are omitted** — every record only contains data the register actually published

### Output fields

#### Pharmacists & pharmacy technicians

| Field | Description |
|---|---|
| `registrationNumber` | GPhC registration number |
| `firstNames`, `lastName`, `fullName` | Registrant name |
| `status` | e.g. `Registered` |
| `registrationExpiryDate` | Current registration expiry (dd/mm/yyyy) |
| `town` | Town associated with the registration |
| `annotations` | Prescriber annotations held (e.g. `Independent Prescriber`) |
| `hasAnnotations` | Boolean — whether any annotation is held |
| `hasFitnessToPractiseInfo` | Boolean — whether fitness-to-practise history exists |
| `superintendentFor` | Organisation name, if the pharmacist is a named superintendent |
| `registerType` | `pharmacist` or `pharmacyTechnician` |
| `sourceUrl` | Canonical registration page |

#### Pharmacies & training sites

| Field | Description |
|---|---|
| `registrationNumber` | GPhC registration number |
| `pharmacyName` / `trainingSiteName` | Business/premises name |
| `ownerName` | Registered owner |
| `address`, `postcode` | Full address and extracted UK postcode |
| `status` | e.g. `Registered` |
| `sector` | Training-site sector (e.g. `Community`) |
| `approvedUntil` | Training-site approval expiry date |
| `inspectionReportPublished`, `inspectionReportUrl` | Whether a pharmacy inspection report exists, and its link |
| `subjectToNoticesOrConditions` | Boolean |
| `hasEnforcementHistory` | Boolean |
| `registerType` | `pharmacy` or `trainingSite` |
| `sourceUrl` | Canonical registration page |

Every record also includes `recordType` and `scrapedAt` (UTC timestamp).

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | select | `byName` | `byName` or `byRegistrationNumber` |
| `registerType` | select | `pharmacist` | `pharmacist` / `pharmacyTechnician` / `pharmacy` / `trainingSite` |
| `firstName` | string | – | Given name (pharmacist/pharmacyTechnician, mode=byName) |
| `lastName` | string | – | Surname (pharmacist/pharmacyTechnician, mode=byName) |
| `premisesName` | string | – | Business name (pharmacy/trainingSite, mode=byName) |
| `townOrPostcode` | string | – | Narrow a pharmacy/training-site search (mode=byName) |
| `fuzzyMatch` | boolean | `false` | Phonetic "not sure of the spelling" match |
| `annotationFilter` | select | (none) | `INDPRESC` / `SUPPRESC` (pharmacist, mode=byName) |
| `sectorFilter` | select | (none) | Training sector, e.g. Community / Hospital / Prison / Academic (trainingSite, mode=byName) |
| `registrationNumber` | string | – | Exact GPhC number (mode=byRegistrationNumber) |
| `fetchDetails` | boolean | `true` | Enrich each result with its full detail page |
| `maxItems` | integer | `20` | Hard cap on emitted records (1–500) |

#### Example: search pharmacists by surname

```json
{
  "mode": "byName",
  "registerType": "pharmacist",
  "lastName": "Smith",
  "maxItems": 20
}
```

#### Example: find all Boots pharmacies in London

```json
{
  "mode": "byName",
  "registerType": "pharmacy",
  "premisesName": "Boots",
  "townOrPostcode": "London",
  "maxItems": 50
}
```

#### Example: exact lookup by registration number

```json
{
  "mode": "byRegistrationNumber",
  "registerType": "pharmacist",
  "registrationNumber": "2025781"
}
```

#### Example: independent prescribers named Smith

```json
{
  "mode": "byName",
  "registerType": "pharmacist",
  "lastName": "Smith",
  "annotationFilter": "INDPRESC",
  "maxItems": 50
}
```

#### Example: browse all Community-sector training sites

```json
{
  "mode": "byName",
  "registerType": "trainingSite",
  "premisesName": "*",
  "sectorFilter": "717750000",
  "maxItems": 50
}
```

### Use cases

- **Employer/HR due diligence** — verify a pharmacist or pharmacy technician's registration status before hiring
- **Compliance & audit** — check whether a pharmacy has notices, conditions, or enforcement history
- **Healthcare directories** — build a searchable directory of registered pharmacies in a region
- **Market research** — analyse pharmacy chain footprint (e.g. all Boots/Superdrug/Lloyds branches in an area)
- **Patient safety tools** — confirm a prescriber holds Independent/Supplementary Prescriber status
- **Training providers** — check a training site's current approval status and expiry date

### FAQ

**What is the GPhC?** The General Pharmaceutical Council is the independent statutory regulator for pharmacists, pharmacy technicians, and registered pharmacy premises in Great Britain.

**Does this cover Northern Ireland?** No — Northern Ireland has its own regulator (the Pharmaceutical Society of Northern Ireland). The GPhC register covers England, Scotland, and Wales only.

**What's the difference between "search by name" and "registration number"?** Name search returns every matching entry (paginated); registration number lookup returns the single exact match for that number.

**What does the fuzzy match do?** It mirrors the register's own "I'm not sure of the spelling" option, which uses phonetic matching to surface names that sound similar even if spelled differently.

**Why do some pharmacy/training-site records not have an `inspectionReportUrl`?** Not every registered pharmacy has a published inspection report yet — the field is only included when the register shows one exists.

**How current is the data?** The register is updated by the GPhC on an ongoing basis; each search results page shows the exact "last updated" timestamp from the source at scrape time.

**Is a proxy or login required?** No — the register is fully public. The actor uses a plain HTTP client with no proxy or authentication.

**Why does `sourceUrl` return a 403 when I open it with a bare `curl` request?** The GPhC site sits behind an AWS WAF that blocks requests without a normal browser `User-Agent` header. The link itself is valid and loads fine in any regular browser or HTTP client that sends a standard User-Agent (which is exactly what this actor does when fetching detail pages).

# Actor input Schema

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

How to search the register.

## `registerType` (type: `string`):

Which GPhC register to search.

## `firstName` (type: `string`):

Given name of the pharmacist or pharmacy technician. Optional if `lastName` is set.

## `lastName` (type: `string`):

Family name / surname of the pharmacist or pharmacy technician. Optional if `firstName` is set.

## `premisesName` (type: `string`):

Business or premises name to search for, e.g. `Boots`, `Superdrug`, `Lloyds Pharmacy`. Use `*` alone to browse all premises (e.g. combined with `sectorFilter`).

## `townOrPostcode` (type: `string`):

Optional town or postcode to narrow a pharmacy/training-site name search, e.g. `London`, `SW1A 1AA`.

## `fuzzyMatch` (type: `boolean`):

Enable the register's phonetic "I'm not sure of the spelling" match instead of an exact name match (mode=byName).

## `annotationFilter` (type: `string`):

Only return pharmacists holding this prescribing annotation.

## `sectorFilter` (type: `string`):

Only return training sites in this sector. Combine with `premisesName: *` (or any name) to browse a whole sector.

## `registrationNumber` (type: `string`):

Exact GPhC registration number to look up, e.g. `2025781`. For registerType=trainingSite, you may also supply a `P`-prefixed "training site only number" (e.g. `P1031261`) for training sites that don't have a separate pharmacy registration (e.g. hospital foundation-training programmes).

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

Enrich every result with its individual registration-details page (expiry date, town, superintendent, enforcement history, etc.). Disable for faster runs with only summary fields.

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

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "byName",
  "registerType": "pharmacist",
  "firstName": "John",
  "lastName": "Smith",
  "fuzzyMatch": false,
  "annotationFilter": "",
  "sectorFilter": "",
  "fetchDetails": true,
  "maxItems": 20
}
```

# Actor output Schema

## `registrations` (type: `string`):

Dataset containing all scraped GPhC register records.

# 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": "byName",
    "registerType": "pharmacist",
    "firstName": "John",
    "lastName": "Smith",
    "fuzzyMatch": false,
    "annotationFilter": "",
    "sectorFilter": "",
    "fetchDetails": true,
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/uk-pharmacist-register-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "byName",
    "registerType": "pharmacist",
    "firstName": "John",
    "lastName": "Smith",
    "fuzzyMatch": False,
    "annotationFilter": "",
    "sectorFilter": "",
    "fetchDetails": True,
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/uk-pharmacist-register-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "mode": "byName",
  "registerType": "pharmacist",
  "firstName": "John",
  "lastName": "Smith",
  "fuzzyMatch": false,
  "annotationFilter": "",
  "sectorFilter": "",
  "fetchDetails": true,
  "maxItems": 20
}' |
apify call crawlerbros/uk-pharmacist-register-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,crawlerbros/uk-pharmacist-register-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/hmP0Mz7YqOGlYnuGR/builds/sqzDUi9ePih4H5Gys/openapi.json
