# UK Companies House Data Scraper (Company Records JSON) (`steadfetch/companies-house-monitor`) Actor

Extract official UK company records as clean JSON: status, type, SIC codes, incorporation date, accounts-overdue flag and registered address. For lead lists, KYB and compliance monitoring. Company fields only — no officers or PSC data. Uses the public Companies House API.

- **URL**: https://apify.com/steadfetch/companies-house-monitor.md
- **Developed by:** [Steadfetch](https://apify.com/steadfetch) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 company delivereds

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

## steadfetch/companies-house-monitor

Extract UK company records from the official [Companies House public data API](https://developer.company-information.service.gov.uk/). Look up a company by number or search the register by name, with structured JSON output. No browser, no login, no CAPTCHA.

### What it does

The Actor calls the official Companies House API and returns one dataset item per company with its register status, type, incorporation date, SIC codes, accounts-overdue flag and registered office address.

- **Company mode:** fetch one company profile by number.
- **Search mode:** search the register by name or number and page through results.
- **Incorporation filter:** keep companies incorporated on or after a given date.
- **Schema validation:** every item is validated against `.actor/dataset_schema.json` before it reaches the dataset. With `strictSchema: true` (the default) an invalid item fails the run.

The data is public under the [Open Government Licence v3.0](https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/). The Actor only maps company-level fields: the officers and PSC endpoints are deliberately **not** called because they can expose personal names and residential addresses. It never returns officer data, dates of birth or contact details.

The Actor authenticates with a free Companies House API key. **Your own key (optional but recommended):** register at [developer.company-information.service.gov.uk](https://developer.company-information.service.gov.uk/) and paste it in the `apiKey` input field. The published API allows 600 calls per 5 minutes *per key*; if every user shares one key, that budget is split between them. If you leave `apiKey` empty, the publisher's key is used as a fallback. Keys are never written to logs or the repository, and the `apiKey` field is masked in run inputs. The client retries `429`/`5xx` responses with exponential backoff.

### Example output

```json
{
    "url": "https://find-and-update.company-information.service.gov.uk/company/08209948",
    "title": "! LTD",
    "scrapedAt": "2026-10-19T18:00:00.000Z",
    "company_number": "08209948",
    "company_name": "! LTD",
    "company_status": "active",
    "company_type": "ltd",
    "sic_codes": ["99999"],
    "incorporated_on": "2012-09-11",
    "accounts_overdue": false,
    "address": {
        "address_line_1": "9 PRINCES SQUARE",
        "locality": "HARROGATE",
        "postal_code": "HG1 1ND",
        "country": "England"
    }
}
```

### Input

Company mode:

```json
{
    "mode": "company",
    "companyNumber": "03977902",
    "maxResults": 10
}
```

Search mode:

```json
{
    "mode": "search",
    "query": "tesla",
    "maxResults": 100,
    "since": "2025-01-01"
}
```

| Field | Type | Description |
| --- | --- | --- |
| `mode` | `company` or `search` | Required. |
| `companyNumber` | string | Required when `mode=company`. |
| `query` | string | Required when `mode=search`. |
| `maxResults` | integer | Default 100, maximum 5000. |
| `since` | string | Optional `YYYY-MM-DD`; search mode keeps companies incorporated on or after this date. |
| `apiKey` | string | Optional. Your own Companies House API key (recommended; see *What it does*). Leave empty to use the publisher's key. |
| `strictSchema` | boolean | Default `true`; fail the run on schema violations. |

The company number in the original STE-18 specification (`00063903`) does not exist in the register: a run with it returns a clean, non-retryable `404` (covered by the live tests). The minimal platform test therefore uses the live company `03977902` (GOOGLE UK LIMITED); choosing this live number is the only deviation from the literal specification input.

### Project structure

```
.actor/actor.json          Actor definition (payPerEvent, dataset schema, output schema)
.actor/input_schema.json   INPUT options (mode, companyNumber, query, maxResults, since, apiKey)
.actor/dataset_schema.json Item JSON Schema (fields) + table view for the Store
.actor/pay_per_event.json  PPE pricing (two synthetic platform events)
src/fetch.ts               Companies House API client: auth, pagination, retry/backoff
src/extract.ts             Pure parsing and filtering (fixture-tested, no network)
src/main.ts                Entry point: fetch, validate, push
src/validate-output.ts     Ajv validator shared by the run and the tests
test/                      Offline fixtures, Vitest suites and optional live API tests
```

### Pay-per-event pricing

The Actor uses Apify **pay-per-event** pricing with the two synthetic platform events:

| Event | Charged when | Price |
| --- | --- | --- |
| `apify-actor-start` | a run starts (synthetic, automatic) | 0.00005 USD per run (Apify-recommended default; includes 5 seconds of free compute) |
| `apify-default-dataset-item` | a company is saved to the dataset (synthetic, automatic) | 0.0025 USD per result = **2.50 USD per 1,000 results** |

There is no custom per-item event and no `Actor.charge()` call: the platform already charges `apify-default-dataset-item` per pushed item, so adding another event would bill users twice.

The price sits inside the direct-competitor band (1.5-3.2 USD per 1,000) and inside Steadfetch's 1-10 USD band. Estimated cost is under 0.10 USD per 1,000 results (a few authenticated JSON calls plus compute), leaving a margin above 96%.

### Development

```bash
npm install
npm test                # lint + typecheck + offline Vitest suites (no credit)
npm run publish:check   # Steadfetch publish gate
npm run schemas:validate
npm run smoke           # local Apify run (no platform credit)
COMPANIES_HOUSE_API_KEY=... npm test   # also runs the live API tests
```

The default test suite runs against committed fixtures and never touches the network. Live tests are skipped unless `COMPANIES_HOUSE_API_KEY` is set; they validate real company and search responses against the same output schema.

### FAQ

**Do I need a Companies House API key?**
No. The Actor uses a key configured as a Steadfetch Actor secret. You only provide a company number or a search term.

**Does it need a browser?**
No. Companies House returns structured JSON; plain HTTP is roughly 10x cheaper than a browser-based Actor.

**Does it return personal data?**
No. Only company-level register fields are returned. Officer and PSC endpoints are never called, so there are no personal names, residential addresses or dates of birth.

**When am I charged?**
Once per run start (`apify-actor-start`) and once per company saved to the dataset (`apify-default-dataset-item`). Failed requests, retries and empty searches are not charged per result.

**Is the output schema stable?**
Yes. New fields are additive and the required fields in `.actor/dataset_schema.json` do not change.

### Maintenance

This Actor is **tested daily**: automated runs check that the Companies House API is reachable and that the output still matches the published schema. Failures are reported as issues in the Steadfetch Actors repository.

# Actor input Schema

## `mode` (type: `string`):

company: fetch one company profile by number. search: search the register by name and page through results.

## `companyNumber` (type: `string`):

Companies House company number (for example 03977902). Required when mode=company.

## `query` (type: `string`):

Company name or number to search for. Required when mode=search.

## `maxResults` (type: `integer`):

Maximum number of companies to save to the dataset.

## `since` (type: `string`):

Optional ISO date (YYYY-MM-DD). In search mode, only keep companies incorporated on or after this date.

## `apiKey` (type: `string`):

Optional. Your own free Companies House API key (register at developer.company-information.service.gov.uk). Recommended: the published API allows 600 calls per 5 minutes per key, and one shared publisher key would be split across all users. Leave empty to use the publisher's key as fallback.

## `strictSchema` (type: `boolean`):

Fail the run when an item does not match the OUTPUT schema. Keep enabled: Steadfetch never publishes Actors without output-schema validation.

## Actor input object example

```json
{
  "mode": "company",
  "companyNumber": "03977902",
  "query": "tesla",
  "maxResults": 100,
  "since": "2025-01-01",
  "strictSchema": true
}
```

# Actor output Schema

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

Dataset items validated against the item schema in dataset_schema.json (fields).

# 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 = {
    "mode": "company",
    "companyNumber": "03977902"
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadfetch/companies-house-monitor").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 = {
    "mode": "company",
    "companyNumber": "03977902",
}

# Run the Actor and wait for it to finish
run = client.actor("steadfetch/companies-house-monitor").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 '{
  "mode": "company",
  "companyNumber": "03977902"
}' |
apify call steadfetch/companies-house-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,steadfetch/companies-house-monitor"
        }
    }
}
```

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/BSVzYGq92FwHYdVan/builds/vlfGcWOMzcjjrDQTq/openapi.json
