# Companies House Scraper: UK Directors, Officers & PSCs (`datagleaner/uk-company-directors`) Actor

Directors, secretaries and owners (PSCs) of any UK company from Companies House, by name or number. No API key. $0.006 per company, all officers included. Also returns status, SIC codes, incorporation date and registered office.

- **URL**: https://apify.com/datagleaner/uk-company-directors.md
- **Developed by:** [Data Gleaner](https://apify.com/datagleaner) (community)
- **Categories:** Lead generation, Business, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$6.00 / 1,000 company with officers

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## UK Company Directors: Companies House Officers & PSCs

Answers "who are the directors of <UK company>?", "who owns this UK company?", "Companies House officers lookup" and "UK director lookup" for any company on the UK register, by company name or company number. $0.006 per company, all officers included.

Give it UK company numbers, Companies House URLs or plain company names. Each company comes back as one row with its **current directors and secretaries**, its **persons with significant control (PSCs)**, plus company status, company type, SIC codes, incorporation date and registered office address. No Companies House API key, no login. The fields are the same on every row, so AI agents, KYC checks and due-diligence pipelines can use it as well as people.

### What it returns

For every company:

- **Officers**: name, role (Director, Secretary, LLP Member and so on), appointed and resigned dates, month and year of birth, nationality, country of residence, correspondence address, identity verification status, and a link to the officer's other appointments. Corporate officers also get where they are registered and their registration number.
- **Persons with significant control**: name, kind (individual, corporate entity or legal person), natures of control (for example "Ownership of shares - 75% or more"), notified and ceased dates, nationality, residence and month and year of birth for individuals, legal form and registration number for companies. PSC statements (such as "no registrable person") and exemptions (such as a listing on a UK regulated market) are returned too, so an empty PSC list always has a reason.
- **Company**: number, name, status (Active, Dissolved, Liquidation...), type, incorporation and dissolution dates, registered office as one line and split into parts, SIC codes with descriptions, previous names.
- **Summary columns**: the first 3 current directors (`topDirectors`), the number of current directors (`activeDirectorCount`) and the current PSC names (`pscNames`), so one table answers the question at a glance.

The data comes from the public Companies House register website, which serves the same information as the official API without needing a key.

### Use cases

- An AI agent answering "who are the directors of Monzo?" or "who controls this supplier?".
- KYC and onboarding: confirm a UK business's officers, owners and status before signing it up.
- Due diligence and M\&A screening: officers, beneficial owners and SIC codes for a target list.
- B2B lead generation: the decision makers of UK companies by name, with their roles and appointment dates.
- CRM enrichment: turn a column of UK company names into numbers, statuses, addresses and directors.

### How it works

1. A company number or Companies House URL is used as is. A name is searched on Companies House and matched: **exact** (same name ignoring case and punctuation), **normalized** (same once Limited, Ltd or PLC are dropped, so `Monzo Bank` finds MONZO BANK LIMITED) or **fuzzy** (the closest similar name). Each row reports `matchType` and `matchConfidence`. Ties go to an active company.
2. The company overview page gives status, type, dates, address and SIC codes.
3. The officers pages give every officer. Companies House lists 35 per page; the Actor follows the pages. Current officers come first, so with `includeResigned` off it stops as soon as all current officers are in.
4. The PSC page gives owners and controllers, statements and exemptions.

That is 3 requests per company (4 for a name), spaced 1 second apart by default.

### Input

| Field | Meaning |
|---|---|
| `companies` | Company numbers (`00445790`, `SC045551`, `OC399026`), Companies House URLs, or company names. One per line. |
| `includeResigned` | Also return resigned officers (default false). |
| `includePsc` | Return persons with significant control (default true). |
| `maxCompanies` | Stop after this many companies (default 50). |
| `requestDelaySecs` | Pause between requests (default 1, minimum 0.5: never more than 2 requests a second). |
| `proxyConfiguration` | Optional. No proxy by default. |

Leave `companies` empty to run 5 well-known sample companies (Tesco, Monzo Bank, Rolls-Royce Holdings, BT Group, Revolut), about 20 seconds.

```json
{
  "companies": ["00445790", "Monzo Bank", "https://find-and-update.company-information.service.gov.uk/company/08804411"],
  "includeResigned": false,
  "includePsc": true
}
```

### Output

One row per company. Fields that are not on the register are empty, never invented.

```json
{
  "input": "Monzo Bank",
  "companyNumber": "09446231",
  "companyName": "MONZO BANK LIMITED",
  "status": "Active",
  "companyType": "Private limited Company",
  "incorporatedOn": "2015-02-18",
  "dissolvedOn": null,
  "registeredOfficeAddress": "Broadwalk House, 5 Appold Street, London, England, EC2A 2AG",
  "registeredOfficeAddressParts": {"addressLine1": "Broadwalk House", "addressLine2": "5 Appold Street", "locality": "London", "region": null, "country": "England", "postalCode": "EC2A 2AG"},
  "sicCodes": [{"code": "64191", "description": "Banks"}, {"code": "64999", "description": "Financial intermediation not elsewhere classified"}],
  "previousNames": [{"name": "FOCUS FS LIMITED", "from": "2015-02-18", "to": "2016-10-21"}],
  "topDirectors": ["BURBIDGE, Eileen", "DIAS, Valerie Michelle", "KEELEY, Rupert Graham"],
  "activeDirectorCount": 7,
  "activeOfficerCount": 8,
  "officerAppointmentsTotal": 30,
  "officers": [
    {
      "name": "BURBIDGE, Eileen",
      "surname": "BURBIDGE",
      "givenNames": "Eileen",
      "role": "Director",
      "status": "Active",
      "officerType": "individual",
      "appointedOn": "2015-04-21",
      "resignedOn": null,
      "birthMonthYear": "1971-06",
      "nationality": "British",
      "countryOfResidence": "United Kingdom",
      "correspondenceAddress": "Broadwalk House, 5 Appold Street, London, England, EC2A 2AG",
      "identityVerified": false,
      "identityVerificationDueOn": "2026-11-25",
      "appointmentsUrl": "https://find-and-update.company-information.service.gov.uk/officers/ssSVue1XDlQnQSitrtOoyTIe5s0/appointments"
    }
  ],
  "pscNames": ["Monzo Bank Holding Group Limited"],
  "psc": [
    {
      "name": "Monzo Bank Holding Group Limited",
      "kind": "corporate-entity",
      "status": "Active",
      "naturesOfControl": ["Ownership of shares – 75% or more", "Ownership of voting rights - 75% or more", "Right to appoint or remove directors"],
      "notifiedOn": "2023-09-12",
      "ceasedOn": null,
      "legalForm": "Private Limited Company",
      "registrationNumber": "14785367"
    }
  ],
  "pscStatements": [],
  "pscExemptions": [],
  "matchType": "normalized",
  "matchConfidence": 0.95,
  "companyUrl": "https://find-and-update.company-information.service.gov.uk/company/09446231",
  "outcome": "ok",
  "error": null,
  "scrapedAt": "2026-10-09T15:30:26+00:00"
}
```

(The example is shortened to one officer and one PSC.) A name with no match, or a number that does not exist, gets a row with `outcome: "not-found"`, the reason in `error` and, for a name, the top 3 search results in `candidates`. Those rows are free.

The dataset has three views: **Companies** (one row per company with status, first 3 directors and PSC names), **All officers** (one row per officer) and **Persons with significant control** (one row per PSC).

### Pricing

Pay per company, one event:

- **`company-with-officers`: $0.006** (from 21 October 2026) for each company returned with at least one officer. All of its officers and PSCs are included, however many there are.
- A company not found, or with no officers to return, is **free**.

**Worked example.** 1,000 UK companies with an average of 5 directors each cost 1,000 x $0.006 = **$6.00**. An Actor that bills $0.004 per company plus $0.002 for each flat officer record would charge $14.00 for the same list, because the 5,000 officers add $10.00. Here every officer is already inside the company row.

Set a maximum total charge on the run and the Actor stops cleanly when it is reached.

### What to expect

Measured on a local test of 10 company numbers and 5 names: every input matched, all 14 distinct companies returned officers (137 current officers in all), names, roles, appointment dates and addresses were filled for 100% of officers, and month of birth, nationality and residence for 90% (secretaries and corporate officers have none). Listed PLCs are exempt from PSC rules, so they return a PSC exemption instead of a PSC list. A run of 15 inputs took about a minute.

### Limits

- **Occupation is not returned.** The public register website no longer shows officer occupations; only the keyed Companies House API does.
- Dates of birth are month and year only, as Companies House publishes them.
- Officers of a dissolved company stay listed as they were on the day it was dissolved.
- Names are matched against Companies House search; a very generic name ("Smith Limited") may match a different company than you meant. Check `matchType` and `matchConfidence`, or use the company number.
- The same company given twice (for example as a number and a name) is returned and charged once.
- Pacing is 1 request a second by default and never above 2 a second, so 1,000 companies take roughly an hour.

### Use with Python

```python
## pip install apify-client
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("datagleaner/uk-company-directors").call(run_input={
    "companies": ["00445790", "Monzo Bank"],  # 2 x $0.006 = $0.012
})
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item["companyName"], item["status"], item["topDirectors"], item["pscNames"])
```

### Use with JavaScript / Node.js

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('datagleaner/uk-company-directors').call({
    companies: ['Revolut Ltd', '09446231'],
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
    console.log(item.companyName, item.officers.map((o) => `${o.name} (${o.role})`));
}
```

### Use it from n8n, Make, Zapier or an AI agent

Actor ID: `datagleaner/uk-company-directors`

Minimal input:

```
{"companies": ["00445790", "Monzo Bank"]}
```

Each tool below runs this Actor with your own Apify API token.

- **n8n:** add the **Apify** node (`@apify/n8n-nodes-apify`). On n8n Cloud you install it from the community node registry. Choose **Run an Actor and get dataset**, set Actor to `datagleaner/uk-company-directors` and paste the input above.

- **Make:** use the Apify app's **Run an Actor** module, then **Get Dataset Items** to read the results. **Watch Actor Runs** can trigger a scenario when a run finishes.

- **Zapier:** use the Apify action **Run Actor**, then the search **Fetch dataset items**. The trigger **Finished Actor run** starts a Zap when a run ends.

- **AI agents (MCP):** connect to `https://mcp.apify.com/?tools=datagleaner/uk-company-directors`. In Claude Code:

  ```
  claude mcp add --transport http apify "https://mcp.apify.com/?tools=datagleaner/uk-company-directors"
  ```

  Then run `/mcp` to sign in to Apify in your browser. Other clients can sign in with OAuth or send the header `Authorization: Bearer YOUR_APIFY_TOKEN`. Clients that run local MCP servers can use Apify's package (`@apify/actors-mcp-server`, run with `npx -y` and `APIFY_TOKEN` set) instead. Then ask the agent in plain words, for example:

  > Who are the current directors and the persons with significant control of Octopus Energy Limited? Give me their roles and appointment dates.

- **LangChain (Python):**

```python
## pip install langchain-apify, then set APIFY_TOKEN in your environment
import json
from langchain_apify import ApifyActorsTool
tool = ApifyActorsTool("datagleaner/uk-company-directors")
result = tool.invoke({"run_input": json.loads('{"companies": ["00445790", "Monzo Bank"]}')})
```

### FAQ

**How do I find the directors of a UK company?** Put the company name or number in `companies`. Each row lists the current directors and secretaries with their roles and appointment dates; `topDirectors` shows the first three.

**How do I find who owns a UK company?** Leave `includePsc` on. The `psc` list gives each person or company with significant control and the share of ownership or votes they hold. Listed PLCs are exempt and say so in `pscExemptions`.

**Do I need a Companies House API key?** No. The Actor reads the public register website.

**Can I search by company name?** Yes. The name is searched on Companies House and the best match is taken; `matchType` and `matchConfidence` tell you how close it was. Use the company number when you need certainty.

**Can I get former directors?** Yes, turn on `includeResigned`. Each officer then carries `status` and `resignedOn`.

**Does it cover Scottish, Northern Irish companies and LLPs?** Yes: any number on the UK register, such as `SC...`, `NI...` and `OC...`.

### Responsible use

This Actor reads the public Companies House register only. Director and PSC data is **personal data**: names, month and year of birth, nationality, residence and addresses of real people. Your use of it must comply with UK GDPR and the Data Protection Act 2018, including having a lawful basis, keeping it accurate and secure, and honouring people's rights. Do not use it for unsolicited marketing without meeting PECR rules, or for harassment or profiling of individuals. Companies House does not check the accuracy of what companies file.

# Actor input Schema

## `companies` (type: `array`):

UK companies, one per line: a company number (`00445790`, `SC045551`, `OC399026`), a Companies House URL, or a company name (`Monzo Bank`). A name is searched on Companies House and the closest match is taken; each row reports `matchType` and `matchConfidence`. Leave empty to run 5 sample companies.

## `includeResigned` (type: `boolean`):

Also return officers who have resigned, with their resignation date. Off by default: only current directors and secretaries are returned.

## `includePsc` (type: `boolean`):

Return the company's owners and controllers (PSCs) with their nature of control, plus any PSC statements or exemptions. Adds one request per company. The price is the same either way.

## `maxCompanies` (type: `integer`):

Stop after this many companies from the list.

## `requestDelaySecs` (type: `number`):

Pause between requests to Companies House. The Actor never goes faster than 2 requests a second, to stay polite to a public service.

## `proxyConfiguration` (type: `object`):

Optional. Defaults to no proxy; Companies House serves datacenter IPs.

## Actor input object example

```json
{
  "companies": [
    "00445790",
    "Monzo Bank"
  ],
  "includeResigned": false,
  "includePsc": true,
  "maxCompanies": 50,
  "requestDelaySecs": 1
}
```

# Actor output Schema

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

No description

# 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 = {
    "companies": [
        "00445790",
        "Monzo Bank"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datagleaner/uk-company-directors").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 = { "companies": [
        "00445790",
        "Monzo Bank",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("datagleaner/uk-company-directors").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 '{
  "companies": [
    "00445790",
    "Monzo Bank"
  ]
}' |
apify call datagleaner/uk-company-directors --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,datagleaner/uk-company-directors"
        }
    }
}
```

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/c4VmOd6nHZPLAwv2I/builds/g0WIKT765rvF91KmD/openapi.json
