Companies House Monitor — filings, officers, PSC changes avatar

Companies House Monitor — filings, officers, PSC changes

Pricing

Pay per usage

Go to Apify Store
Companies House Monitor — filings, officers, PSC changes

Companies House Monitor — filings, officers, PSC changes

Know the moment a UK company you care about files at Companies House, changes a director, changes a PSC, changes its name or is dissolved. Give it company numbers or names; it watches filing history, officers, PSCs and the profile, and emits only what changed — with the previous value.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

Daniel James

Daniel James

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

0

Monthly active users

9 days ago

Last modified

Share

Companies House Monitor

Know the moment a company you care about files, changes officers or changes PSCs.

There are dozens of ways to look up a UK company. This is not one of them. This actor watches a list of companies and tells you what changed since last time — a new set of accounts, a director appointed, a director resigned, a person with significant control ceasing, a name change, a dissolution — with the previous value attached so the alert is actionable on its own.

Straight from the official Companies House Public Data API. No scraping, no browser, no proxy.

Who this is for

  • Accountants — you have 400 clients and a filing deadline calendar. Get told the night a client's confirmation statement lands, or the night one of them appoints a director you have never heard of.
  • Lenders and credit teams — a borrower quietly changing its PSC, changing its name, or slipping into liquidation is the event you needed to know about on the day, not at the next review.
  • Compliance and KYB — ongoing monitoring is the part of KYB everyone skips because it means re-checking a spreadsheet by hand. Run this nightly against your book instead.
  • Procurement and supplier risk — a supplier's directors all resigning is a signal. So is a charge, a name change, or a dissolution notice.
  • Journalists and researchers — one schema, stable IDs, joinable across runs.

What it does

Give it company numbers, or company names, and pick what to watch:

trackWatches
filingsfiling history — accounts, confirmation statements, appointments, capital, charges
officersappointments and resignations
pscpersons with significant control — notified, ceased, changed
profilecompany name, status, dissolution, next-due dates
allall four (the default)

Every row comes back in one schema, whichever part of the register it came from:

{
"id": "3f5a1c9e0b7d4a2f8c6e1b3d5a7f9c2e4b6d8a01",
"companyNumber": "00445790",
"companyName": "TESCO PLC",
"companyStatus": "active",
"category": "filings",
"itemId": "MzM1Njk4NDgyOGFkaXF6a2N4",
"description": "accounts-with-made-up-date",
"date": "2026-03-31",
"status": "filed",
"filingType": "AA",
"filingCategory": "accounts",
"companyUrl": "https://find-and-update.company-information.service.gov.uk/company/00445790",
"links": {
"selfUrl": "https://api.company-information.service.gov.uk/company/00445790/filing-history/MzM1Njk4NDgyOGFkaXF6a2N4"
},
"query": "Tesco"
}

The same shape, from the officers register:

{
"companyNumber": "00445790",
"companyName": "TESCO PLC",
"category": "officers",
"description": "FIXTURE, Jane Elizabeth, director",
"date": "2019-05-01",
"status": "active",
"officerName": "FIXTURE, Jane Elizabeth",
"officerRole": "director",
"appointedOn": "2019-05-01",
"resignedOn": null,
"dateOfBirthYear": 1975
}
  • Stable IDssha1(companyNumber:category:itemId), built on the register's own identifier for the item (a transaction id, an appointment id, a PSC notification id). The same filing always produces the same id, so diffs and joins downstream just work, run after run.
  • companyName and companyStatus on every row — including filing and officer rows. An alert that says "a director resigned" is useless without the company's name next to it, and you should not need a second lookup to get it.
  • query on every row tells you which of your inputs produced it.
  • Names resolve automatically. Type Tesco PLC and it is resolved through the official company search — and the match it picked is written to the log, because a silent best guess is how a monitor ends up watching the wrong company. Supply the number when you need certainty.
  • Short company numbers are padded. 445790 becomes 00445790. Unpadded numbers 404 against the API, and every spreadsheet in the country holds them unpadded.

Monitor mode (changesOnly) — the actual product

Turn a watchlist into an alert feed. State is remembered between runs in the named key-value store companies-house-state, and only movement is emitted:

changeTypeMeaning
newa filing that was not there before; an officer newly appointed; a PSC newly notified
updatedsomething changed on an existing record — a director now shows as resigned, a PSC as ceased, the company as dissolved or renamed
removedthe record no longer comes back from the register at all

Updated rows carry the before and the after, which is the part that makes an alert worth having:

{
"changeType": "updated",
"changedFields": ["status"],
"category": "officers",
"companyName": "TESCO PLC",
"description": "FIXTURE, Jane Elizabeth, director",
"previousStatus": "active",
"status": "resigned",
"resignedOn": "2026-08-14"
}

A company changing its name comes through on the profile row with previousCompanyName filled in — one of the highest-value signals on the whole register, and one a name-keyed watchlist misses entirely.

The first run emits everything once, as the baseline. Every run after that is quiet unless something moved.

Two false alarms this actor refuses to raise

  1. Filings are never reported as removed. The filing history is append-only. A filing that is no longer in the fetched window has scrolled past maxFilings — it has not been withdrawn from the register. Telling an accountant a client had retracted its accounts would be the worst thing this actor could say, so it does not say it, and a test enforces that.
  2. Narrowing track never mass-reports the rest as gone. Run once with track: all and then with track: filings, and a naive monitor announces that every director and every PSC has vanished from the register. State is category-aware: untracked records are carried forward untouched, and only a category this run actually fetched can produce a removed row.

Getting your free API key (2 minutes, no payment step)

The Companies House Public Data API requires a key on every request. It is free.

  1. Go to https://developer.company-information.service.gov.uk/ and sign in (or create a Companies House account — the same one used for filing).
  2. Open Manage applicationsCreate an application. Give it a name; choose the Live environment.
  3. In the application, choose Create new keyREST API key (sometimes labelled "API key").
  4. Copy the key into this actor's apiKey field. It is stored as a secret input.

It must be a REST API key. The hub also issues stream keys (for the streaming API) and OAuth web clients (for acting on behalf of a signed-in user). Neither authenticates these endpoints, and pasting one produces a 401 that looks exactly like a wrong key — which is why this actor's 401 message says so in words.

Under the bonnet the key is sent as HTTP Basic with the key as the username and a blank password, exactly as Companies House documents it. The actor's test suite asserts its header matches Companies House's own published example byte for byte.

Input

FieldExampleNotes
apiKeyrequired, secret. Free — see above
companies00445790, SC123456, Tesco PLCrequired, one per line. Numbers or names
trackallall, filings, officers, psc, profile
changesOnlyfalsemonitor mode, as above
maxCompanies25per run — keeps a long watchlist inside the rate limit
maxFilings25how far back into the filing history each run looks

Rate limits, and how this actor behaves inside them

Companies House publishes a limit of 600 requests in any 5-minute period, returns 429 when you exceed it, and reserves the right to ban an application without notice for regularly exceeding or trying to bypass it.

This client therefore paces itself below the limit rather than sprinting into 429s: one request every 550 ms, process-wide, which works out at roughly 545 requests per 5 minutes. It honours Retry-After exactly when the API does send a 429, and it backs off rather than hammering on 5xx.

Budget your runs. track: all costs 4 requests per company (profile, filings, officers, PSC); a single narrower track costs 2 (the profile is always fetched, because every row carries the company's name and status). A name that has to be resolved costs 1 more, once. So:

WatchlisttrackRequestsWall time
25 companiesall100~1 minute
25 companiesfilings50~30 seconds
100 companiesall400~4 minutes

The limit is per API key, not per run — so if you schedule several runs, stagger them, and remember anything else you have built on the same key is spending the same 600.

Two things about this data that will bite you elsewhere

1. A filing's description is an enumeration key, not a sentence. Companies House sends accounts-with-made-up-date, not "Accounts made up to 31 December 2025". The sentence lives in the companieshouse/api-enumerations file and is interpolated client-side. This actor emits the key verbatim — resolve it yourself if you want the prose. It does not fabricate a sentence from the key, because a fabricated sentence that looks official is worse than an honest identifier. filingType (AA, AP01, CS01, SH03) and filingCategory (accounts, officers, capital, …) are there for filtering and are stable.

2. A 404 from the PSC endpoint is normal. A company that has never filed PSC information has no PSC resource at all. This actor reports "no PSC records" and carries on. Anything that treats that as an error will mark healthy companies as failed on every single run.

Personal data — what this actor deliberately does not publish

The officer and PSC registers are, by design of the public register, records about named natural persons. Publication by Companies House is lawful; republishing every field of it is a separate decision, and this actor makes a conservative one.

Emitted: name, role / PSC kind, natures of control, appointment / resignation / notification / cessation dates, and the year of birth.

Never emitted: the service address (which for a great many small companies is the person's home), nationality, occupation, country of residence, former names, the cross-company officer identifier that follows a person between companies, and the filing description_values object — which for appointment filings carries the officer's name.

Two details worth stating plainly:

  • Companies House already suppresses the day of an officer's date of birth and publishes month + year. This actor reduces it again to the year alone. The year is enough to tell two directors of the same name apart, which is the only thing a business monitor legitimately needs it for; month + year is a much stronger token for matching a person against other datasets.
  • Super-secure PSCs — people whose details the register withholds for their personal safety — still produce a row, so you can see one appear or cease, but with no name, and none is invented.

This is enforced by construction: every row is built field by field from an allow-list, with no object spread anywhere in the mapper, so a new personal field appearing in a future API version cannot leak by default. Tests assert that planted addresses, nationalities, occupations, former names and birth months never reach the output.

The company's registered office IS emitted, on the profile row — that is the company's official address for service and a company attribute, not an officer's personal one. Note that for a single-director company it is frequently that director's home; Companies House publishes no flag distinguishing the two, so no automated redaction is possible and none is claimed.

Licence and terms

Companies House publishes this data through its own public API and this actor uses it as documented, within the published rate limit. No Open Government Licence statement was found on any Companies House page read during development, so none is asserted here — if you intend to republish the data rather than consume it, confirm the terms with Companies House yourself. See tests/fixtures/SOURCES.md for exactly what was and was not verified.

Running it locally

npm install
npm test # fixture-driven, no network, no key needed
APIFY_CH_KEY=your-key npm test # additionally runs one live smoke call
npm start # reads storage/key_value_stores/default/INPUT.json

Every claim this actor makes about the API — the auth mechanism, the rate limit, the endpoints, the 404-on-PSC behaviour, the enumeration-key description — is recorded with its evidence in tests/fixtures/SOURCES.md, including the things that could not be verified and what was done about them instead.