# UK Food Hygiene Ratings (`spookyweb/uk-food-hygiene-ratings`) Actor

Official FSA food hygiene ratings for every UK food business. Search by council, postcode, business type or rating, and isolate businesses rated 2 or below.

- **URL**: https://apify.com/spookyweb/uk-food-hygiene-ratings.md
- **Developed by:** [丂卩ㄖㄖҜㄚ](https://apify.com/spookyweb) (community)
- **Categories:** Lead generation, News, AI
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 establishments

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/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 Food Hygiene Ratings, FSA

Food hygiene ratings for every food business in the UK, straight from the official Food Standards Agency register. Restaurants, cafes, takeaways, pubs, hotels, schools, care homes, shops and manufacturers. No API key needed.

### 🔍 What does UK Food Hygiene Ratings do?

It queries the FSA's own ratings API and returns every matching establishment as a clean row of data, ready for a spreadsheet, a CRM or your own product. Search by council, postcode, coordinates, business name, business type or rating.

The useful bit is `actionableOnly`. Set it and you get only businesses rated 2 or below, meaning the FSA has told them to improve. Those are the businesses actively looking to fix something right now.

That matters if you sell:

- Food hygiene consultancy, audits or Level 2 and 3 training
- Pest control
- Commercial kitchen deep cleaning or equipment
- HACCP software or temperature monitoring
- EPOS and compliance systems

Every record includes the address, postcode, coordinates, and the council's own environmental health contact.

### 📊 What data can I extract from the FSA?

One row per establishment:

| Field | Description |
|---|---|
| `fhrsId` | FSA establishment id |
| `businessName`, `businessType`, `businessTypeId` | Business and its category |
| `address`, `postcode`, `phone` | Location and contact where published |
| `latitude`, `longitude` | Coordinates |
| `ratingValue` | Rating as published, 0 to 5, or Pass and Improvement Required in Scotland |
| `ratingNumeric` | Numeric rating, null for Scottish ratings |
| `ratingDate` | When the rating was given |
| `newRatingPending` | A re-inspection result is due |
| `isActionable` | True when rated 2 or below |
| `hygieneScore`, `structuralScore`, `managementConfidenceScore` | Component scores, lower is better |
| `schemeType` | FHRS for England, Wales and Northern Ireland, FHIS for Scotland |
| `localAuthority`, `localAuthorityEmail`, `localAuthorityWebsite` | Responsible council |
| `fsaUrl` | Link to the public FSA record |
| `retrievedAt` | Retrieval timestamp |

Note that Scotland uses a different scheme with Pass and Improvement Required rather than 0 to 5, so `ratingNumeric` and `isActionable` are null and false for Scottish records.

### 💡 Why scrape food hygiene ratings?

**Lead generation.** Every business in an area rated 2 or below, with the address and the council's environmental health contact attached.

**Market research.** Rating distribution by area or business type, from the official register rather than a sample.

**Property and franchise.** Check a site's hygiene history before signing a lease or approving a franchisee.

**Consumer apps.** Enrich a restaurant listing with its official rating and a link back to the FSA record.

### 🚀 How do I use UK Food Hygiene Ratings?

1. Click **Try for free**.
2. Set at least one filter, most often `postcodeOrAddress` with a `radiusMiles`.
3. Narrow it with `name`, `businessTypeId` or `ratingValue`.
4. Turn on `actionableOnly` to keep only businesses rated 2 or below, and set `maxResults` to cap the run.
5. Click **Start**, then download the results as JSON, CSV or Excel, or pull them from the API.

### ⬇️ Input

The FSA rejects unfiltered queries, so set at least one of `localAuthorityId`, `name`, `postcodeOrAddress`, `latitude` and `longitude`, `businessTypeId` or `ratingValue`.

```json
{
  "postcodeOrAddress": "M1 1AE",
  "radiusMiles": 5,
  "ratingValue": "2",
  "actionableOnly": true,
  "maxResults": 200
}
```

| Field | Type | Default | What it does |
|---|---|---|---|
| `postcodeOrAddress` | string | `M1 1AE` | Free text address or postcode |
| `name` | string | | Business name contains |
| `businessTypeId` | integer | | Numeric business type id |
| `ratingValue` | string | | Exact rating, 0 to 5 |
| `actionableOnly` | boolean | `false` | Keep only businesses rated 2 or below |
| `radiusMiles` | integer | `1` | Radius around the postcode or coordinates |
| `maxResults` | integer | `500` | Hard cap on billable results |

Three further inputs are available. `localAuthorityId` takes one of 363 councils, listed at [api.ratings.food.gov.uk/Authorities](https://api.ratings.food.gov.uk/Authorities). `latitude` and `longitude` do a radius search from coordinates instead of a postcode. `sortBy` takes rating, alpha or distance. Business type ids are listed at [api.ratings.food.gov.uk/BusinessTypes](https://api.ratings.food.gov.uk/BusinessTypes).

### ⬆️ Output

#### Table view

Results arrive as a Ratings table you can sort and filter in the Console, with the business, rating, address and council lined up for scanning. There is a second view, Inspection scores, which lines up the three component scores for comparing establishments against each other.

#### JSON

A typical row:

```json
{
  "businessName": "Abaseen",
  "businessType": "Takeaway/sandwich shop",
  "ratingValue": "2",
  "ratingDate": "2025-04-18T00:00:00.000Z",
  "address": "484 Cheetham Hill Road, Manchester",
  "postcode": "M8 9JW",
  "localAuthority": "Manchester City Council",
  "fsaUrl": "https://ratings.food.gov.uk/business/1820175",
  "fhrsId": 1820175
}
```

Download it from the run as JSON, CSV or Excel, or read it straight from the API.

### Postcode formats

Type the postcode however you have it. All of these reach the same place:

```
M1 1AE       m1 1ae       M11AE        m11ae
M1-1AE       M1.1AE       "M1 1AE"     M1 1AE.
```

Case, spacing and surrounding punctuation are all normalised before the lookup runs. This matters more than it looks: the postcode is geocoded so that the radius is honoured, and a postcode that fails to resolve falls back to being matched as literal address text, which quietly returns a single business instead of the surrounding area.

`GIR 0AA` is handled as the special case it is. Anything that is not a postcode, such as a place name or a full address, is matched as address text instead.

### Data source

Food Standards Agency, [ratings.food.gov.uk](https://ratings.food.gov.uk/), published under the Open Government Licence v3.0. Ratings are a snapshot of the last inspection and can change. Always link back to `fsaUrl` for the current position.

### 💰 How much does it cost?

You pay per establishment returned. Set `maxResults` to cap what a run can cost, and use `actionableOnly` or `ratingValue` to avoid paying for records you were only going to filter out afterwards.

Runs that return nothing cost nothing. Paid Apify plans get a lower rate per establishment.

### 🔌 Integrations

Send results straight to Google Sheets, Slack, Airtable, Zapier, Make or your own webhook using [Apify integrations](https://docs.apify.com/platform/integrations). You can also trigger a run whenever something happens in another tool, which is the usual way to drop new low rated businesses into a CRM as leads.

### 🔗 Using UK Food Hygiene Ratings with the Apify API

```bash
curl -X POST "https://api.apify.com/v2/acts/spookyweb~uk-food-hygiene-ratings/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"postcodeOrAddress": "M1 1AE", "radiusMiles": 5, "ratingValue": "2", "actionableOnly": true, "maxResults": 200}'
```

Or with the Apify client:

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

const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('spookyweb/uk-food-hygiene-ratings').call({
  postcodeOrAddress: 'M1 1AE',
  radiusMiles: 5,
  ratingValue: '2',
  actionableOnly: true,
  maxResults: 200,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Full detail is in the [Apify API reference](https://docs.apify.com/api/v2), and every run is also callable from the [Python](https://docs.apify.com/api/client/python) and [JavaScript](https://docs.apify.com/api/client/js) clients.

### ❓ FAQ

#### What does a rating of 2 or below mean?

That the FSA has told the business to improve. A 5 is very good and a 0 means urgent improvement is necessary, so anything at 2 or lower is a business with an open problem and a reason to buy help. Set `actionableOnly` to true and you get only those, and the `isActionable` field flags them on every row.

#### Does it cover Scotland?

Yes, but Scotland runs a different scheme. FHIS publishes Pass or Improvement Required instead of a 0 to 5 number, so `ratingValue` carries that text, and `ratingNumeric` is null and `isActionable` is false for Scottish records. The `schemeType` field tells you which scheme a row came from.

#### How current are the ratings?

A rating is a snapshot of the last inspection, and the register is updated as councils publish new inspections. `ratingDate` tells you when the current rating was given, and `newRatingPending` flags an establishment whose re-inspection result is due. Always link back to `fsaUrl` for the current position.

#### Can I search a whole council area?

Yes, set `localAuthorityId` to the council you want. The full list of 363 councils is at [api.ratings.food.gov.uk/Authorities](https://api.ratings.food.gov.uk/Authorities). Pair it with `actionableOnly` to get every low rated business in that council in one run.

#### What are the three component scores?

`hygieneScore` covers food handling, `structuralScore` covers the condition of the premises, and `managementConfidenceScore` covers how much the inspector trusts management to keep standards up. Lower is better on all three, and together they produce the headline rating. They are useful for telling apart two businesses that both scored a 2 for different reasons.

#### Do I need an FSA API key?

No. The FSA publishes this as open data with no key and no quota. The only rule to know is that it rejects an unfiltered query, so you must set at least one of the filters listed in the Input section.

### ⚖️ Is it legal to scrape food hygiene ratings?

The Food Standards Agency publishes hygiene ratings as open data so the public can check where they eat. This is business information about premises, not personal data, and it comes from the FSA's own API.

Data is published under the Open Government Licence v3.0, so commercial use is permitted with attribution. Apify's [ethical scraping guide](https://blog.apify.com/is-web-scraping-legal/) covers the wider picture.

### 👍 Your feedback

Found a bug, or want a field that is not here yet? Open an issue on the Actor's Issues tab. Requests that make the data more useful get built, and problems get fixed quickly.

### 🔎 You might also like

| Actor | What it does |
|---|---|
| [UK Planning Applications](https://apify.com/spookyweb/uk-planning-applications) | Planning applications from every UK council, tagged by the type of work proposed |
| [UK Insolvency Register Search](https://apify.com/spookyweb/uk-insolvency-register-search) | Individual Insolvency Register search for bankruptcies, IVAs and debt relief orders |
| [Website Contact Scraper](https://apify.com/spookyweb/website-contact-scraper) | Company websites in, one contact record per domain out, with emails and social links |

# Actor input Schema

## `localAuthorityId` (type: `integer`):

Numeric FSA local authority id, for example 1 for Cambridge City or 27 for Welwyn Hatfield. See https://api.ratings.food.gov.uk/Authorities for the full list.

## `postcodeOrAddress` (type: `string`):

Free text address or postcode search, for example CB1 or Cambridge.

## `latitude` (type: `string`):

Latitude for a radius search. Use with longitude and radius.

## `longitude` (type: `string`):

Longitude for a radius search. Use with latitude and radius.

## `radiusMiles` (type: `integer`):

Search radius around the given coordinates.

## `name` (type: `string`):

Search by business name, for example greggs.

## `businessTypeId` (type: `integer`):

Numeric FSA business type id, for example 1 for Restaurant, Cafe or Canteen. See https://api.ratings.food.gov.uk/BusinessTypes for the list.

## `ratingValue` (type: `string`):

Only return businesses with this exact rating, 0 to 5. Applies to the England, Wales and Northern Ireland scheme.

## `actionableOnly` (type: `boolean`):

Keep only businesses that have been told to improve. These are the ones actively in the market for hygiene consultancy, training, pest control or equipment.

## `sortBy` (type: `string`):

How the FSA should order results before paging.

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

Hard cap on results. Each establishment is one billable result.

## `pageSize` (type: `integer`):

Records per API call. Leave as default unless you have a reason.

## Actor input object example

```json
{
  "postcodeOrAddress": "M1 1AE",
  "radiusMiles": 5,
  "ratingValue": "",
  "actionableOnly": false,
  "sortBy": "rating",
  "maxResults": 200,
  "pageSize": 200
}
```

# Actor output Schema

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

One row per item: establishments with their hygiene ratings.

## `runSummary` (type: `string`):

Counts and stop reason for the run.

# 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 = {
    "postcodeOrAddress": "M1 1AE",
    "radiusMiles": 5,
    "maxResults": 200
};

// Run the Actor and wait for it to finish
const run = await client.actor("spookyweb/uk-food-hygiene-ratings").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 = {
    "postcodeOrAddress": "M1 1AE",
    "radiusMiles": 5,
    "maxResults": 200,
}

# Run the Actor and wait for it to finish
run = client.actor("spookyweb/uk-food-hygiene-ratings").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 '{
  "postcodeOrAddress": "M1 1AE",
  "radiusMiles": 5,
  "maxResults": 200
}' |
apify call spookyweb/uk-food-hygiene-ratings --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,spookyweb/uk-food-hygiene-ratings"
        }
    }
}

```

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/yTDuT6xAODNgHZmYG/builds/hoJUqz0WarIiiWdMb/openapi.json
