# Teaching Vacancies GOV UK Scraper (DfE) (`santamaria-automations/teaching-vacancies-uk-scraper`) Actor

Extract UK teaching jobs from teaching-vacancies.service.gov.uk, the official DfE board for state schools and academies. Returns title, school, trust, local authority, phase, key stage, subject, salary scale, ECT suitability, closing date and apply URL. Pay-per-result.

- **URL**: https://apify.com/santamaria-automations/teaching-vacancies-uk-scraper.md
- **Developed by:** [NanoScrape](https://apify.com/santamaria-automations) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 serp job (fast)s

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

## Teaching Vacancies UK Scraper (DfE)

Extract UK teaching jobs from [teaching-vacancies.service.gov.uk](https://teaching-vacancies.service.gov.uk), the UK Department for Education's official jobs board for state schools, academies, and Multi-Academy Trusts. No login. No captcha. Pay-per-result.

### What it does

Scrapes live vacancies from the official DfE Teaching Vacancies service and returns clean, structured JSON. Coverage includes classroom teachers, teaching assistants, HLTAs, SENCOs, subject leads, deputy and headteachers across nursery, primary, secondary, 16-19, all-through, and special schools.

Works with:

- Search keywords (e.g. `"primary teacher"`, `"SENCO"`, `"maths"`).
- Any search URL copy-pasted from the site (all filters preserved).
- Location or postcode filter.
- Phase filter and "ECT suitable" filter.

### Sample output

```json
{
  "_type": "job",
  "id": "headteacher-st-john-fisher",
  "title": "Headteacher",
  "school_name": "St John Fisher Roman Catholic Primary School",
  "company_name": "St John Fisher Roman Catholic Primary School",
  "local_authority": "Manchester",
  "location": "St John Fisher Roman Catholic Primary School, Manchester, M14 6RB",
  "postcode": "M14 6RB",
  "country": "GB",
  "phase": "primary",
  "religious_character": "Roman Catholic",
  "key_stage": null,
  "position_type": "headteacher",
  "pay_min_pence": null,
  "pay_max_pence": null,
  "pay_scale": "L18-L24",
  "pay_text": "L18-L24 (£65,286-£75,675)",
  "employment_type": "full-time",
  "working_pattern": "full-time",
  "ect_suitable": false,
  "visa_sponsorship": null,
  "start_date": "1 September 2026",
  "closing_at": "12 September 2026 at 12:00pm",
  "listed_at": "20 August 2026",
  "posted_at_text": "20 August 2026",
  "posted_at_datetime": "2026-08-20T00:00:00Z",
  "application_url": "https://schools.stoccat.org.uk/vacancies",
  "job_url": "https://teaching-vacancies.service.gov.uk/jobs/headteacher-st-john-fisher",
  "source_url": "https://teaching-vacancies.service.gov.uk/jobs/headteacher-st-john-fisher",
  "source_platform": "teaching-vacancies.service.gov.uk",
  "scraped_at": "2026-08-22T14:30:00Z",
  "description": "St John Fisher Roman Catholic Primary School is seeking to appoint an inspirational Headteacher...",
  "description_full": "St John Fisher Roman Catholic Primary School is seeking to appoint an inspirational Headteacher...\n\nThe successful candidate will be a practising Catholic with a proven track record of school leadership.\n\nFor an informal discussion, please contact afidler@sjcmat.co.uk.",
  "description_html": "<p>St John Fisher Roman Catholic Primary School is seeking to appoint an inspirational Headteacher...</p><p>The successful candidate will be...</p>",
  "description_md": "St John Fisher Roman Catholic Primary School is seeking to appoint an inspirational Headteacher...\n\nThe successful candidate will be a practising Catholic with a proven track record of school leadership.\n\nFor an informal discussion, please contact afidler@sjcmat.co.uk.",
  "contact_emails": ["afidler@sjcmat.co.uk"],
  "contact_phones": [],
  "contact_urls": ["https://schools.stoccat.org.uk/vacancies"],
  "school_size": 210,
  "age_range": "4 to 11",
  "company_about": null,
  "company_phone": null,
  "company_email": null,
  "company_website": "https://www.stjohnfisher.stoccat.org.uk/",
  "company_address_street": null,
  "company_address_city": null,
  "company_address_postcode": "M14 6RB",
  "company_address_country": "United Kingdom",
  "company_active_jobs_count": 2,
  "company_active_jobs": [{"title": "Class Teacher (Y3)", "job_url": "https://teaching-vacancies.service.gov.uk/jobs/class-teacher-y3-st-john-fisher"}]
}
```

### Pricing

**$0.001 per actor start + $0.005 per full-detail row (or $0.003 per SERP-only row) + optional $0.005 per unique school profile enriched. About $5 per 1,000 jobs in full mode.**

You only pay for rows that successfully return data. Failed fetches are not charged.

**New to Apify?** Every account gets a $5 free monthly platform credit, enough for around 1,000 full-mode results on this actor before you commit to paying anything. Test extensively first.

### Input

| Field | Type | Description |
|---|---|---|
| `searchUrls` | array | Paste one or more search URLs from the site. All filters preserved. |
| `searchQueries` | array | Keywords like `"primary teacher"`, `"maths"`, `"SENCO"`. Each runs as a separate search. |
| `location` | string | UK location or postcode, e.g. `"London"`, `"SW1A 1AA"`. |
| `phase` | select | Filter by phase: nursery, primary, secondary, 16-19, all-through, special. |
| `ectSuitable` | boolean | Only include jobs marked suitable for Early Career Teachers. |
| `maxResults` | integer | Total row cap across all queries. |
| `maxResultsPerQuery` | integer | Row cap per query. |
| `mode` | select | `fast` (SERP only) or `full` (SERP + detail pages). Default `full`. |
| `includeJobDetails` | boolean | Alias for full mode. When true, forces mode=full. |
| `includeCompanyDetails` | boolean | Fetch each school's `/organisations/{slug}` page for a snapshot of other roles at the school. Deduplicated per school. Implies `includeJobDetails=true`. |

### Output fields

**Identity and title:** `id`, `title`, `job_url`, `source_url` (alias of `job_url`), `source_platform`, `_type`.

**School and organisation:** `school_name`, `company_name` (fleet-standard alias of `school_name`), `trust_name`, `local_authority`, `location`, `postcode`, `country`, `organisation_type_raw`, `religious_character`, `age_range`, `school_size`.

**Role classification:** `phase`, `key_stage`, `subject`, `position_type`, `job_role_raw`, `sen_specialism`.

**School profile (populated when `includeCompanyDetails=true`)**

- `company_website`: The school's own website URL — extracted from the "Website" row in the school-overview section on the PDP. Populated when the school included one in their listing (majority of secondary and academy trust listings; some primaries omit it).
- `company_about`, `company_phone`, `company_email`, `company_address_street`, `company_address_city`: Usually null. Teaching-vacancies's `/organisations/{slug}` page is a filtered jobs view, not a school details page, so these fields rarely populate. Use `contact_emails[]` / `contact_phones[]` / `contact_urls[]` below for description-embedded contacts.
- `company_address_postcode`, `company_address_country`: Aliased from the PDP-level postcode + fixed to United Kingdom.
- `company_active_jobs_count`, `company_active_jobs`: Snapshot of other currently-open roles at the same school (title + URL).

**Contract and pay:** `employment_type`, `working_pattern`, `pay_min_pence`, `pay_max_pence`, `pay_currency`, `pay_scale`, `pay_text`, `ect_suitable`, `visa_sponsorship`.

**Timeline and links:** `start_date`, `closing_at`, `listed_at`, `interview_date`, `application_url`, `ofsted_url`.

**Description (4-field standard):** `description` (single-line whitespace-normalised, back-compat), `description_full` (multi-line with `\n` at paragraph/list/heading boundaries), `description_html` (raw HTML block), `description_md` (Markdown for LLM ingestion — h1-h6, paragraphs, lists, links).

**Contact extraction (parsed from job description text):**

- `contact_emails` (array): Email addresses found in the description body, deduplicated and lower-cased. Populated on ~50-70% of headteacher and SEN listings where schools include a direct-contact address.
- `contact_phones` (array): UK phone numbers (0-prefix, `+44`, spaced formats) found in the description body, deduplicated.
- `contact_urls` (array): External http(s) URLs found in the description body, deduplicated. Self-referential teaching-vacancies.service.gov.uk service links are excluded.

**Posted-at date fields:** `listed_at` (raw display string as shown on the site), `posted_at_text` (same raw string, fleet-standard field name), `posted_at_datetime` (parsed ISO datetime).

**Meta:** `search_query`, `scraped_at`.

**Contact extraction from description:** `contact_emails[]` (deduplicated + lower-cased), `contact_phones[]` (UK 0-prefix, +44, spaced formats), `contact_urls[]` (external http(s) links; self-referential DfE service links are excluded).

### Use with AI Agents (MCP)

Connect this actor to any MCP-compatible AI client: Claude Desktop, Claude.ai, Cursor, VS Code, LangChain, LlamaIndex, or custom agents.

**Apify MCP server URL:**

`https://mcp.apify.com?tools=nanoscrape/teaching-vacancies-uk-scraper`

**Example prompt once connected:**

> "Use `teaching-vacancies-uk-scraper` to find all Early Career Teacher primary vacancies in London closing this week. Return as a table with school, closing date, and application URL."

Clients that support dynamic tool discovery (Claude.ai, VS Code) receive the full input schema automatically.

### Why this scraper

- **Official DfE source.** Every vacancy is real, verified, published by the school or MAT that hosts it.
- **Deep school metadata.** Trust, local authority, religious character, Ofsted link, age range, and pupil count come out of the box.
- **UK-specific field parsing.** Salaries in pence, pay-scale detection (Main Pay Scale / UPS / Leadership), Key Stage normalisation (EYFS, KS1..KS5).
- **ECT flag surfaced.** Filter directly for jobs suitable for Early Career Teachers.
- **No login. No captcha.** The DfE service is public.

### Common use cases

- Recruitment agencies aggregating live UK teaching vacancies for their candidate CRM.
- EdTech firms building a live map of subject-specific demand (Maths, Science, SEND).
- Journalists and researchers tracking headteacher turnover and pay scales across regions.
- MAT central offices monitoring competitor vacancy volume and pay bands.

### Notes and limits

- When `includeCompanyDetails=true`, each unique school is fetched once per run (deduplicated by /organisations/{slug}). Teaching-vacancies renders schools as filtered jobs views, so extraction primarily fills `company_active_jobs`; `company_about`/`_phone`/`_website` stay null.

- Some vacancies do not publish a numeric salary. `pay_text` will hold the scale name (e.g. `"Teacher Main Scale"`) but `pay_min_pence` and `pay_max_pence` will be null.

- `trust_name` is only populated when the vacancy page explicitly links a MAT.

- Subject specialism is inferred from the `Subject` field on the vacancy page. Where the school leaves it blank, `subject` is null.

- The service currently lists ~15,000 to 25,000 live vacancies at any time. Practical maximum per query is ~1,000 rows due to the site's own pagination cap.

### Related Actors

- [Job Feed](https://apify.com/santamaria-automations/job-feed): one normalized, deduplicated job feed across 50+ international job boards. Orchestrates the NanoScrape fleet.
- [Career Site Jobs Scraper](https://apify.com/santamaria-automations/career-site-jobs-scraper): scrape jobs directly from company career pages (Greenhouse, Lever, Workday, etc.).
- [Website Job Extractor](https://apify.com/santamaria-automations/website-job-extractor): extract job listings from any website via HTML pattern detection.
- [Reed.co.uk Scraper](https://apify.com/santamaria-automations/reed-uk-scraper): private-sector UK jobs board, 200,000+ live vacancies.
- [NHS Jobs Scraper](https://apify.com/santamaria-automations/nhs-jobs-scraper): sister UK-public-sector board.
- [CV-Library Scraper](https://apify.com/santamaria-automations/cvlibrary-scraper): general UK jobs board.
- [Civil Service Jobs Scraper](https://apify.com/santamaria-automations/civilservicejobs-scraper): sister UK-public-sector board.

### Support

For issues, feature requests, or field gaps, please open an issue on the [Issues tab](https://apify.com/nanoscrape/teaching-vacancies-uk-scraper/issues). We typically respond within 24 hours.

Contact: contact@nanoscrape.com

# Actor input Schema

## `searchQueries` (type: `array`):

One or more keywords, e.g. 'primary teacher', 'maths', 'SENCO', 'headteacher'. Each runs as a separate search. Results are deduplicated.

## `location` (type: `string`):

Location or postcode filter, e.g. 'London', 'Manchester', 'SW1A 1AA'. Applied to all search queries.

## `searchUrls` (type: `array`):

Paste one or more teaching-vacancies.service.gov.uk search URLs. Go to the site, apply any filters (phase, subject, location, ECT status), and copy the browser URL. All filters are preserved. Mutually exclusive with searchQueries.

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

Alias of searchUrls — direct SERP URLs to crawl instead of building from keywords. Mutually exclusive with searchQueries.

## `includeJobDetails` (type: `boolean`):

Fetch each job's detail page for the full description, structured salary, employment type, closing date, and any additional PDP-only fields. Otherwise only SERP-visible fields are returned.

## `includeCompanyDetails` (type: `boolean`):

Also fetch each unique employer's company profile page for the About-us text, phone, address, website, and a list of the employer's other currently-open roles. Deduplicated per employer within a run. Adds one HTTP hop per unique employer.

## `phase` (type: `string`):

Filter by phase. Applied to keyword searches only.

## `ectSuitable` (type: `boolean`):

Only include jobs marked as suitable for Early Career Teachers.

## `maxResults` (type: `integer`):

Total cap across all queries and search URLs.

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

Maximum results per search URL or keyword.

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

Fast mode returns the SERP fields only. Full mode also fetches each vacancy page for full description, salary scale, key stage, subject, dates and apply URL.

## `maxConcurrency` (type: `integer`):

Maximum concurrent detail-page requests in full mode.

## Actor input object example

```json
{
  "searchQueries": [
    "primary teacher"
  ],
  "location": "London",
  "searchUrls": [],
  "includeJobDetails": false,
  "includeCompanyDetails": false,
  "phase": "",
  "ectSuitable": false,
  "maxResults": 5,
  "maxResultsPerQuery": 5,
  "mode": "full",
  "maxConcurrency": 6
}
```

# Actor output Schema

## `jobListings` (type: `string`):

Dataset of UK teaching vacancies. Each row includes job id, title, school, trust, phase, key stage, subject, position type, working pattern, contract type, pay range in pence, pay scale, ECT flag, start/close/listed dates, application URL, description and source URL.

# 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 = {
    "searchQueries": [
        "primary teacher"
    ],
    "searchUrls": [],
    "maxResults": 5,
    "maxResultsPerQuery": 5,
    "mode": "full",
    "maxConcurrency": 6
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/teaching-vacancies-uk-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 = {
    "searchQueries": ["primary teacher"],
    "searchUrls": [],
    "maxResults": 5,
    "maxResultsPerQuery": 5,
    "mode": "full",
    "maxConcurrency": 6,
}

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/teaching-vacancies-uk-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 '{
  "searchQueries": [
    "primary teacher"
  ],
  "searchUrls": [],
  "maxResults": 5,
  "maxResultsPerQuery": 5,
  "mode": "full",
  "maxConcurrency": 6
}' |
apify call santamaria-automations/teaching-vacancies-uk-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,santamaria-automations/teaching-vacancies-uk-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/CKI5rqbCWgZOae0i3/builds/k3AgLeCIKlR8jfKPj/openapi.json
