# UK Restaurant & Hospitality Territory Monitor (`dig_stays/uk-hospitality-territory-monitor`) Actor

Find and monitor UK restaurants, cafés, pubs, bars and takeaways by council and postcode district. Export FSA/FHRS names, addresses, ratings, inspection dates and coordinates. Schedule repeat runs to return only newly seen or changed businesses for sales territories, market research and alerts.

- **URL**: https://apify.com/dig\_stays/uk-hospitality-territory-monitor.md
- **Developed by:** [Chris Hopkin](https://apify.com/dig_stays) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 business records

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## UK Restaurant & Hospitality Territory Monitor

Build a clean **UK restaurant and hospitality business list** for the councils and postcode districts you serve. Export official Food Standards Agency (FSA/FHRS) business data, then run the Actor again to return only businesses that are newly seen or whose published details have changed.

Use it for **hospitality lead research, sales territory planning, local market analysis, rating-change alerts, and repeatable food-business monitoring**. Choose your area, run without a source API key, and download the results as CSV, Excel, or JSON.

### What can you do with this Actor?

- **Map a sales territory:** list restaurants, cafés, pubs, bars, takeaways, hotels, or mobile caterers in up to 10 council areas.
- **Narrow the area precisely:** include outward postcode districts such as `M1`, `M2`, or `BS1` without accidentally matching `M10`.
- **Build a trustworthy baseline:** capture the businesses currently published by the official FSA API.
- **Monitor changes automatically:** schedule later runs with the same filters to return only newly seen or changed records.
- **See the evidence:** every changed result includes `changedFields`, `previousValues`, and the official FSA record link.
- **Feed your workflow:** export to spreadsheets or connect the dataset to webhooks, Make, Zapier, n8n, Slack, or another Apify integration.

No proxy, browser, or separate FSA API key is required.

### Who is it for?

| User | Practical use |
|---|---|
| Coffee roasters and food wholesalers | Build café, restaurant, pub, and takeaway prospect lists by delivery area. |
| Catering-equipment and fit-out suppliers | Map hospitality businesses around a showroom, depot, or sales representative. |
| Cleaning, pest-control, and compliance providers | Monitor published rating changes and prioritize follow-up research. |
| Agencies and local publishers | Maintain structured hospitality directories and local-market datasets. |
| Property and market researchers | Compare the hospitality mix across councils and postcode districts. |
| Multi-site operators | Watch selected territories for newly observed businesses and changes to existing records. |

### Quick start: Manchester city centre

Paste this into the Actor input and click **Start**:

```json
{
  "localAuthorities": ["Manchester"],
  "businessTypeIds": [1, 7843, 7844],
  "postcodeDistricts": ["M1"],
  "excludeNameContains": [],
  "resetBaseline": false,
  "maxRecords": 10000
}
```

The first successful run returns a **baseline** of matching restaurants/cafés, pubs/bars, and takeaways. Run the same input later and the dataset contains only records that are newly seen or changed since the last successful snapshot.

### More input examples

#### Monitor several council areas

Useful for a supplier or sales team covering a wider territory:

```json
{
  "localAuthorities": ["Manchester", "Salford", "Trafford"],
  "businessTypeIds": [1, 7843, 7844],
  "postcodeDistricts": [],
  "excludeNameContains": [],
  "maxRecords": 20000
}
```

#### Focus on selected postcode districts

```json
{
  "localAuthorities": ["Bristol"],
  "businessTypeIds": [1, 7843],
  "postcodeDistricts": ["BS1", "BS2", "BS3"],
  "excludeNameContains": [],
  "maxRecords": 10000
}
```

#### Apply your own name exclusions

```json
{
  "localAuthorities": ["Manchester"],
  "businessTypeIds": [1],
  "postcodeDistricts": ["M1", "M2"],
  "excludeNameContains": ["costa", "starbucks"],
  "maxRecords": 10000
}
```

Name exclusions are simple text filters supplied by you. They do not prove that the remaining businesses are independent or identify business ownership.

### What data do you get?

Each returned record includes:

| Field | Example or meaning |
|---|---|
| `changeType` | `baseline`, `newly_seen`, or `changed` |
| `businessName` | Published trading name |
| `businessType` / `businessTypeId` | Restaurant/Cafe/Canteen, Pub/bar/nightclub, Takeaway, and other FSA types |
| `address`, `postcode`, `postcodeDistrict` | Published location and exact outward postcode |
| `localAuthority` | FSA council name |
| `rating`, `scheme`, `ratingDate` | Published hygiene rating, scheme, and inspection date when available |
| `newRatingPending` | Whether the FSA record says a new rating is pending |
| `latitude`, `longitude` | Published coordinates when available |
| `changedFields` | Fields that differ from the previous successful snapshot |
| `previousValues`, `previousRating` | Evidence of the earlier published values |
| `observedAt` | When this Actor observed the record |
| `sourceUrl` | Direct link to the official FSA business record |
| `signalNote` | Plain-language guidance on what the signal does and does not establish |

Example output:

```json
{
  "fhrsId": "1234567",
  "businessName": "Example Cafe",
  "businessType": "Restaurant/Cafe/Canteen",
  "businessTypeId": 1,
  "address": "10 Example Street",
  "postcode": "M1 1AA",
  "postcodeDistrict": "M1",
  "localAuthority": "Manchester",
  "rating": "5",
  "ratingDate": "2026-08-20",
  "changeType": "changed",
  "changedFields": ["rating"],
  "previousValues": { "rating": "3" },
  "previousRating": "3",
  "observedAt": "2026-09-08T12:00:00.000Z",
  "sourceUrl": "https://ratings.food.gov.uk/business/1234567"
}
```

The example is illustrative. Actual fields come from the official source and may be empty when the FSA does not publish a value.

### How change monitoring works

1. The first successful run saves a complete baseline for the exact territory filters.
2. A later run collects the same territory again and compares it with that saved snapshot.
3. Unchanged businesses are omitted.
4. Newly seen and changed records are returned with comparison evidence.
5. The saved baseline advances only after the complete scan and output succeed.

Use an Apify schedule to run daily, weekly, or monthly. Keep the territory filters identical between comparison runs and avoid overlapping runs for the same territory. To start again, set `resetBaseline` to `true` for one run.

#### What the signals mean

| Signal | Meaning |
|---|---|
| `baseline` | Present on the first scan. This is an existing record, not a new-opening lead. |
| `newly_seen` | Absent from the saved snapshot and present now. It may be an opening, delayed publication, or a record entering the selected filters. |
| `changed` | One or more tracked fields changed. Inspect `changedFields` and `previousValues` for the evidence. |

`newly_seen` is **not a verified opening or registration date**. A changed name does not establish new ownership, and a missing record is not labelled closed. FSA publication can lag real-world events.

### Filters and business-type IDs

- `localAuthorities`: 1–10 exact FSA council names. Use the [official council directory](https://api.ratings.food.gov.uk/Authorities/basic).
- `businessTypeIds`: defaults to restaurants/cafés (`1`), pubs/bars (`7843`), and takeaways (`7844`). Other useful IDs include hotels (`7842`) and mobile caterers (`7846`). An empty list includes all published business types.
- `postcodeDistricts`: exact outward codes such as `M1` or `BS1`. Empty includes all postcodes within the selected councils.
- `excludeNameContains`: optional case-insensitive name fragments.
- `maxRecords`: safety cap applied before postcode and name filtering; 10,000 by default and 50,000 maximum.
- `resetBaseline`: exports all current matches and replaces the saved baseline for that exact territory.

If the source territory exceeds `maxRecords`, the run fails instead of returning and saving a misleading partial snapshot.

### Export and integrations

Results are stored in the default Apify dataset. You can:

- Download CSV, Excel, JSON, XML, RSS, or JSONL from the run page.
- Connect a Google Sheet or downstream database.
- Trigger a webhook when a scheduled run finishes.
- Send newly seen or changed records to Make, Zapier, n8n, Slack, or your own application.
- Run the Actor through Apify API, CLI, JavaScript, Python, or MCP integrations.

API example:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/dig_stays~uk-hospitality-territory-monitor/runs?waitForFinish=300" \
  -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "localAuthorities": ["Manchester"],
    "businessTypeIds": [1, 7843, 7844],
    "postcodeDistricts": ["M1"]
  }'
```

### Pricing

The Actor costs **$0.01 per returned business record**, plus Apify platform usage.

| Returned records | Event charge |
|---:|---:|
| 100 | $1.00 |
| 500 | $5.00 |
| 1,000 | $10.00 |

A baseline run charges for every matching record it returns. Later runs with unchanged filters charge the event fee only for returned changes. A no-change run has no `business-record` fee, although platform usage still applies.

The Actor checks the run's maximum-charge limit before writing results. If the limit cannot cover the complete output, it fails without charging for or saving partial results.

### Frequently asked questions

#### Does this find newly opened restaurants?

It finds businesses that are newly present in the official dataset compared with your saved snapshot. That is a useful research signal, but it is not proof of an opening date. Confirm promising leads independently before outreach or publication.

#### Does it include business emails, phone numbers, or owner names?

No. The Actor returns the public FSA fields listed above. It does not guess contacts, identify owners, or present council contact details as business contacts.

#### Which parts of the UK are covered?

The FSA/FHRS service covers England, Wales, and Northern Ireland. Scotland operates a separate food-hygiene information service and is not included by this Actor.

#### Why did a repeat run return zero results?

That normally means none of the tracked fields changed since the last successful run for those filters. Check `SUMMARY` in the run's key-value store for scanned, matched, and emitted counts.

#### Can I change the territory later?

Yes. Every exact combination of councils, business types, postcode districts, and exclusions has its own saved comparison state. Use `resetBaseline: true` when you intentionally want to replace the baseline.

#### What happens if the FSA API changes during a scan?

The Actor detects inconsistent totals, duplicate records, incomplete pagination, request failures, and source-scan caps. It fails rather than saving a snapshot it knows is incomplete. The upstream API is not transactionally frozen, so an equal-count swap during pagination cannot always be detected.

### Storage and reliability

The default dataset contains the returned baseline or changes. `SUMMARY` reports scan counts and comparison mode. `SNAPSHOT` stores the complete snapshot for that run, while the named key-value store `uk-hospitality-territory-monitor-state-v1` keeps the latest successful state for each exact territory.

Bounded retries handle temporary source failures. A failed scan never replaces the saved comparison state.

### Data source and licence

Data comes from the [Food Standards Agency ratings service](https://ratings.food.gov.uk/open-data) through the [official v2 API](https://api.ratings.food.gov.uk/Help/Index). It contains public-sector information licensed under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/).

This Actor is not affiliated with or endorsed by the FSA. Published hygiene ratings are historical inspection results and should not be presented as a real-time safety determination.

### Support and feature requests

Use the public **Issues** tab for questions, bug reports, or feature requests. Include the run ID and the council filters you used so the problem can be reproduced quickly. Do not post API tokens or private data.

# Actor input Schema

## `localAuthorities` (type: `array`):

Enter exact FSA council names such as Manchester, Bristol, Salford, or Trafford. Add 1–10 councils. See https://api.ratings.food.gov.uk/Authorities/basic for the official names.

## `businessTypeIds` (type: `array`):

FSA IDs: 1 restaurants/cafes; 7843 pubs/bars; 7844 takeaways; 7842 hotels; 7846 mobile caterers. Empty means every published type.

## `postcodeDistricts` (type: `array`):

Enter exact outward codes such as M1, M2, or BS1. M1 does not match M10. Leave empty to include all postcodes in the selected councils.

## `excludeNameContains` (type: `array`):

Optional case-insensitive name fragments. This is a user-defined filter, not verified independent-business classification.

## `resetBaseline` (type: `boolean`):

Export every matching record as a new baseline and replace the saved comparison state for this exact territory.

## `maxRecords` (type: `integer`):

Safety cap before postcode/name filtering. If exceeded, the run fails without publishing a misleading partial snapshot. Narrow the territory or raise this cap.

## Actor input object example

```json
{
  "localAuthorities": [
    "Manchester"
  ],
  "businessTypeIds": [
    1,
    7843,
    7844
  ],
  "postcodeDistricts": [],
  "excludeNameContains": [],
  "resetBaseline": false,
  "maxRecords": 10000
}
```

# Actor output Schema

## `businessRecords` (type: `string`):

Baseline, newly seen, and changed hospitality business records from the default dataset.

## `summary` (type: `string`):

Counts, run mode, and comparison status for this scan.

## `snapshot` (type: `string`):

The complete territory snapshot saved by this 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 = {
    "localAuthorities": [
        "Manchester"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dig_stays/uk-hospitality-territory-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 = { "localAuthorities": ["Manchester"] }

# Run the Actor and wait for it to finish
run = client.actor("dig_stays/uk-hospitality-territory-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 '{
  "localAuthorities": [
    "Manchester"
  ]
}' |
apify call dig_stays/uk-hospitality-territory-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dig_stays/uk-hospitality-territory-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/e5jnIm1cQZL4g1Myc/builds/tVjTahllS3fqAOt1C/openapi.json
