# NHS Jobs Scraper (`crawlerbros/nhs-jobs-scraper`) Actor

Extract UK NHS job vacancies from jobs.nhs.uk including title, employer, salary, band, pay scheme, location, contract type, closing date, full description, and more.

- **URL**: https://apify.com/crawlerbros/nhs-jobs-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Jobs, Automation, Developer tools
- **Stats:** 2 total users, 0 monthly users, 100.0% runs succeeded, 9 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## NHS Jobs Scraper

Extract UK NHS job vacancies from **jobs.nhs.uk** — title, employer, location, salary, band, pay scheme, contract type, working pattern, closing date, full description and more. No cookies, no proxy, no rate-limits on datacenter IPs.

### Features

- **20 output fields** per vacancy — complete job data in a flat schema
- **Search by keyword, or provide any jobs.nhs.uk search URL** with filters (location, band, pay scheme, staff group, specialty)
- **Full detail page enrichment** — pay scheme, band, reference number, job summary, main duties, full description
- **Parsed salary ranges** (GBP min/max) in addition to the raw formatted text
- **ISO-8601 dates** for posted and closing dates
- **Pagination** — walks `?page=N` until `maxItems` is reached
- **No proxy required** — jobs.nhs.uk is publicly accessible
- **No nulls** — every field has a typed default

### Input

| Field | Type | Description |
|---|---|---|
| `startUrls` | Array | NHS Jobs search-result URLs. Any filter applied in the URL (e.g., `payScheme=AGENDA`, `payBand=Band+6`, `staffGroup=Nursing+and+Midwifery`) is preserved. |
| `search` | String | Alternative shortcut — a plain keyword (e.g., `"nurse"`) that builds a default search URL. |
| `maxItems` | Integer | Maximum number of vacancies to return (default 50, max 500). |

#### Example Input

```json
{
    "startUrls": [
        "https://www.jobs.nhs.uk/candidate/search/results?keyword=nurse&payBand=Band+6"
    ],
    "maxItems": 50
}
````

or with a free-text keyword:

```json
{
    "search": "midwife",
    "maxItems": 20
}
```

### Output

Each job has **20 fields**. All fields are always present — empty strings or zero for missing data, never `null`.

#### Identity

| Field | Type | Description |
|---|---|---|
| `jobRef` | String | NHS reference number (e.g., `C9371-26-0259`) |
| `url` | String | Full job advert URL |
| `title` | String | Job title |

#### Employer & Location

| Field | Type | Description |
|---|---|---|
| `employer` | String | Employing NHS Trust or organisation |
| `location` | String | Full location text |
| `postcode` | String | UK postcode |

#### Pay & Contract

| Field | Type | Description |
|---|---|---|
| `salary` | String | Formatted salary (e.g., `"£39,959 to £48,117 a year"`) |
| `salaryMin` | Number | Minimum salary in GBP |
| `salaryMax` | Number | Maximum salary in GBP |
| `salaryPeriod` | String | Pay period (`a year`, `per annum`, `per hour`, etc.) |
| `payScheme` | String | Pay scheme (e.g., `"Agenda for change"`) |
| `payBand` | String | Pay band (e.g., `"Band 6"`) |
| `contractType` | String | Contract type (e.g., `Permanent`, `Fixed term`) |
| `workingPattern` | String | Working pattern (e.g., `Full-time`, `Part-time`) |

#### Dates

| Field | Type | Description |
|---|---|---|
| `postedDate` | String | Date posted (ISO 8601 `YYYY-MM-DD`) |
| `closingDate` | String | Closing date (ISO 8601 `YYYY-MM-DD`) |

#### Description

| Field | Type | Description |
|---|---|---|
| `jobSummary` | String | Short job summary (truncated to 2,000 chars) |
| `mainDuties` | String | Main duties text (truncated to 2,000 chars) |
| `description` | String | Full job description (truncated to 4,000 chars) |

#### Metadata

| Field | Type | Description |
|---|---|---|
| `scrapedAt` | String | ISO 8601 scrape timestamp |

#### Example Output

```json
{
    "jobRef": "C9371-26-0259",
    "url": "https://www.jobs.nhs.uk/candidate/jobadvert/C9371-26-0259",
    "title": "District Nurse/Community Nursing Sister/Charge Nurse",
    "employer": "Berkshire Healthcare Foundation Trust",
    "location": "Community Nursing West Berkshire",
    "postcode": "RG18 3HD",
    "salary": "£39,959 to £48,117 a year",
    "salaryMin": 39959.0,
    "salaryMax": 48117.0,
    "salaryPeriod": "a year",
    "payScheme": "Agenda for change",
    "payBand": "Band 6",
    "contractType": "Permanent",
    "workingPattern": "Full-time",
    "postedDate": "2026-04-09",
    "closingDate": "2026-04-16",
    "jobSummary": "...",
    "mainDuties": "...",
    "description": "...",
    "scrapedAt": "2026-04-10T17:40:00+00:00"
}
```

### FAQ

**Q: Do I need a proxy?**
No. jobs.nhs.uk serves pages directly over HTTPS without bot protection. This scraper runs fine from Apify datacenter IPs.

**Q: How do I filter by pay band or staff group?**
Apply the filter on the NHS Jobs site, then copy the URL from the address bar into `startUrls`. All query parameters (including `payBand`, `payScheme`, `staffGroup`, `specialty`, `location`) are passed through verbatim.

**Q: Are closed / expired jobs included?**
Only currently-listed vacancies from the search results are returned. Historical closed jobs aren't accessible via search.

**Q: What's the maximum throughput?**
NHS search pages return 10 results each. The scraper walks pages sequentially and enriches details in parallel (concurrency 4) — expect ~40 jobs/minute.

**Q: Why are some `salaryMin` / `salaryMax` values the same?**
When a job has a fixed salary (not a range), both fields are set to the same value.

### Use Cases

- **Healthcare recruitment research** — monitor NHS hiring trends by band, speciality, region
- **Job alerts** — daily runs to watch new nursing, medical, or admin postings in specific trusts
- **Salary benchmarking** — aggregate pay data across NHS bands and locations
- **Workforce planning** — pull open positions into HR/ATS systems
- **Regional healthcare analysis** — compare vacancy counts across regions or trusts

# Actor input Schema

## `startUrls` (type: `array`):

NHS Jobs search-result URLs (e.g., https://www.jobs.nhs.uk/candidate/search/results?keyword=nurse). Any filters you apply on the site (location, pay scheme, band, staff group) are preserved in the URL.

## `search` (type: `string`):

Alternative to startUrls — a plain keyword that builds a default NHS Jobs search URL (e.g., 'nurse', 'doctor', 'midwife').

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

Maximum number of job vacancies to return.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.jobs.nhs.uk/candidate/search/results?keyword=nurse"
  ],
  "maxItems": 3
}
```

# Actor output Schema

## `jobs` (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 = {
    "startUrls": [
        "https://www.jobs.nhs.uk/candidate/search/results?keyword=nurse"
    ],
    "maxItems": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/nhs-jobs-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 = {
    "startUrls": ["https://www.jobs.nhs.uk/candidate/search/results?keyword=nurse"],
    "maxItems": 3,
}

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

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

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

```

## CLI example

```bash
echo '{
  "startUrls": [
    "https://www.jobs.nhs.uk/candidate/search/results?keyword=nurse"
  ],
  "maxItems": 3
}' |
apify call crawlerbros/nhs-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=crawlerbros/nhs-jobs-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "NHS Jobs Scraper",
        "description": "Extract UK NHS job vacancies from jobs.nhs.uk including title, employer, salary, band, pay scheme, location, contract type, closing date, full description, and more.",
        "version": "1.0",
        "x-build-id": "lHi8PTdt6qK34h1GB"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/crawlerbros~nhs-jobs-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-crawlerbros-nhs-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/crawlerbros~nhs-jobs-scraper/runs": {
            "post": {
                "operationId": "runs-sync-crawlerbros-nhs-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/crawlerbros~nhs-jobs-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-crawlerbros-nhs-jobs-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "NHS Jobs search-result URLs (e.g., https://www.jobs.nhs.uk/candidate/search/results?keyword=nurse). Any filters you apply on the site (location, pay scheme, band, staff group) are preserved in the URL.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "search": {
                        "title": "Search Keyword (optional)",
                        "type": "string",
                        "description": "Alternative to startUrls — a plain keyword that builds a default NHS Jobs search URL (e.g., 'nurse', 'doctor', 'midwife')."
                    },
                    "maxItems": {
                        "title": "Max Items",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Maximum number of job vacancies to return.",
                        "default": 50
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
