UK Food Business First-Seen Leads
Pricing
$2.50 / 1,000 first observed food businesses
UK Food Business First-Seen Leads
Track FHRS food businesses first observed after your prior complete scan. Filter by council, region, business type and rating. No opening-date claims or private contacts.
Pricing
$2.50 / 1,000 first observed food businesses
Rating
0.0
(0)
Developer
AFK Digital
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
10 days ago
Last modified
Categories
Share
API24 — UK Food Business First-Seen Leads
Source: Netcup adf-netcup-01, /opt/APIFY/API24. Apify Actor: afkdigital/uk-food-business-first-seen-leads. Full cloud validation and pricing are described below.
An independent Apify Actor that monitors the Food Standards Agency Food Hygiene Rating Scheme (FHRS) public register. Designed for food suppliers, POS providers, packaging distributors, and commercial-kitchen service firms looking for businesses first observed in their own monitoring scope.
Accuracy notice: An FHRS entry first seen by this Actor is not proof of a newly opened, newly incorporated, or newly registered business. The FSA Search API does not expose a dependable per-establishment registration/publishing timestamp.
RatingDateis the hygiene inspection/rating date; collectionmeta.extractDateis an API data extraction time, not a business publication date.
Public source, licence, and access
- Official FSA API v2: https://api.ratings.food.gov.uk/help
- Official establishments search spec: https://api.ratings.food.gov.uk/Help/Api/GET-Establishments_name_address_longitude_latitude_maxDistanceLimit_businessTypeId_schemeTypeKey_ratingKey_ratingOperatorKey_localAuthorityId_countryId_sortOptionKey_pageNumber_pageSize
- API v2 requests include header
x-api-version: 2, JSONAccept, and EnglishAccept-Language. - Official FAQ on throttling: https://api.ratings.food.gov.uk/Help/FAQs
- Dataset: https://data.food.gov.uk/catalog/datasets/38dd8d6a-5ab1-4f50-b753-ab33288e3200
- FSA open data and licence: https://www.food.gov.uk/our-data
- Open Government Licence v3.0: https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/
- FSA status notices (including official FHRSID reassignment warnings): https://api.ratings.food.gov.uk/Help/Status
FSA currently permits anonymous read access; there are no credentials to request or protected endpoints to bypass. FHRS is public-sector information under OGL v3; attribution is displayed on every result and in the run summary. Commercial use of the public data is allowed subject to licence conditions; that does not authorize using or exposing personal contact details, making unsupported opening-date claims, or ignoring relevant marketing/privacy law.
FSA throttles requests but publishes no fixed request-per-second rate. This Actor uses sequential calls, a default 1,250 ms minimum gap, and short bounded retries on HTTP 403/429/5xx. Exhaustion fails safely rather than circumventing restrictions. The Actor does not scrape web pages, rotate proxies, or call unofficial endpoints.
What counts as a lead?
- First full scan: Enumerate every page of every selected local authority and apply all filters. The result is a free, portable baseline. There are no paid leads on this run.
- Subsequent full scans: Compare FHRS IDs against the baseline and all previously accepted observations; produce only qualifying unseen IDs. Compare a conservative hashed business-name/address fingerprint to suppress likely FHRSID reassignments.
- An observation is recorded and eligible for the custom charge only once successfully emitted. Excess candidates beyond
resultLimitare retained as pending observations (with their originalfirstObservedAttimestamps). - Repeated existing FHRS IDs, filtered-out businesses, suspected ID reassignments, baseline records, API errors, and incomplete scans are never charged as new leads.
- Source collection inconsistencies, mismatched page totals, repeated IDs across pages, safety-ceiling overruns, and source failures stop the scan before any new leads are emitted.
Scope safety: A new monitor must have localAuthorityId, exact localAuthority name, or exact FSA region. For existing snapshots, filters must be identical; changing a filter requires a fresh baseline. Excessively large scans fail rather than making a claim based on partial results.
Inputs
| Field | Function |
|---|---|
localAuthorityId / localAuthority / region | At least one required; names match the FSA authority catalogue case-insensitively |
businessTypeId | Optional exact FSA business type ID, sent to FSA |
businessType | Optional substring of official FSA business type |
keyword | Optional substring of official business name, not emails/phones |
dateFrom, dateTo | Optional inclusive inspection date (RatingDate) range |
ratingMin, ratingMax | Numeric FHRS rating 0–5, inclusive; pending/non-numeric FHIS results excluded when bounded |
resultLimit | Max new billable results per run (default 100) |
monitorId | Stable unique logical monitor ID; enables persistence across separate Apify runs |
previousSnapshot | Optional exported SNAPSHOT JSON to resume without a persistent monitor; takes precedence |
pageSize | Requested FSA page size; actual maximum is server-capped |
maxPages / maxAuthorities | Fail-safe completion ceilings (defaults 150 and 40) |
requestDelayMs | Sequential FSA pacing, minimum 1,000 ms |
For a repeatable, automatic monitor use the same monitorId on later runs or a stable Apify Task (the task ID is used if no explicit monitorId is provided). A named KV store is created under a one-way hash of that ID combined with Apify's initiating APIFY_USER_ID when available, to avoid cross-user state collisions. Filters are additionally keyed with a SHA-256 scope hash.
When neither monitorId nor an Apify Task ID is present, use the prior run's SNAPSHOT value as previousSnapshot on the next run. Without a previous snapshot, the next run intentionally becomes a new baseline.
Concurrency and anti-repeat safety: A persistent per-user/per-monitor/per-scope Apify Request Queue provides an atomic unique-key claim for each new FHRSID, before the custom paid dataset event. If concurrent runs detect the same new FHRSID, only the first claimant attempts to deliver and charge it; subsequent attempts are suppressed, including attempts with stale snapshots. For best delivery reliability schedule non-overlapping tasks. A hard process crash after a successful claim but before delivery can cause an unbilled skipped observation: the safety model deliberately prefers not charging twice over claiming guaranteed delivery. Refer to RUN-SUMMARY claim fields and the release report.
Output fields
The default Dataset contains two explicitly typed records: recordType: "first-seen-business" for a qualifying paid lead, or a free recordType: "monitor-status" receipt when a successful complete scan finds no billable new business. The latter carries monitorId, status, checkedAt, authoritiesChecked, establishmentsScanned, filterMatches, and resultsEmitted: 0 and does not claim a business opened or was newly registered. Integrations that expect leads only should filter recordType == "first-seen-business". Paid lead records contain these public/derived fields:
fhrsId, businessName, addressLine1–addressLine4, postCode, localAuthority, region, businessType, businessTypeId, ratingValue, ratingNumeric, inspectionDate, sourceExtractAt, firstObservedAt, observationStatus, sourceUrl, matchReason, dataAttribution.
The source URL points directly to the documented official API detail resource: https://api.ratings.food.gov.uk/Establishments/{FHRSID}. No inferred company registration date or publication/update date is fabricated. Phone numbers, personal email addresses, contact details, and local-authority emails are explicitly excluded from the output and snapshot.
Default KV records:
RUN-SUMMARY: status, complete scan metrics, counts of newly observed/migrated/pending rows, charging and source information, or safe failure reason.SNAPSHOT: portable state (format,scopeHash,seenIds, hashed name/address identities,pendingtimestamps, coverage counts).
Local installation, testing and repeat runs
Requires Node.js 22+.
cd /opt/APIFY/API24npm ci --no-audit --no-fundnpm testnpm run smokemkdir -p storage/key_value_stores/defaultcp examples/baseline.json storage/key_value_stores/default/INPUT.jsonAPI24_DISABLE_CHARGING=1 npm startAPI24_DISABLE_CHARGING=1 npm startcat storage/key_value_stores/default/RUN-SUMMARY.json
The example monitors FSA local authority 321 (Isles of Scilly), filtering business type Restaurant. First run: baseline-created, one free monitor-status record and zero chargeable leads. Second unchanged run: completed, one free monitor-status record and zero chargeable leads. The test command npm run smoke uses genuine FHRS records and a controlled omitted-record baseline to demonstrate a genuine-ID first-seen diff without claiming the establishment really just opened.
For an Apify task, paste e.g.:
{"localAuthorityId": 321,"monitorId": "my-scilly-food-leads","businessType": "Restaurant","resultLimit": 50,"maxPages": 10}
For a different region, see examples/region.json. Exact region names are returned by the FSA Authorities endpoint; scanning too many pages/authorities will fail with a clear message and no partial billable results.
Monetisation and release gating
Price: $0.0025 USD per qualifying first-seen FHRS record ($2.50 per 1,000). The Actor uses exactly one Apify pay-per-event event, first-seen-business, for a qualifying new observation delivered to the Dataset. The free first-run baseline, unchanged repeats, filtered results and source failures are not charged. Spend caps are checked before claiming a record. The run summary counts only the configured custom event using the ChargingManager, excluding any synthetic free dataset event.
Verified Apify monetization: The Actor has a PAY_PER_EVENT pricing configuration with only first-seen-business as the configured paid event at $0.0025. The private cloud baseline and identical-repeat runs each charged zero events; a controlled omission test based on a genuine published FHRS ID charged one event, and replaying the old snapshot charged zero. This is not proof that the test business recently opened. Consult the API24 release report for the latest build and concurrency checks. Avoid simultaneous scheduling for the same monitor to reduce missing-delivery risk following abrupt process interruptions.
Local tests disable monetisation with API24_DISABLE_CHARGING=1. This environment variable is not for a monetized production Actor run.
Limitations and integrity
- FSA data may be delayed or corrected. Missing records may be withdrawn or moved, not necessarily closed. Newly observed records may be old businesses absent from an earlier extract.
- A change of FSA
FHRSIDcan reflect a council system migration; the fingerprint check reduces, but cannot eliminate, reassignment false positives. - Scotland FHIS ratings are not generally numeric 0–5; choose an unbounded numeric rating filter to include those categories.
- A bad/old snapshot, altered scope, partial pages, HTTP 403/429 or source schema drift causes a safe failure. No scraping or rate-limit evasions are used.
- No automated collection of personal emails or phone numbers. Users must comply with UK GDPR and electronic-marketing rules when contacting businesses via independently obtained, lawful channels.
- This is a read-only public registry monitor, not a company formation, restaurant permit, new-opening or commercial-contacts database.
Files
src/fhrs.js — official v2 HTTP API, pagination, pacing, error handling
src/monitor.js — input validation, scope, FHRS matching, portable snapshots and lead selection
src/main.js — Apify lifecycle, named snapshot state, output and custom PPE charging
.actor/ — Apify Actor definition, input/dataset/output schema
test/ — mocked boundary/error tests and live FSA test script
reports/ — local evidence; deliberately omitted from Docker/Actor uploads
Store QA repair (2026-10-15)
A small official localAuthorityId: 321 scope and stable demo monitorId are prefilled in the input form. Valid first scans and unchanged repeat scans return a free status receipt, allowing Apify automated QA to verify a non-empty dataset without pretending a lead exists or charging for one. The API still requires an explicit authority/region if called without the UI prefill.