# Ofsted Inspections Scraper (England Schools & Childcare) (`steadfetch/ofsted-inspection-monitor`) Actor

Search and monitor England's public Ofsted inspection register. Get normalized provider records (URN, provider, type, overall grade, inspection date, report URL) by keyword, postcode, local authority or URN, and only new or changed providers in monitor mode.

- **URL**: https://apify.com/steadfetch/ofsted-inspection-monitor.md
- **Developed by:** [Steadfetch](https://apify.com/steadfetch) (community)
- **Categories:** Other, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 provider record delivereds

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?

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

[Apify](https://apify.com) Actor by [Steadfetch](https://apify.com/steadfetch): search and monitor England's public Ofsted inspection register, with normalized records and only new-or-changed results in monitor mode.

### What it does

- Searches Ofsted's public inspection register ([reports.ofsted.gov.uk](https://reports.ofsted.gov.uk/)) by keyword, postcode, local-authority code or Ofsted URN.
- Returns one normalized dataset item per provider: URN, provider name, provider category/type, overall grade, inspection date, report URL, and English postal county. Missing grade, date and county are returned as `null` -- never inferred.
- Filters results by provider category using `providerTypes` (case-insensitive match).
- Handles the national result pagination for you: it follows the site's own "next page" links until `maxResults` is reached.
- **Monitor mode:** delivers only providers that are new or whose grade, inspection date, category or address changed since the previous run for the same Apify user. A quiet run pushes no results.
- **Daily captures:** every run uploads the full result set to S3 at `qa/ofsted/<date>/` so the QA team can inspect what was returned. Best-effort -- missing S3 credentials never fail the Actor.
- Validates every item against the dataset schema in `.actor/dataset_schema.json` before it reaches the dataset. With `strictSchema: true` (the default) invalid data fails the run instead of being published.
- Reads public register metadata only: no report bodies, staff names, parent letters or personal data. No login, paywall, CAPTCHA or anti-bot bypass.

### How to use

Run it from the Apify Console or with the CLI:

```bash
apify call steadfetch/ofsted-inspection-monitor --input='{"query":"primary school","maxResults":10}'
```

Then read the run's default dataset (JSON, CSV or the API).

#### Input fields

| Field | Type | Required | Default | Description | Example |
| --- | --- | --- | --- | --- | --- |
| `urns` | array of strings | No | `[]` | Look up specific providers by Ofsted URN. Exact matches only. | `["140696"]` |
| `query` | string | No | `"primary school"` | Free-text search: name, URN or keyword. | `"primary school"` |
| `postcode` | string | No | - | Search around a UK postcode or place name. | `"SW1A 1AA"` |
| `localAuthority` | string | No | - | Numeric Ofsted local-authority code (from the site's Local Authority filter). | `"202"` |
| `providerTypes` | array of strings | No | `[]` | Case-insensitive category filter (for example Primary, Independent School). Leave empty for all types. | `["Primary", "Nursery"]` |
| `monitorMode` | boolean | No | `false` | Deliver only new or changed providers and bill one `monitor-check` per provider checked. | `true` |
| `knownState` | object | No | `{}` | Optional monitor seed. Empty keeps the state saved for your Apify user. | `{}` |
| `maxResults` | integer | No | `100` | Maximum providers delivered to the dataset. | `100` |
| `strictSchema` | boolean | No | `true` | Fail the run when an item does not match the output schema. Keep enabled. | `true` |

Provide at least one of `urns`, `query`, `postcode` or `localAuthority`. URN lookups take precedence over the other selectors.

#### Example input

Matches the declared `exampleRunInput` exactly:

```json
{
  "query": "primary school",
  "maxResults": 10
}
```

### Output

#### Example output

```json
{
  "url": "https://reports.ofsted.gov.uk/provider/21/140696",
  "title": "Ab Kettleby Primary School",
  "scrapedAt": "2026-10-26T09:00:00.000Z",
  "urn": "140696",
  "provider": "Ab Kettleby Primary School",
  "providerType": "Primary",
  "providerTypeCode": "21",
  "address": "Wartnaby Road, Ab Kettleby, Melton Mowbray, Leicestershire, LE14 3JJ",
  "grade": "Good",
  "inspectionDate": "2023-01-27",
  "reportUrl": "https://reports.ofsted.gov.uk/provider/21/140696",
  "sourceUrl": "https://reports.ofsted.gov.uk/search?q=primary+school",
  "postalCounty": "Leicestershire",
  "lad": null,
  "ons_code": null
}
```

In monitor mode each emitted item also carries `changeType` (`new` or `updated`) and `changedFields`.

#### Output fields

| Field | Type | Description |
| --- | --- | --- |
| `url` | string | Report URL (common Steadfetch envelope, required). |
| `title` | string | null | Provider name from the result block. |
| `scrapedAt` | date-time | ISO 8601 UTC timestamp of the run (common envelope, required). |
| `urn` | string | Ofsted Unique Reference Number (required). |
| `provider` | string | Provider name; falls back to the URN when the source does not declare one (required). |
| `providerType` | string | null | Ofsted category shown on the result block. |
| `providerTypeCode` | string | null | Provider type segment of the report URL. |
| `address` | string | null | Provider postal address. |
| `grade` | string | null | Latest overall grade, or `null` when the block does not declare one. |
| `inspectionDate` | date | null | Latest report date, ISO 8601, or `null`. |
| `reportUrl` | string | Official Ofsted provider report page. |
| `sourceUrl` | string | Search URL the provider was found on. |
| `postalCounty` | string | null | English postal county extracted from the address (the word immediately before the postcode). |
| `lad` | string | null | Local Authority derived from the address. Null -- not published by Ofsted on the result page. |
| `ons_code` | string | null | ONS code for the Local Authority. Placeholder -- null until a lookup is implemented. |
| `changeType` | string | null | Monitor mode only: `new` or `updated`. |
| `changedFields` | array | Monitor mode only: fields that changed since the previous run. |

New fields are additive and `required` fields never change, so downstream code can rely on `url`, `scrapedAt`, `urn` and `provider`.

### Pricing

Pay-per-event with the Apify synthetic events plus the reserved monitor event:

- `apify-actor-start` at 0.00005 USD per run (Apify-recommended default, includes the first 5 seconds of compute).
- `apify-default-dataset-item` at **5 USD per 1,000 results**. Every delivered provider is one result; unchanged checks in monitor mode deliver nothing and cost nothing.
- `monitor-check` at **0.40 USD per 1,000 checks**, charged once per provider actually checked in a monitor run, including checks where nothing changed. Extract runs never charge it.

There is no custom per-result event, so users are never billed twice for the same record.

**Works on the Apify free plan:** at 0.005 USD per result, the 5 USD monthly credit covers roughly 1,000 delivered providers, minus the negligible run-start charge.

**Data attribution:** contains public sector information licensed under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/). (c) Crown copyright. Each row carries the `reportUrl` and `sourceUrl` it came from.

### FAQ

**Does the Actor need a login or paid subscription to Ofsted?** No. It only reads public inspection register pages.

**Why no browser?** The Ofsted search is server-rendered HTML, so HTTP + Cheerio is roughly 10x cheaper and faster than a browser. No JavaScript rendering is required.

**When am I charged?** Once per run start (`apify-actor-start`), once per delivered provider (`apify-default-dataset-item`) and, in monitor mode only, once per provider checked (`monitor-check`). Failed runs that deliver no results only incur the start event.

**Does it return people's names?** No. Only public register metadata about the provider (institution) is emitted. Report bodies, staff names and parent letters are never read or returned.

**What happens if a provider has no published grade?** The record is still returned with `grade: null` and `inspectionDate: null`. The Actor never invents values.

**Is the output schema stable?** Yes. New fields are added additively and `required` fields never change.

### Support

Report bugs or request features through the Apify Store page (Issues tab) of this Actor, or through the Steadfetch actors repository issues. Include the run ID and the input used.

### Maintenance

This Actor is **tested daily** in the Steadfetch catalog QA, and every change passes `npm test` (lint, typecheck, Vitest) plus the shared publish gate before publication. The source's robots file is checked before every change; the Actor only requests `/search`, never the disallowed `/unsubscribe/` or `/subscribe/validate/` paths.

# Actor input Schema

## `urns` (type: `array`):

Optional. Fetch specific providers by their Ofsted URN (for example 140696). Each URN is looked up in the public search; exact matches only.

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

Optional. Free-text search across provider name, URN or keyword, exactly as on reports.ofsted.gov.uk.

## `postcode` (type: `string`):

Optional. Search around a UK postcode or place name (for example SW1A 1AA).

## `localAuthority` (type: `string`):

Optional. Numeric Ofsted local-authority code (for example 202 for Camden). The code is shown in the site's Local Authority filter.

## `providerTypes` (type: `array`):

Optional. Narrow results to specific Ofsted provider categories (case-insensitive match against the Category field, for example Primary, Independent School, Childcare on Non-Domestic Premises). Leave empty for all types.

## `monitorMode` (type: `boolean`):

When enabled, only providers that are new or whose grade, inspection date, category or address changed since the previous run for the same Apify user are delivered, and each checked provider bills one monitor-check event. Leave disabled for a one-off backfill.

## `knownState` (type: `object`):

Optional. Monitor-mode seed of previously seen providers. Leave empty to keep using the state saved for your Apify user from the previous run.

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

Maximum number of providers delivered to the dataset. Each delivered provider is one billable result event.

## `strictSchema` (type: `boolean`):

Fail the run when an item does not match the OUTPUT schema. Keep enabled: Steadfetch never publishes Actors without output-schema validation.

## Actor input object example

```json
{
  "urns": [
    "140696",
    "123456"
  ],
  "query": "King's School",
  "postcode": "SW1A 1AA",
  "localAuthority": "202",
  "providerTypes": [
    "Primary",
    "Nursery"
  ],
  "monitorMode": true,
  "knownState": {
    "140696": {
      "grade": "Good",
      "date": "2026-01-15"
    }
  },
  "maxResults": 100,
  "strictSchema": true
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset items validated against the item schema in dataset_schema.json (fields).

# 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 = {
    "urns": [],
    "query": "primary school",
    "providerTypes": [],
    "monitorMode": false,
    "knownState": {},
    "maxResults": 10,
    "strictSchema": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadfetch/ofsted-inspection-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 = {
    "urns": [],
    "query": "primary school",
    "providerTypes": [],
    "monitorMode": False,
    "knownState": {},
    "maxResults": 10,
    "strictSchema": True,
}

# Run the Actor and wait for it to finish
run = client.actor("steadfetch/ofsted-inspection-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 '{
  "urns": [],
  "query": "primary school",
  "providerTypes": [],
  "monitorMode": false,
  "knownState": {},
  "maxResults": 10,
  "strictSchema": true
}' |
apify call steadfetch/ofsted-inspection-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadfetch/ofsted-inspection-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/4eIbSuAcsk1regymY/builds/EbGfQ6hSYTMKZ6ypY/openapi.json
