Companies House shows each company's officers on its own page, which is fine for one firm and tedious for a list. The free API exposes the same data, but you have to call the profile, officers and filing history endpoints separately, combine them and stay inside the rate limit of 600 requests per 5 minutes.
If what you need is a spreadsheet of directors for a set of companies, say every active scaffolding firm in Manchester incorporated since 2020, or the officers behind 300 suppliers in your purchase ledger, you want that stitched together already, with one row per person you can filter and sort.
This guide covers choosing companies by number or by filters, finding SIC codes, running the export, turning nested officers into a flat director list, and keeping the output privacy-safe.
Step by step
Choose how to select companies
There are three ways in, in this order of priority. companyNumbers enriches exactly the companies you list. If no numbers are given, the advanced filters (sicCodes, companyStatus, incorporatedFrom, incorporatedTo, location) run a targeted search. If there are neither, searchTerms runs a free-text name search such as 'plumbing manchester'.
Find the SIC codes for your sector
SIC codes are the Standard Industrial Classification codes companies declare on the register. 43991 is scaffolding, for example, and you can pass several codes at once. Combine them with companyStatus active and a location such as 'Manchester' to get a targeted list of trading companies with a registered office in that area.
{ "sicCodes": ["43991", "43999"], "companyStatus": "active", "incorporatedFrom": "2020-01-01", "location": "Manchester", "maxResults": 500, "includeOfficers": true, "includeFilings": false }Or enrich a list of company numbers you already have
Paste company numbers into companyNumbers to enrich exactly those firms. Keep them as text: UK company numbers often start with zeros or letters, and spreadsheets tend to strip leading zeros. Mistyped numbers are skipped and never charged, so check the run's row count against your list.
{ "companyNumbers": ["09876543", "12345678", "SC123456"], "includeOfficers": true, "includeFilings": true }Flatten officers into one row per director
Each company row has an officers list with name, role, appointedOn, resignedOn, nationality and occupation, up to 100 per company. The script below turns that into a flat CSV of current directors only (no resignation date), with the company's number, name, status and SIC codes on every line.
import csv import os from apify_client import ApifyClient client = ApifyClient(os.environ["APIFY_TOKEN"]) run = client.actor("actor-forge/uk-companies-house-enrichment").call(run_input={ "sicCodes": ["43991"], "companyStatus": "active", "location": "Manchester", "maxResults": 500, "includeOfficers": True, "includeFilings": False, }) with open("directors.csv", "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["companyNumber", "companyName", "status", "sicCodes", "officerName", "role", "appointedOn", "occupation"]) for company in client.dataset(run["defaultDatasetId"]).iterate_items(): for officer in company.get("officers") or []: if officer.get("resignedOn"): continue if "director" not in (officer.get("role") or "").lower(): continue writer.writerow([ company["companyNumber"], company["name"], company.get("status"), " ".join(company.get("sicCodes") or []), officer["name"], officer["role"], officer.get("appointedOn"), officer.get("occupation"), ])Use filings to qualify the list
With includeFilings on, each company carries its 25 most recent filings with date, category, type and description. That is enough to spot companies that have recently filed accounts or changed officers, or to drop ones whose history suggests they are winding down. Leave it off if you only need directors; the price per company is the same.
Plan for throughput on big exports
Companies House allows 600 requests per 5 minutes, and a fully enriched company uses 3 requests, so expect about 180 companies per 5 minutes on the shared key. For large or frequent exports, get a free key from developer.company-information.service.gov.uk and put it in apiKey for dedicated throughput.
Handle director data responsibly
The actor never returns officers' dates of birth or personal addresses, only statutory register fields. Directors' names and roles are still personal data, so make sure you have a lawful basis for any outreach and keep the export to what you need.
Sample input
{
"sicCodes": [
"43991"
],
"companyStatus": "active",
"incorporatedFrom": "2020-01-01",
"location": "Manchester",
"maxResults": 200,
"includeOfficers": true,
"includeFilings": true
}Sample output
Each company row arrives with officers and filings nested inside it, summarised in the table below:
| companyNumber | name | status | incorporatedOn | registeredAddress | sicCodes | officers | filings |
|---|---|---|---|---|---|---|---|
| 12345678 | EXAMPLE SCAFFOLDING LTD | active | 2019-03-14 | 1 Example Street, Unit 4, Manchester, M1 2AB, England | 43991, 43999 | 2 active, 1 resigned (names, roles, dates) | 25 most recent (date, type, description) |
| 87654321 | SAMPLE JOINERY (LEEDS) LTD | active | 2021-09-02 | 22 Demo Road, Leeds, LS1 4XY, England | 43320 | 1 active (name, role, dates) | 25 most recent (date, type, description) |
Run it from code
cURL
curl -X POST "https://api.apify.com/v2/acts/actor-forge~uk-companies-house-enrichment/run-sync-get-dataset-items" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"sicCodes": ["43991"], "companyStatus": "active", "incorporatedFrom": "2020-01-01", "location": "Manchester", "maxResults": 200, "includeOfficers": true, "includeFilings": true}'JavaScript (Node.js)
// Node.js 18+ (built-in fetch). Set APIFY_TOKEN in your environment.
const input = {
"sicCodes": [
"43991"
],
"companyStatus": "active",
"incorporatedFrom": "2020-01-01",
"location": "Manchester",
"maxResults": 200,
"includeOfficers": true,
"includeFilings": true
};
const res = await fetch(
"https://api.apify.com/v2/acts/actor-forge~uk-companies-house-enrichment/run-sync-get-dataset-items",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify(input),
}
);
const items = await res.json();
console.log(items.length, items[0]);Python
# pip install apify-client (set APIFY_TOKEN in your environment)
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run_input = {
"sicCodes": [
"43991"
],
"companyStatus": "active",
"incorporatedFrom": "2020-01-01",
"location": "Manchester",
"maxResults": 200,
"includeOfficers": True,
"includeFilings": True
}
run = client.actor("actor-forge/uk-companies-house-enrichment").call(run_input=run_input)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)The run-sync-get-dataset-items endpoint waits for the run (up to 5 minutes) and returns the dataset rows directly. For longer runs, start the run asynchronously and read the dataset when it finishes, as the Python example does. Replace APIFY_TOKEN with your own token from the Apify console.
What it costs
Exporting directors for 500 companies costs 500 x $0.005 = $2.50, with profile, officers and filings included in that price. Companies that are not found cost nothing.
| Charged for | When | Price | Per 1,000 | Worked example |
|---|---|---|---|---|
| Enriched company | One UK company with profile, officers and filing history from the official register. | $0.005 | $5 | 1,000 companies = $5.00; 100 companies = $0.50 |
| Actor Start (platform start fee) | Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). | $0.00005 | — | One run at up to 1 GB = $0.00005 (charged as one event) |
Ready to try it? Companies House Enrichment — UK Company Directors & Filings runs on Apify, pay per result.
Run on Apify → Read the full actor pageTips and pitfalls
- companyNumbers takes priority over everything else, so clear it if you want the SIC code filters to run.
- searchTerms is ignored whenever company numbers or advanced filters are given.
- Officers include resigned ones by default; filter on resignedOn to keep only current directors.
- Coverage is UK-registered companies only: England, Wales, Scotland and Northern Ireland.
- Set a run budget if you are unsure how many companies a filter will match; the actor stops cleanly at the cap.
FAQ
Can I download all directors of a company from Companies House for free?
Yes, one company at a time on the Companies House website or through its free API. This actor is for doing it in bulk in one dataset, at $0.005 per company.
Does the export include officers other than directors?
Yes. The officers list holds directors and other officers, up to 100 per company, each with a role, so you can keep directors only, as in the script, or include every role.
Why is my director missing a date of birth?
Dates of birth are deliberately never returned, along with personal addresses. Only statutory business-register fields are included.
Can I export dissolved companies too?
Yes. Set companyStatus to dissolved or liquidation, or to any to disable the status filter.
Actors used in this guide
Companies House Enrichment — UK Company Directors & Filings
Enrich UK companies from the official Companies House API: profile, SIC codes, current and resigned directors and officers, and the latest filing…
$5 per 1,000 · enriched companyRelated guides
How to Use UK Planning Applications as Sales Leads
Pull each council's weekly list of newly validated applications with UK Planning Applications, filter the proposal text for the work you do, and…
How to Get SEC Form D Startup Funding Data as a Daily Feed
Use Startup Funding Rounds to read EDGAR's daily Form D indexes and parse each filing into a row with issuer, amounts, industry and exemption.…
How to Get Local Business Leads Without Scraping Google Maps
Query the open Overture Maps places dataset by city and category with Business Places Data to get names, addresses, phones, websites and emails for…