UK Regulatory Compliance Status Watchdog avatar

UK Regulatory Compliance Status Watchdog

Pricing

from $3.00 / 1,000 entity checked no changes

Go to Apify Store
UK Regulatory Compliance Status Watchdog

UK Regulatory Compliance Status Watchdog

Monitors a fixed watch list of known UK businesses for regulatory status changes — Companies House filing status/dissolution, CQC inspection ratings, and FCA firm registration status. A compliance monitor for suppliers and partners you already know, not a lead-generation tool.

Pricing

from $3.00 / 1,000 entity checked no changes

Rating

0.0

(0)

Developer

joseph fadero

joseph fadero

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Categories

Share

Two modes, two different jobs, two different buyers — on the same Companies House data. Pick one per run.

  • watchlist_monitor (default, original): a compliance monitor for businesses you already know about. You give it a fixed watch list of suppliers, partners, or portfolio companies you already have a relationship with, and it tells you when their regulatory status changes — a dissolution, a CQC rating drop, an FCA firm losing authorisation.
  • prospect_discovery (addendum): a lead-gen feed. You give it a region and/or SIC-code scope, and it finds new signal-worthy companies — fresh incorporations, new director appointments, new charges, SIC-code pivots, unusually high filing activity, or dissolution risk — rather than monitoring entities you already track.

Do not let discovery-mode framing bleed into the compliance-monitoring output existing watchlist_monitor buyers depend on — the two output schemas are entirely separate (ComplianceReport vs. DiscoverySignal), and this README keeps them in their own sections below.

If you're looking to find new UK business prospects but don't need the signal-classification/director-background layer this actor's prospect_discovery mode adds, ../UK%20Local%20Business%20Leads/uk-local-business-leads (Actor 3) is a simpler Google-Maps-plus-Companies-House sourcing tool.

Who it's for

  • watchlist_monitor: compliance/risk teams, insurers, franchisors, or any B2B business that needs to know when a supplier's or partner's regulatory standing changes — before it becomes their problem too.
  • prospect_discovery: sales/lead-gen teams (agencies, B2B vendors, investors) looking for a live feed of newly signal-worthy UK companies in a target sector/region — not a compliance concern at all.

What it checks

SourceWhat it monitorsWatch-list field needed
Companies HouseFiling status, dissolutioncompanyNumber
CQC (care sector)Inspection ratingcqcLocationId
FCAFirm registration/authorisation statusfcaFirmReferenceNumber

Each is a separate, independently-failing module — a missing FCA credential doesn't stop the Companies House or CQC checks from running.

Credentials — read this before running

All three of these are free public APIs, but "free" doesn't mean keyless:

  • Companies House — requires a free registered API key (developer.company-information.service.gov.uk), sent as HTTP Basic Auth. Any watch-list entry with checkCompaniesHouse: true is skipped with a clear message if companiesHouseApiKey isn't set — it doesn't waste a call on a request that would just 401.
  • CQC — some public endpoints work without a key; others are gated behind a free subscription key (api-portal.service.cqc.org.uk). This actor always attempts the call and only asks for cqcSubscriptionKey if the API itself returns a 401/403, rather than assuming one way or the other.
  • FCA — always requires a free email+key credential pair (register.fca.org.uk/Developer), sent as X-Auth-Email/X-Auth-Key. Skipped upfront with a clear message if fcaAuthEmail/fcaAuthKey aren't set.

A gap worth knowing about: CCJs

The output schema's changeType enum includes ccj (County Court Judgment), but this actor never populates it. CCJ data against UK companies is not part of Companies House's free public API — it sits with Registry Trust and commercial credit bureaus behind a paid feed. What Companies House does expose for free is dissolution and general filing-status changes, which is what the companies_house source actually monitors. If CCJ monitoring is a hard requirement, it needs a paid third-party data source layered on top — flagging this now rather than silently shipping a ccj field that never fires.

watchlist_monitor — input schema

{
"mode": "watchlist_monitor",
"watchList": [
{ "companyNumber": "12345678", "checkCompaniesHouse": true, "checkCQC": false, "checkFCA": false },
{ "cqcLocationId": "1-XXXXXXXXX", "checkCQC": true }
],
"alertOnAnyChange": false,
"companiesHouseApiKey": "your-key",
"cqcSubscriptionKey": "your-key (optional)",
"fcaAuthEmail": "your-email",
"fcaAuthKey": "your-key"
}

alertOnAnyChange — off (default) pushes a dataset row only when a status change is actually detected against the last run. On, it pushes a full status row for every watched entity every run, useful for building a complete audit trail rather than just a change log.

watchlist_monitor — output schema

{
"entityId": "string",
"entityName": "string",
"source": "companies_house | cqc | fca",
"previousStatus": "string | null",
"currentStatus": "string | null",
"changeDetected": "boolean",
"changeType": "filing_status | dissolution | cqc_rating_change | fca_registration_change | null",
"checkedAt": "ISO timestamp",
"detailsUrl": "string",
"status": "success | failed | skipped",
"errorMessage": "string | null"
}

previousStatus is null on an entity's first-ever check (nothing to diff against yet) — that's expected, not a failure. Status is persisted between runs in the actor's Key-Value Store (named uk-compliance-status-store), same pattern as Actor 12's BSR history tracking. A real, previously-flagged bug was fixed during this addendum's build: the store was being opened with no name (Actor.openKeyValueStore()), which scopes it to the current run only and silently never persists across runs — meaning previousStatus would have always come back null in production, defeating this actor's entire premise. Confirmed live: two real runs against the real Companies House API, with the same real company, correctly showed previousStatus: null on the first run and previousStatus: "active" on the second.

watchlist_monitor — pricing

EventPrice
Run started£0.05
Entity checked (no change)£0.005
Change detected£0.02
Check failed / skippedfree

Prospect Discovery Mode (addendum)

Reuses the same Companies House REST API and diffing engine as watchlist_monitor — the change is what you're diffing against (a broad region/SIC-code sweep via the real Advanced Search API, advanced-search/companies) instead of a fixed watch list, and what you do with a detected change (surface it as a lead signal, not a compliance alert).

Input schema

{
"mode": "prospect_discovery",
"discoveryFilters": {
"region": "Cambridge",
"sicCodes": ["62012"],
"signalTypes": ["new_incorporation", "director_change", "new_charge", "sic_change", "rapid_filing_activity", "dissolution_risk"],
"minCompanyAge": 0,
"maxCompanyAge": 7,
"maxCompanies": 50
},
"companiesHouseApiKey": "your-key"
}

At least one of region/sicCodes is required — an unscoped sweep genuinely matches hundreds of thousands of companies (confirmed live: sic_codes=62012 alone returns 215,343 hits with no date/region narrowing). signalTypes defaults to ["new_incorporation"] if omitted, since it's the cheapest signal to compute (no extra API calls beyond the sweep itself) — the other five each cost one or more additional real Companies House calls per company, only made when actually requested. maxCompanyAge/minCompanyAge are in days since incorporation and default to a 7-day window, matching this addendum's own worked example. maxCompanies is a safety cap not in the addendum's own field list — added because nothing else bounds how many companies a broad sweep could return; defaults to 50, hard-capped at 200 regardless of what's set.

region is a real-but-imprecise filter — not an exact match. Companies House's own location search parameter is a relevance-ranked text search (confirmed live: location=Cambridge returned ~77% genuine Cambridge results mixed with some from other towns), not a hard filter. This actor uses it as a real pre-filter for efficiency, then applies an exact client-side check against each result's registered-office locality on top — so output is precise, but the region parameter alone, if you were calling Companies House directly, would not be.

Output schema

{
"companyNumber": "string",
"companyName": "string",
"signalType": "new_incorporation | director_change | new_charge | sic_change | rapid_filing_activity | dissolution_risk",
"signalDetectedDate": "ISO timestamp",
"signalStrength": "high | medium | low",
"directorBackground": "string | null",
"plainEnglishSummary": "string",
"detailsUrl": "string"
}

directorBackground and the per-row plainEnglishSummary are populated for new_incorporation and director_change signals where a director's most recent other directorship was found (capped to one prior appointment per officer, to bound API calls on a real sweep) — null when the director has no other appointments (a real, common, correct case for a brand-new company's first-ever director, not a bug). "Relevant experience" means the prior company shares a SIC code with the newly-discovered one.

In addition to the per-row schema above, each run logs one aggregate run-level summary in the addendum's own worked-example style ("34 new technology companies incorporated... 11 have directors with prior technology-company experience") — deterministically built from the run's real signal counts (not an LLM call; this actor has no AI dependency and none was added for this), with sentence structure that genuinely varies by what was actually found, not one fixed template with numbers substituted in.

director_change / sic_change / new_charge are diff-based, same as watchlist_monitor

These three need a real previous snapshot to compare against, stored in a separate named KV store (uk-compliance-discovery-snapshots) keyed per company and per field. A real bug was caught and fixed during this addendum's own live testing, before it shipped: reading and writing that snapshot separately for each requested signal type meant an earlier signal type's write (e.g. sic_change saving an untouched activeDirectorNames: [] default alongside its own real SIC-code update) leaked into a later signal type's "previous state" read within the same run — making a company's very first-ever look register every current director as newly appointed. Fixed by loading the snapshot once per company, diffing all requested fields against that single load, and writing once at the end — with per-field undefined (never captured) kept distinct from an empty array (captured, genuinely empty). Verified live with three real runs: baseline (no false positives), unchanged rerun (still no false positives), and a rerun against a deliberately altered snapshot (correctly detected both a real director_change and sic_change).

new_incorporation, rapid_filing_activity, and dissolution_risk are computed directly each run (not diff-based) — they'll fire consistently for a matching company on every run within their respective windows, which is correct, not a bug.

Pricing

Rides the existing run-started event. One new PPE event: signal-detected — needs pricing configured in the Apify Console alongside the existing three.

Setup note

No browser needed — plain Node actor (apify/actor-node:20), all sources (Companies House, CQC, FCA, and the addendum's Advanced Search/Officers/Charges/Filing-History endpoints) are REST APIs called via axios.

n8n integration

  • Workflow A (trigger): scheduled run against your watch list — weekly for Companies House/FCA, monthly for CQC (inspection ratings change far less often). For prospect_discovery, a daily or weekly sweep of your target region/SIC scope.
  • Workflow B (processing): for watchlist_monitor, alert on any changeDetected: true, routed by changeType — dissolution goes urgent, rating/registration changes go informational. For prospect_discovery, route by signalStrength into a lead queue.